14

我正在创建一个脚本,它需要解析 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中找到了一些相关信息。但我无法让它正常工作......

4

4 回答 4

24

我已通过电子邮件向 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
于 2012-03-16T01:48:29.347 回答
1

我认为问题的症结在于 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​​ 中编写脚本可能会更容易。

于 2011-12-02T19:46:20.957 回答
1

我只需要类部分。所以我最终创建了这个小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())
于 2011-12-05T15:04:39.887 回答
-1

简单的 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
于 2018-07-24T13:00:40.953 回答