2011-12-02 26 views
14

Estoy creando un script que necesita analizar la salida yaml que produce el títere.Analizando puppet-api yaml con python

Cuando hace un ejemplo de petición agains https: // títere: 8140/producción/Catálogo/my.testserver.no voy a conseguir un poco hacia atrás yaml que se ve algo como:

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

y así ... El problema es cuando hago un yaml.load (yamlstream), me sale un error 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 ... 
    ^

por lo que yo sé, esto & id001 parte se apoya en yaml.

¿Hay alguna forma de evitar esto? ¿Puedo decirle al analizador yaml que los ignore? Solo necesito un par de líneas de la transmisión yaml, ¿tal vez la expresión regular es mi amiga aquí? ¿Alguien ha hecho alguna de las expresiones regulares de limpieza yaml antes?

Usted puede obtener la salida yaml con rizo 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) 

También encontré algo de información sobre este tema en la lista de correo de marionetas @http://www.mail-archive.com/[email protected]/msg24143.html. Pero no puedo hacer que funcione correctamente ...

Respuesta

23

he enviado por correo electrónico Kirill Simonov, el creador de PyYAML, para obtener ayuda para analizar Archivo Puppet YAML.

Con gusto ayudó con el siguiente código. Este código es para analizar el registro de Puppet, pero estoy seguro de que puede modificarlo para analizar otro archivo Puppet YAML.

La idea es crear el cargador correcto para el objeto Ruby, luego PyYAML puede leer los datos después de eso.

aquí va:

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

No tuve la oportunidad de probarlo todavía, pero parece muy prometedor y creo que esto es exactamente lo que necesito. Trataré de cambiar mi código actual a algo así en lugar de tomar el código yaml no analizable. ¡Gracias! – xeor

1

Creo que el quid de la cuestión es el hecho de que Puppet está utilizando yaml "etiquetas" para ruby-fu, y eso es confuso el cargador de python predeterminado. En particular, PyYAML no tiene idea de cómo construir un rubí/objeto: Puppet :: Resource :: Catalog, que tiene sentido, ya que es un objeto ruby.

Aquí hay un enlace que muestra algunos diversos usos de las etiquetas YAML: http://www.yaml.org/spec/1.2/spec.html#id2761292

que he conseguido pasado esto en un enfoque de fuerza bruta con sólo hacer algo como:

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

pero ahora estoy atascado en un problema donde el bloque * resource_table * confunde PyYAML con sus claves complejas (el uso de '?' para indicar el inicio de una clave compleja, específicamente).

Si encuentra una forma agradable de hacerlo, por favor, hágamelo saber ... pero teniendo en cuenta lo atada que está a la rubí en el títere de cadera, puede que sea más fácil hacer su guión directamente en rubí.

+0

Gracias por la información. Lo probaré el lunes. Como no hay mucha información que realmente necesite, probablemente pueda quitarme muchas cosas. Ruby no es una opción, lo siento ...: =) Haré un comentario sobre esta pregunta si descubro algo inteligente. – xeor

1

Solo necesitaba la sección de clases. Así que terminé la creación de esta pequeña función de Python para despojar a cabo ...

Espero su muy útil para alguien :)

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