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

时间:2019-04-02 10:55:07

标签: python yaml amazon-cloudformation pyyaml ruamel.yaml

我正在一个项目中解析一个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文件),以描述云形成文件之间的相互依赖关系。

1 个答案:

答案 0 :(得分:1)

如果您使用ruamel.yaml的往返装载程序,则不必做 加载标签的所有特殊操作,然后递归地遍历 由此产生的数据结构相对容易。对应的钥匙 需要传递,因为至少第一个!ImportValue在 键下的序列。

假设一个input.yaml由以下组成:

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

  AnotherKey:
  - 42
  - nested: !ImportValue xyz

(可能不完全是您输入的内容,但可以 演示目的),并使用新的ruamel.yaml API( 默认为往返加载/转储):

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