Разбор файлов conf icinga в python

Я пытаюсь написать оболочку для экземпляра icinga2. Объекты внутри файлов конфигурации выглядят так;

object object_type "object_name" {
  some_property = "some_value"
}

пример;

object Host "server1" {
  import "generic-host"
  address = "192.168.0.1"
  vars.os = "Linux"
}

object Host "server2" {
  import "generic-host"
  address = "192.168.0.2"
  vars.os = "Linux"
}

Я хочу сделать что-то вроде:

icinga = icinga("/etc/icinga2/conf.d/hosts.conf")

print icinga.hosts_list()

icinga.hosts_add("server3","192.168.0.3")
icinga.hosts_remove("server1")

Поэтому я попытался использовать Pynag, что-то вроде;

nc = Config('/etc/icinga2/conf.d/hosts.conf')
nc.parse()
print nc.get_host('server1')

но я получаю;

File "./icinga.py", line 51, in <module>
    print nc.get_host('server1')
  File "/Library/Python/2.7/site-packages/pynag/Parsers/__init__.py", line 1259, in get_host
    return self.get_object('host', object_name, user_key=user_key)
  File "/Library/Python/2.7/site-packages/pynag/Parsers/__init__.py", line 1238, in get_object
    for item in self.data['all_%s' % object_type]:
KeyError: 'all_host'

Есть ли простой способ работы с таким форматом?

3 ответа

Используя pyparsing, нетрудно работать с таким структурированным текстовым форматом, как этот.

Вот как может выглядеть парсер:

from pyparsing import (Suppress, Keyword, Word, alphas, alphanums, Combine, 
    OneOrMore, quotedString, removeQuotes, Group, ZeroOrMore)

LBRACE,RBRACE,EQ = map(Suppress, "{}=")

OBJECT = Keyword("object")
IMPORT = Keyword("import")

ident = Word(alphas, alphanums)
dottedIdent = Combine(ident + OneOrMore("." + ident))

quotedString.setParseAction(removeQuotes)

propertyDefn = Group((dottedIdent | ident)("name") + EQ + quotedString("value"))

importDirective = Group(IMPORT + quotedString('source'))

objectBodyDefn = Group(ZeroOrMore(propertyDefn("properties*") | 
                                  importDirective("imports*")))

objectDefn = Group(OBJECT + ident("type") + quotedString("name") +
                    LBRACE + objectBodyDefn("body") + RBRACE)

parser = ZeroOrMore(objectDefn)

Вот как применить анализатор и получить доступ к проанализированным данным:

# parsing the sample, and accessing the parsed data fields
for obj in parser.parseString(sample):
    print(obj.dump())
    print("%(name)s (%(type)s)" % obj)
    print("imports:", ','.join(imp.source for imp in obj.body.imports))
    print("properties:")
    if obj.body.properties:
        for prop in obj.body.properties:
            print('-', prop.name, ':', prop.value)
    else:
        print(' ','<none>')
    print()

С этим выводом:

['object', 'Host', 'server1', [['import', 'generic-host'], ['address', '192.168.0.1'], ['vars.os', 'Linux']]]
- body: [['import', 'generic-host'], ['address', '192.168.0.1'], ['vars.os', 'Linux']]
  - imports: 
    [0]:
      ['import', 'generic-host']
      - source: generic-host
  - properties: 
    [0]:
      ['address', '192.168.0.1']
      - name: address
      - value: 192.168.0.1
    [1]:
      ['vars.os', 'Linux']
      - name: vars.os
      - value: Linux
- name: server1
- type: Host
server1 (Host)
imports: generic-host
properties:
- address : 192.168.0.1
- vars.os : Linux

['object', 'Host', 'server2', [['import', 'generic-host'], ['address', '192.168.0.2'], ['vars.os', 'Linux']]]
- body: [['import', 'generic-host'], ['address', '192.168.0.2'], ['vars.os', 'Linux']]
  - imports: 
    [0]:
      ['import', 'generic-host']
      - source: generic-host
  - properties: 
    [0]:
      ['address', '192.168.0.2']
      - name: address
      - value: 192.168.0.2
    [1]:
      ['vars.os', 'Linux']
      - name: vars.os
      - value: Linux
- name: server2
- type: Host
server2 (Host)
imports: generic-host
properties:
- address : 192.168.0.2
- vars.os : Linux

Я использую снипплет вот так:

icinga_conf+='object Host "%s" {\n\timport "generic-LinuxHost"\n\t' \
                         'address = "%s"\n\t' \
                         'vars.http_vhost="%s"\n\t' \
                         '%s' \
                         '\n\t}' \
                         '\n\n' % (icinga_name,ip,name,backupvars)

Я создаю dict с файлом conf хоста, вот так:

import re
with open('hosts.conf', 'r') as f:
    lines = f.readlines()
    host=dict()
    add_attributes = False
    p= re.compile('obj[]\w\s]+"(.+)"')
    for line in lines:
        if '}' in line:
            add_attributes = False
        if  add_attributes and '=' in line:
            host[name][line.split('=')[0]]=line.split('=')[1]
        if p.search(line):
            name=p.search(line).group(1)
            add_attributes = True
            host[name]=dict()

Тогда у меня есть диктат, который легко разобрать.

Другие вопросы по тегам