如何解析 Cloudformation YAML 以从 YAML 模板获取所有 !ImportValue?

How to parse Cloudformation YAML to get all the !ImportValue from YAML template?

我正在从事一个解析 AWS Cloudformation Yaml 文件以从 YAML 模板中提取所有 !ImportValue 的项目。

我正在尝试使用 ruamel.yaml 来解析它(我是新手),我能够读取 YAML 文件并获取各个元素。

import ruamel.yaml

def general_constructor(loader, tag_suffix, node):
  return node.value

ruamel.yaml.SafeLoader.add_multi_constructor(u'!', general_constructor)

with open(cfFile, 'r') as service:
  stream = service.read()

yaml_data = ruamel.yaml.safe_load(stream)
print yaml_data

以上代码获取指定 YAML 文件的内容,输出如下所示。

{'Application': {'Properties': {'ApplicationName': [ScalarNode(tag=u'tag:yaml.org,2002:str', value=u'-'),
    SequenceNode(tag=u'tag:yaml.org,2002:seq', value=[ScalarNode(tag=u'tag:yaml.org,2002:str', value=u'***'), ScalarNode(tag=u'!ImportValue', value=u'jkl')])],
   *
   *
     ScalarNode(tag=u'!ImportValue', value=u'def'),
   *
   *
     ScalarNode(tag=u'!ImportValue', value=u'rst')])]},


所以 ScalarNode 中列出了一堆 !ImportValue(例如 ScalarNode(tag=u'!ImportValue', value=u'rst')),我实际上想提取它。现在这些 ImportValues 分散在模板中的各个地方。提取这些价值的最佳方式是什么?在我们的 cloudformation 中,我们有一堆 YAML 文件,其中一些导出某些资源,其他 YAML 文件导入它们。所以,我想构建一种依赖关系图(可能是 JSON 文件),它将描述 Cloud-formation 文件之间的相互依赖关系。

如果您使用 ruamel.yaml 的往返加载程序,则无需执行此操作 任何特殊的东西来加载标签,并递归地遍历 由此产生的数据结构相对容易。对应的键 需要传递,因为至少第一个 !ImportValue 在 键下的序列。

假设 input.yaml 包括:

Application:
  Properties:
    ApplicationName: ["-", ["**", !ImportValue "jkl"]]

  AnotherKey:
  - 42
  - nested: !ImportValue xyz

(这可能与您输入的内容不完全相同,但可以用于 演示目的),并使用新的 ruamel.yaml API(其中 默认为往返 loading/dumping):

import sys
from pathlib import Path
import ruamel.yaml

ta = ruamel.yaml.comments.Tag.attrib

yaml = ruamel.yaml.YAML()
data = yaml.load(Path('input.yaml'))

def process(d, key=None):
    if isinstance(d, dict):
        for k, v in d.items():
            for res in process(v, k):  # recurse and pass on new key
                yield res
    elif isinstance(d, list):
        for item in d:
            for res in process(item, key):
                yield res
    else:
       try:
           if getattr(d, ta, None).value == '!ImportValue':
               yield (key, d)
       except AttributeError:
           pass

for k, v in process(data):
   print(k, '->', v)

给出:

ApplicationName -> jkl
nested -> xyz