【问题标题】:Parsing puppet-api yaml with python用 python 解析 puppet-api yaml
【发布时间】:2012-01-11 13:27:03
【问题描述】:

我正在创建一个脚本,它需要解析 puppet 输出的 yaml 输出。

当我再次请求示例时 https://puppet:8140/production/catalog/my.testserver.no 我会得到一些看起来像这样的 yaml:

--- &id001 !ruby/object:Puppet::Resource::Catalog
  aliases: {}
  applying: false
  classes: 
    - s_baseconfig
    ...
  edges: 
    - &id111 !ruby/object:Puppet::Relationship
      source: &id047 !ruby/object:Puppet::Resource
        catalog: *id001
        exported: 

等等...问题是当我执行 yaml.load(yamlstream) 时,我会收到如下错误:

yaml.constructor.ConstructorError: could not determine a constructor for the tag '!ruby/object:Puppet::Resource::Catalog'
 in "<string>", line 1, column 5:
   --- &id001 !ruby/object:Puppet::Reso ... 
       ^

据我所知,yaml 支持这个 &id001 部分。

有没有办法解决这个问题?我可以告诉 yaml 解析器忽略它们吗? 我只需要 yaml 流中的几行,也许正则表达式是我的朋友? 之前有人做过任何 yaml 清理正则表达式吗?

您可以使用 curl 获取 yaml 输出,例如:

curl --cert /var/lib/puppet/ssl/certs/$(hostname).pem --key /var/lib/puppet/ssl/private_keys/$(hostname).pem --cacert /var/lib/puppet/ssl/certs/ca.pem -H 'Accept: yaml' https://puppet:8140/production/catalog/$(hostname)

我还在 puppet 邮件列表@http://www.mail-archive.com/puppet-users@googlegroups.com/msg24143.html 中找到了一些相关信息。但我无法让它正常工作......

【问题讨论】:

    标签: python yaml puppet


    【解决方案1】:

    我已通过电子邮件向 PyYAML 的创建者 Kirill Simonov 发送电子邮件,以获取解析 Puppet YAML 文件的帮助。

    他很乐意帮助编写以下代码。此代码用于解析 Puppet 日志,但我相信您可以修改它以解析其他 Puppet YAML 文件。

    这个想法是为 Ruby 对象创建正确的加载器,然后 PyYAML 可以读取之后的数据。

    这里是:

    #!/usr/bin/env python
    
    import yaml
    
    def construct_ruby_object(loader, suffix, node):
        return loader.construct_yaml_map(node)
    
    def construct_ruby_sym(loader, node):
        return loader.construct_yaml_str(node)
    
    yaml.add_multi_constructor(u"!ruby/object:", construct_ruby_object)
    yaml.add_constructor(u"!ruby/sym", construct_ruby_sym)
    
    
    stream = file('201203130939.yaml','r')
    mydata = yaml.load(stream)
    print mydata
    

    【讨论】:

    • 我还没有机会尝试它,但它看起来很有希望,我认为这正是我所需要的。我将尝试将我当前的代码更改为这样的代码,而不是取出无法解析的 yaml 代码。谢谢!
    【解决方案2】:

    我认为问题的症结在于 puppet 为 ruby​​-fu 使用 yaml“标签”,这让默认的 python 加载器感到困惑。特别是,PyYAML 不知道如何构造一个 ruby​​/object:Puppet::Resource::Catalog,这是有道理的,因为那是一个 ruby​​ 对象。

    这是一个显示 yaml 标签的各种用途的链接:http://www.yaml.org/spec/1.2/spec.html#id2761292

    我已经通过简单地执行以下操作以蛮力方法克服了这个问题:

    cat the_yaml | sed 's#\!ruby/object.*$##gm' > cleaner.yaml
    

    但现在我遇到了一个问题,即 *resource_table* 块将 PyYAML 与其复杂键混淆(特别是使用 '?' 表示复杂键的开始)。

    如果您找到解决此问题的好方法,请告诉我...但考虑到臀部木偶与 ruby​​ 的关系,直接在 ruby​​ 中编写脚本可能更容易。

    【讨论】:

    • 感谢您的信息。我会在星期一试一试。由于我实际需要的信息并不多,因此我可能可以删除很多内容。Ruby 不是一个选项,抱歉。:=) 如果我发现一些聪明的东西,我会评论这个问题。
    【解决方案3】:

    我只需要类部分。所以我最终创建了这个小 Python 函数来剥离它......

    希望它对某人有用:)

    #!/usr/bin/env python
    
    import re
    
    def getSingleYamlClass(className, yamlList):
        printGroup = False
        groupIndent = 0
        firstInGroup = False
        output = ''
    
        for line in yamlList:
            # Count how many spaces in the beginning of our line
            spaceCount = len(re.findall(r'^[ ]*', line)[0])
            cleanLine = line.strip()
    
            if cleanLine == className:
                printGroup = True
                groupIndent = spaceCount
                firstInGroup = True
    
            if printGroup and (spaceCount > groupIndent) or firstInGroup:
                # Strip away the X amount of spaces for this group, so we get valid yaml
                output += re.sub(r'^[ ]{%s}' % groupIndent, '', line) + '\n'
                firstInGroup = False # Reset this
            else:
                # End of our group, reset
                groupIndent = 0
                printGroup = False
    
        return output
    
    getSingleYamlClass('classes:', open('puppet.yaml').readlines())
    

    【讨论】:

      【解决方案4】:

      简单的 YAML 解析器:

      with open("file","r") as file:
          for line in file:
              re= yaml.load('\n'.join(line.split('?')[1:-1]).replace('?','\n').replace('""','\'').replace('"','\''))
              # print '\n'.join(line.split('?')[1:-1])
              # print '\n'.join(line.split('?')[1:-1]).replace('?','\n').replace('""','\'').replace('"','\'')
              print line
              print re
      

      【讨论】:

        猜你喜欢
        • 2019-06-27
        • 1970-01-01
        • 2013-01-25
        • 2015-12-06
        • 2018-09-02
        • 2018-02-16
        • 1970-01-01
        • 2018-10-04
        • 2020-10-14
        相关资源
        最近更新 更多