Pergunta

Estou criando um script que precisa analisar a saída do yaml gerada pelo fantoche.

Quando eu fizer uma solicitação contra o exemplo https:// puppet: 8140 / production / catalog / my.testserver.no , receberei de volta algum yaml que se parece com:

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

e assim por diante ... O problema é que quando faço um yaml.load (yamlstream), obtenho um erro como:

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

Até onde eu sei, esta parte & id001 é compatível com yaml.

Existe alguma maneira de contornar isso? Posso dizer ao analisador yaml para ignorá-los? Preciso apenas de algumas linhas do stream yaml, talvez regex seja meu amigo aqui? Alguém já fez alguma regex de limpeza yaml antes?

Você pode obter a saída do yaml com curl como:

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)

Também encontrei algumas informações sobre isso na lista de e-mails de fantoches @ http:// www .mail-archive.com / puppet-users @ googlegroups.com / msg24143.html . Mas não consigo fazer funcionar corretamente ...

Foi útil?

Solução

Mandei um e-mail para Kirill Simonov, o criador do PyYAML, para obter ajuda para analisar o arquivo YAML do Puppet.

Ele ajudou de bom grado com o código a seguir.Este código é para analisar o registro do Puppet, mas tenho certeza de que você pode modificá-lo para analisar outro arquivo YAML do Puppet.

A ideia é criar o carregador correto para o objeto Ruby, então PyYAML pode ler os dados depois disso.

Aqui vai:

#!/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

Outras dicas

Eu acredito que o ponto crucial da questão é o fato de que o puppet está usando "tags" yaml para ruby-fu, e isso está confundindo o carregador python padrão.Em particular, PyYAML não tem ideia de como construir um objeto / ruby: Puppet :: Resource :: Catalog, o que faz sentido, já que é um objeto ruby.

Aqui está um link que mostra alguns usos de tags yaml: http:// www.yaml.org / spec / 1.2 / spec.html # id2761292

Superei isso com uma abordagem de força bruta simplesmente fazendo algo como:

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

mas agora estou preso em um problema em que o bloco * resource_table * está confundindo PyYAML com suas chaves complexas (o uso de '?' para indicar o início de uma chave complexa, especificamente).

Se você encontrar uma maneira legal de contornar isso, por favor, me avise ... mas dado o quão amarrado o boneco de quadril está ao rubi, pode ser mais fácil fazer seu script diretamente em rubi.

Eu só precisava da seção de aulas.Então, acabei criando esta pequena função Python para removê-la ...

Espero que seja útil para alguém :)

#!/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())

Analisador YAML simples:

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
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top