Domanda

Sto creando uno script che deve analizzare l'output yaml emesso dal pupazzo.

Quando eseguo una richiesta contro l'esempio https://puppet:8140/production/catalog/my.testserver.no Otterrò indietro uno yaml che assomiglia a qualcosa del tipo:

--- &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 così via...Il problema è che quando eseguo un yaml.load(yamlstream), otterrò un errore come:

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

Per quanto ne so, questa parte &id001 è supportata in yaml.

C'è un modo per aggirare questo?Posso dire al parser yaml di ignorarli?Ho solo bisogno di un paio di righe dallo stream yaml, forse regex è mio amico qui?Qualcuno ha già eseguito regex di pulizia yaml?

Puoi ottenere l'output yaml con curl come:

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)

Ho anche trovato alcune informazioni a riguardo nella mailinglist dei pupazzi @ http://www.mail-archive.com/puppet-users@googlegroups.com/msg24143.html.Ma non riesco a farlo funzionare correttamente...

È stato utile?

Soluzione

Ho inviato un'e-mail a Kirill Simonov, il creatore di PyYAML, per ottenere aiuto per analizzare il file YAML di Puppet.

Ha aiutato volentieri con il seguente codice.Questo codice serve per analizzare il registro Puppet, ma sono sicuro che puoi modificarlo per analizzare altri file YAML Puppet.

L'idea è creare il caricatore corretto per l'oggetto Ruby, quindi PyYAML può leggere i dati successivamente.

Ecco qui:

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

Altri suggerimenti

Credo che il nocciolo della questione sia il fatto che pupazzo utilizza "tag" yaml per ruby-fu, e questo crea confusione nel caricatore Python predefinito.In particolare, PyYAML non ha idea di come costruire un ruby/object:Puppet::Resource::Catalog, il che ha senso, dato che è un oggetto ruby.

Ecco un collegamento che mostra alcuni vari usi dei tag yaml: http://www.yaml.org/spec/1.2/spec.html#id2761292

Ho superato questo problema con un approccio di forza bruta semplicemente facendo qualcosa del tipo:

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

ma ora sono bloccato su un problema in cui il blocco *resource_table* confonde PyYAML con le sue chiavi complesse (l'uso di '?' per indicare l'inizio di una chiave complessa, in particolare).

Se trovi un bel modo per aggirare il problema, fammi sapere...ma dato quanto il pupazzo è legato a Ruby, potrebbe essere più semplice realizzare la sceneggiatura direttamente in Ruby.

Avevo solo bisogno della sezione delle lezioni. Così ho finito per creare questa piccola funzione Python per eliminarla ...

Spero sia utile per qualcuno :)

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

Semplice parser 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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top