Skip to content

Commit 5f2430a

Browse files
committed
Add E3062 to validate DBInstanceClass against Engine
1 parent 66b209b commit 5f2430a

5 files changed

Lines changed: 134936 additions & 33 deletions

File tree

scripts/update_schemas_from_aws_api.py

Lines changed: 114 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,36 @@
1414

1515
LOGGER = logging.getLogger("cfnlint")
1616

17-
1817
session = boto3.session.Session()
1918
config = Config(retries={"max_attempts": 10})
2019
rds_client = session.client("rds", region_name="us-east-1", config=config)
2120
elasticache_client = session.client(
2221
"elasticache", region_name="us-east-1", config=config
2322
)
2423

24+
_ENGINE_SUPPORTED = [
25+
"aurora-mysql",
26+
"aurora-postgresql",
27+
"custom-oracle-ee",
28+
"custom-oracle-ee-cdb",
29+
"custom-sqlserver-ee",
30+
"custom-sqlserver-se",
31+
"custom-sqlserver-web",
32+
"db2-ae",
33+
"db2-se",
34+
"mariadb",
35+
"mysql",
36+
"oracle-ee",
37+
"oracle-ee-cdb",
38+
"oracle-se2",
39+
"oracle-se2-cdb",
40+
"postgres",
41+
"sqlserver-ee",
42+
"sqlserver-se",
43+
"sqlserver-ex",
44+
"sqlserver-web",
45+
]
46+
2547

2648
def configure_logging():
2749
"""Setup Logging"""
@@ -52,7 +74,7 @@ def write_output(resource, filename, obj):
5274
def write_db_cluster(results):
5375
schema = {"allOf": []}
5476

55-
engines = ["aurora-mysql", "aurora-postgresql", "mysql", "postgres"]
77+
engines = sorted(["aurora-mysql", "aurora-postgresql", "mysql", "postgres"])
5678

