Skip to content

Commit 70c71eb

Browse files
authored
Update E3615 to validate all CloudWatch Alarm periods (#3556)
1 parent 4bac100 commit 70c71eb

File tree

5 files changed

+160
-109
lines changed

5 files changed

+160
-109
lines changed

src/cfnlint/data/schemas/extensions/aws_cloudwatch_alarm/aws_namespace_period.json

-29
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"additionalProperties": true,
3+
"description": "The period, in seconds, over which the statistic is applied. This is required for an alarm based on a metric. Valid values are 10, 30, 60, and any multiple of 60.",
4+
"if": {
5+
"properties": {
6+
"Period": {
7+
"type": [
8+
"integer",
9+
"string"
10+
]
11+
}
12+
},
13+
"required": [
14+
"Period"
15+
],
16+
"type": "object"
17+
},
18+
"then": {
19+
"properties": {
20+
"Period": {
21+
"else": {
22+
"multipleOf": 60
23+
},
24+
"if": {
25+
"maximum": 60
26+
},
27+
"then": {
28+
"enum": [
29+
10,
30+
30,
31+
60
32+
]
33+
}
34+
}
35+
}
36+
}
37+
}

src/cfnlint/rules/resources/cloudwatch/AlarmAwsNamespacePeriod.py renamed to src/cfnlint/rules/resources/cloudwatch/AlarmPeriod.py

+7-9
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,24 @@
88
from typing import Any
99

1010
import cfnlint.data.schemas.extensions.aws_cloudwatch_alarm
11-
from cfnlint.jsonschema import ValidationError
11+
from cfnlint.jsonschema.exceptions import ValidationError
1212
from cfnlint.rules.jsonschema.CfnLintJsonSchema import CfnLintJsonSchema, SchemaDetails
1313

1414

15-
class AlarmAwsNamespacePeriod(CfnLintJsonSchema):
15+
class AlarmPeriod(CfnLintJsonSchema):
1616
id = "E3615"
17-
shortdesc = "Validate CloudWatch Alarm using AWS metrics has a correct period"
18-
description = (
19-
"Period < 60 not supported for namespaces with the following prefix: AWS/"
20-
)
21-
tags = ["resources"]
17+
shortdesc = "Validate the period is a valid value"
18+
description = "Valid values are 10, 30, 60, and any multiple of 60."
19+
tags = ["resources", "cloudwatch"]
2220

2321
def __init__(self) -> None:
2422
super().__init__(
2523
keywords=["Resources/AWS::CloudWatch::Alarm/Properties"],
2624
schema_details=SchemaDetails(
2725
module=cfnlint.data.schemas.extensions.aws_cloudwatch_alarm,
28-
filename="aws_namespace_period.json",
26+
filename="period.json",
2927
),
3028
)
3129

3230
def message(self, instance: Any, err: ValidationError) -> str:
33-
return err.message
31+
return f"{err.instance!r} is not one of [10, 30, 60] or a multiple of 60"

test/unit/rules/resources/cloudwatch/test_alarm_aws_namespace_period.py

-71
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
"""
2+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
SPDX-License-Identifier: MIT-0
4+
"""
5+
6+
from collections import deque
7+
8+
import pytest
9+
10+
from cfnlint.jsonschema import ValidationError
11+
from cfnlint.rules.resources.cloudwatch.AlarmPeriod import AlarmPeriod
12+
13+
14+
@pytest.fixture(scope="module")
15+
def rule():
16+
rule = AlarmPeriod()
17+
yield rule
18+
19+
20+
@pytest.mark.parametrize(
21+
"instance,expected",
22+
[
23+
(
24+
{
25+
"Period": 60,
26+
},
27+
[],
28+
),
29+
(
30+
[], # wrong type
31+
[],
32+
),
33+
(
34+
{
35+
"Period": {"Ref": "Period"}, # ignore when object
36+
},
37+
[],
38+
),
39+
(
40+
{
41+
"Period": 30,
42+
},
43+
[],
44+
),
45+
(
46+
{
47+
"Period": 600,
48+
},
49+
[],
50+
),
51+
(
52+
{
53+
"Period": 45,
54+
},
55+
[
56+
ValidationError(
57+
"45 is not one of [10, 30, 60] or a multiple of 60",
58+
rule=AlarmPeriod(),
59+
path=deque(["Period"]),
60+
validator="enum",
61+
schema_path=deque(["then", "properties", "Period", "then", "enum"]),
62+
)
63+
],
64+
),
65+
(
66+
{
67+
"Period": "45",
68+
},
69+
[
70+
ValidationError(
71+
"'45' is not one of [10, 30, 60] or a multiple of 60",
72+
rule=AlarmPeriod(),
73+
path=deque(["Period"]),
74+
validator="enum",
75+
schema_path=deque(["then", "properties", "Period", "then", "enum"]),
76+
)
77+
],
78+
),
79+
(
80+
{
81+
"Period": 121,
82+
},
83+
[
84+
ValidationError(
85+
"121 is not one of [10, 30, 60] or a multiple of 60",
86+
rule=AlarmPeriod(),
87+
path=deque(["Period"]),
88+
validator="multipleOf",
89+
schema_path=deque(
90+
["then", "properties", "Period", "else", "multipleOf"]
91+
),
92+
)
93+
],
94+
),
95+
(
96+
{
97+
"Period": "121",
98+
},
99+
[
100+
ValidationError(
101+
"'121' is not one of [10, 30, 60] or a multiple of 60",
102+
rule=AlarmPeriod(),
103+
path=deque(["Period"]),
104+
validator="multipleOf",
105+
schema_path=deque(
106+
["then", "properties", "Period", "else", "multipleOf"]
107+
),
108+
)
109+
],
110+
),
111+
],
112+
)
113+
def test_validate(instance, expected, rule, validator):
114+
errs = list(rule.validate(validator, "", instance, {}))
115+
116+
assert errs == expected, f"Expected {expected} got {errs}"

0 commit comments

Comments
 (0)