Синтаксический анализ puppet-api yaml с помощью python

StackOverflow https://stackoverflow.com/questions/8357650

  •  27-10-2019
  •  | 
  •  

Вопрос

Я создаю скрипт, которому нужно проанализировать выходные данные 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 ... 
       ^

Насколько я знаю, эта часть &id001 поддерживается в yaml.

Есть ли какой-нибудь способ обойти это?Могу ли я сказать анализатору yaml игнорировать их?Мне нужна всего пара строк из потока yaml, может быть, регулярное выражение - мой друг здесь?Кто-нибудь раньше выполнял какие-либо регулярные выражения для очистки yaml?

Вы можете получить вывод yaml с помощью curl, например:

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.Но я не могу заставить его работать правильно...

Это было полезно?

Решение

Я отправил электронное письмо Кириллу Симонову, создателю PyYAML, чтобы получить помощь по разбору файла 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

Другие советы

Я полагаю, что суть вопроса заключается в том факте, что 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 с толку своими сложными ключами (использование '?' в частности, для обозначения начала сложной клавиши).

Если вы найдете хороший способ обойти это, пожалуйста, дайте мне знать...но учитывая, насколько сильно the hip puppet привязан к ruby, возможно, вам будет проще создать скрипт непосредственно на ruby.

Мне нужен только раздел классов. Итак, я закончил тем, что создал эту маленькую функцию 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())

Простой ямл анализатор:

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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top