5779
schema["allOf"].append(
5880
{
@@ -78,7 +100,7 @@ def write_db_cluster(results):
78100
if not results.get(engine):
79101
continue
80102

81-
engine_versions = sorted(results.get(engine))
103+
engine_versions = sorted(results.get(engine).keys())
82104
if engine == "aurora-mysql":
83105
for engine_version in engine_versions.copy():
84106
sub_engine_version = ".".join(engine_version.split(".")[0:2])
@@ -113,29 +135,6 @@ def write_db_cluster(results):
113135
def write_db_instance(results):
114136
schema = {"allOf": []}
115137

116-
engines = [
117-
"aurora-mysql",
118-
"aurora-postgresql",
119-
"custom-oracle-ee",
120-
"custom-oracle-ee-cdb",
121-
"custom-sqlserver-ee",
122-
"custom-sqlserver-se",
123-
"custom-sqlserver-web",
124-
"db2-ae",
125-
"db2-se",
126-
"mariadb",
127-
"mysql",
128-
"oracle-ee",
129-
"oracle-ee-cdb",
130-
"oracle-se2",
131-
"oracle-se2-cdb",
132-
"postgres",
133-
"sqlserver-ee",
134-
"sqlserver-se",
135-
"sqlserver-ex",
136-
"sqlserver-web",
137-
]
138-
139138
schema["allOf"].append(
140139
{
141140
"if": {
@@ -149,18 +148,18 @@ def write_db_instance(results):
149148
"then": {
150149
"properties": {
151150
"Engine": {
152-
"enum": sorted(engines),
151+
"enum": sorted(_ENGINE_SUPPORTED),
153152
}
154153
}
155154
},
156155
}
157156
)
158157

159-
for engine in engines:
158+
for engine, engine_details in sorted(results.items()):
160159
if not results.get(engine):
161160
continue
162161

163-
engine_versions = sorted(results.get(engine))
162+
engine_versions = sorted(list(engine_details.keys()))
164163
if engine == "postgres":
165164
for engine_version in engine_versions.copy():
166165
major_engine_version = ".".join(engine_version.split(".")[0:1])
@@ -195,6 +194,58 @@ def write_db_instance(results):
195194
write_output("aws_rds_dbinstance", "engine_version", schema)
196195

197196

197+
def write_db_instance_version_dbinstanceclass(results):
198+
schema = {"allOf": []}
199+
200+
schema = {"allOf": []}
201+
202+
def _create_schema(engine, engine_version, db_instance_classes):
203+
v_parts = engine_version.split(".")
204+
engine_pattern = (
205+
f"^({v_parts[0]}\.{v_parts[1]}\..+|{v_parts[0]}\.{v_parts[1]})$"
206+
)
207+
return {
208+
"if": {
209+
"properties": {
210+
"Engine": {
211+
"type": "string",
212+
"const": engine,
213+
},
214+
"EngineVersion": {
215+
"type": "string",
216+
"pattern": engine_pattern,
217+
},
218+
"DBInstanceClass": {
219+
"type": "string",
220+
},
221+
},
222+
"required": ["Engine", "EngineVersion", "DBInstanceClass"],
223+
},
224+
"then": {
225+
"properties": {
226+
"DBInstanceClass": {
227+
"enum": sorted(db_instance_classes),
228+
}
229+
}
230+
},
231+
}
232+
233+
for engine, engine_details in sorted(results.items()):
234+
for engine_version, engine_version_details in engine_details.items():
235+
db_instance_classes = engine_version_details.get("DBInstanceClass")
236+
if not db_instance_classes:
237+
continue
238+
if not results.get(engine):
239+
continue
240+
241+
db_instance_classes = sorted(db_instance_classes)
242+
schema["allOf"].append(
243+
_create_schema(engine, engine_version, db_instance_classes)
244+
)
245+
246+
write_output("aws_rds_dbinstance", "db_instance_class", schema)
247+
248+
198249
def write_elasticache_engines(results):
199250
schema = {"allOf": []}
200251

@@ -256,14 +307,44 @@ def rds_api():
256307
for page in rds_client.get_paginator("describe_db_engine_versions").paginate():
257308
for version in page.get("DBEngineVersions"):
258309
engine = version.get("Engine")
310+
if engine not in _ENGINE_SUPPORTED:
311+
continue
259312
engine_version = version.get("EngineVersion")
260313
if engine not in results:
261-
results[engine] = []
262-
results[engine].append(engine_version)
314+
results[engine] = {}
315+
results[engine][engine_version] = {}
263316

264317
write_db_cluster(results)
265318
write_db_instance(results)
266319

320+
results_db_instance_class = dict.fromkeys(results.keys(), dict())
321+
for engine, versions in results.items():
322+
for engine_version in versions.keys():
323+
LOGGER.info(
324+
f"Starting RDS DB options collection for {engine!r}:{engine_version!r}"
325+
)
326+
minor_engine_verison = ".".join(engine_version.split(".")[:2])
327+
if minor_engine_verison in results_db_instance_class[engine]:
328+
results_db_instance_class[engine][minor_engine_verison][
329+
"EngineVersions"
330+
].add(engine_version)
331+
else:
332+
results_db_instance_class[engine][minor_engine_verison] = {
333+
"EngineVersions": set([engine_version]),
334+
"DBInstanceClass": set(),
335+
}
336+
337+
for page in rds_client.get_paginator(
338+
"describe_orderable_db_instance_options"
339+
).paginate(Engine=engine, EngineVersion=engine_version):
340+
for options in page.get("OrderableDBInstanceOptions"):
341+
db_instance_class = options.get("DBInstanceClass")
342+
results_db_instance_class[engine][minor_engine_verison][
343+
"DBInstanceClass"
344+
].add(db_instance_class)
345+
346+
write_db_instance_version_dbinstanceclass(results_db_instance_class)
347+
267348

268349
def elasticache_api():
269350
results = {}
@@ -283,7 +364,9 @@ def elasticache_api():
283364
def main():
284365
"""main function"""
285366
configure_logging()
367+
LOGGER.info("Starting RDS data collection")
286368
rds_api()
369+
LOGGER.info("Starting Elasticache data collection")
287370
elasticache_api()
288371

289372

0 commit comments

Comments
 (0)