2011-12-02 15 views
14

Tworzę skrypt, który musi przeanalizować wyjściowy wynik yaml, który generuje marionetka.Parsowanie marionetek-api yaml z pytonem

Kiedy robi Przykładowe żądanie Agains https: // lalek: 8140/produkcja/Katalog/my.testserver.no będę trochę yaml tyłu, który wygląda mniej więcej tak:

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

i tak na ... problemem jest to, kiedy zrobić yaml.load (yamlstream), będę się błąd jak:

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

o ile wiem, to & id001 część jest obsługiwana w YAML.

Czy jest jakiś sposób obejścia tego? Czy mogę powiedzieć parserowi yaml, aby je zignorował? Potrzebuję tylko kilku linii z potoku yaml, może regex jest moim przyjacielem tutaj? Ktoś zrobił wcześniej wyszczuplające sprzączki yaml?

można uzyskać wyjście yaml z curl jak:

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) 

Znalazłem również kilka informacji na ten temat w mailingową lalkowego @http://www.mail-archive.com/[email protected]/msg24143.html. Ale nie mogę go poprawnie uruchomić ...

Odpowiedz

23

Wysłałem Kirill Simonov, twórca PyYAML, aby uzyskać pomoc do analizowania Plik YAML marionetki.

On chętnie pomógł z następującego kodu. Ten kod służy do analizowania dziennika Puppet, ale jestem pewien, że możesz go zmodyfikować, aby przeanalizować inny plik YAML Puppet.

Chodzi o to, aby utworzyć poprawny moduł ładujący dla obiektu Ruby, a następnie PyYAML może odczytać dane po tym.

Tu idzie:

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

Nie miałem jeszcze okazji tego wypróbować, ale wygląda to bardzo obiecująco i myślę, że właśnie tego potrzebuję. Spróbuję zmienić mój obecny kod na coś takiego, zamiast brać niepoprawny kod yaml. Dzięki! – xeor

1

Wierzę, że sedno sprawy polega na tym, że marionetka używa tagów "yaml" dla ruby-fu, a to mylące domyślny program ładujący python. W szczególności PyYAML nie ma pojęcia, jak skonstruować ruby ​​/ obiekt: Puppet :: Resource :: Catalog, co ma sens, ponieważ jest to obiekt ruby.

Oto link pokazano kilka różnych zastosowań tagów yaml: http://www.yaml.org/spec/1.2/spec.html#id2761292

stałam obok tego w podejściu brute-force po prostu robi coś takiego:

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

ale teraz jestem utknął na problem, w którym blok * resource_table * myli PyYAML z jego złożonymi kluczami (użycie "?" w szczególności wskazuje początek złożonego klucza).

Jeśli znajdziesz w tym dobry sposób, proszę dać mi znać ... ale biorąc pod uwagę, jak przywiązany do hipokalcem jest rubin, może być łatwiejsze do wykonania skryptu bezpośrednio w rubinie.

+0

Dzięki za info. Wypróbuję to w poniedziałek. Ponieważ nie ma zbyt wielu informacji, których potrzebuję, prawdopodobnie będę w stanie dużo usunąć ... Ruby nie jest opcją, przepraszam ..: =) Powiem na to pytanie, jeśli dowiem się czegoś sprytnego. – xeor

1

Potrzebowałem tylko sekcji zajęć. Więc skończyło się tworząc tę ​​małą funkcję Pythona strip go ...

nadziei jej przydatne dla kogoś :)

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