Разбор файлов 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()
Тогда у меня есть диктат, который легко разобрать.