使用 python 解析 puppet-api yaml

发布于 2024-12-19 00:01:13 字数 1456 浏览 0 评论 0原文

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

当我再次发出请求时 https://puppet:8140/product/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/[电子邮件受保护]/msg24143.html。但我无法让它正常工作......

I am creating a script which need to parse the yaml output that the puppet outputs.

When I does a request agains example https://puppet:8140/production/catalog/my.testserver.no I will get some yaml back that looks something like:

--- &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: 

and so on... The problem is when I do an yaml.load(yamlstream), I will get an error like:

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 ... 
       ^

As far as I know, this &id001 part is supported in yaml.

Is there any way around this? Can I tell the yaml parser to ignore them?
I only need a couple of lines from the yaml stream, maybe regex is my friend here?
Anyone done any yaml cleanup regexes before?

You can get the yaml output with curl like:

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)

I also found some info about this in the puppet mailinglist @ http://www.mail-archive.com/[email protected]/msg24143.html. But I cant get it to work correctly...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

酷遇一生 2024-12-26 00:01:13

我已向 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

I have emailed Kirill Simonov, the creator of PyYAML, to get help to parse Puppet YAML file.

He gladly helped with the following code. This code is for parsing Puppet log, but I'm sure you can modify it to parse other Puppet YAML file.

The idea is to create the correct loader for the Ruby object, then PyYAML can read the data after that.

Here goes:

#!/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
长不大的小祸害 2024-12-26 00:01:13

我认为问题的关键在于 puppet 使用 yaml“标签”来表示 ruby​​-fu,这混淆了默认的 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​​ 中编写脚本可能会更容易。

I believe the crux of the matter is the fact that puppet is using yaml "tags" for ruby-fu, and that's confusing the default python loader. In particular, PyYAML has no idea how to construct a ruby/object:Puppet::Resource::Catalog, which makes sense, since that's a ruby object.

Here's a link showing some various uses of yaml tags: http://www.yaml.org/spec/1.2/spec.html#id2761292

I've gotten past this in a brute-force approach by simply doing something like:

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

but now I'm stuck on an issue where the *resource_table* block is confusing PyYAML with its complex keys (the use of '? ' to indicate the start of a complex key, specifically).

If you find a nice way around that, please let me know... but given how tied at the hip puppet is to ruby, it may just be easier to do you script directly in ruby.

分開簡單 2024-12-26 00:01:13

我只需要课程部分。所以我最终创建了这个小 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())

I only needed the classes section. So I ended up creating this little python function to strip it out...

Hope its usefull for someone :)

#!/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())
养猫人 2024-12-26 00:01:13

简单的 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

Simple YAML parser:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文