+VERSION = "1.4.0"
+
+"""
+test nesting depth
+0 -> 1 -> 2 -> too deep.
+"""
+MAX_DEPTH = 3
+
+
+def check_for_invalid_nesting( # pylint: disable=too-many-branches
+ yml, yaml_file, dirpath
+):
+ """
+ return a list of all nested files
+ """
+ if not hasattr(yml, "items"):
+ return []
+ invalid_nesting = []
+ p = re.compile("^[A-z]*::[A-z]*::[A-z]*$")
+
+ for v in yml.values():
+ if isinstance(v, dict) and "type" in v:
+ t = v["type"]
+ if t.endswith(".yml") or t.endswith(".yaml"):
+ filepath = path.join(dirpath, t)
+ elif t == "OS::Heat::ResourceGroup":
+ rd = v["properties"]["resource_def"]
+ if not isinstance(rd, dict) or "type" not in rd:
+ invalid_nesting.append(yaml_file)
+ continue
+ elif not p.match(rd["type"]):
+ filepath = path.join(dirpath, rd["type"])
+ else:
+ continue
+ else:
+ continue
+ try:
+ with open(filepath) as fh:
+ yml = yaml.load(fh)
+ except yaml.YAMLError as e:
+ invalid_nesting.append(filepath)
+ print(e) # pylint: disable=superfluous-parens
+ invalid_nesting.extend(check_for_invalid_nesting(yml, filepath, dirpath))
+ if isinstance(v, dict):
+ invalid_nesting.extend(check_for_invalid_nesting(v, yaml_file, dirpath))
+ elif isinstance(v, list):
+ for d in v:
+ invalid_nesting.extend(check_for_invalid_nesting(d, yaml_file, dirpath))
+ return invalid_nesting
+
+
+def get_dict_of_nested_files(yml, dirpath):
+ """Return dict.
+ key: resource id in yml which references a nested file.
+ value: the nested file name.
+ Nested files are either referenced through "type", or
+ for OS::Heat::ResourceGroup, through "resource_def type".
+ """
+ nested_files = get_type_nested_files(yml, dirpath)
+ nested_files.update(get_resourcegroup_nested_files(yml, dirpath))
+ return nested_files