Разбор кукол-апи ямл с питоном - PullRequest
14 голосов
/ 02 декабря 2011

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

Я также нашел информацию об этом в списке рассылки марионеток @ http://www.mail-archive.com/puppet-users@googlegroups.com/msg24143.html. Но я не могу заставить его работать правильно ...

Ответы [ 4 ]

23 голосов
/ 16 марта 2012

Я написал Кириллу Симонову, создателю PyYAML, чтобы получить помощь в разборе файла Puppet YAML.

Он с радостью помог со следующим кодом. Этот код предназначен для анализа журнала Puppet, но я уверен, что вы можете изменить его для анализа другого файла YAML Puppet.

Идея состоит в том, чтобы создать правильный загрузчик для объекта 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
1 голос
/ 05 декабря 2011

Мне нужен был только раздел классов. Так что я закончил тем, что создал эту маленькую функцию Python, чтобы удалить ее ...

Надеюсь, кому-нибудь это пригодится :) 1003 *

#!/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())
1 голос
/ 02 декабря 2011

Я считаю, что суть дела в том, что puppet использует yaml-теги для ruby-fu, и это сбивает с толку загрузчик Python по умолчанию.В частности, PyYAML не имеет представления о том, как создать объект ruby ​​/: 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.

0 голосов
/ 24 июля 2018

Простой синтаксический анализатор 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
...