1

I'm trying to write a wrapper for an icinga2 instance. The objets inside the config files look like this;

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

example;

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"
}

I'm looking to do something like:

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

print icinga.hosts_list()

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

So I tried using pynag, something like;

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

but I'm getting;

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'

Is there an easy way to work with this kind of formar?

Marcelo Grebois
  • 383
  • 1
  • 4
  • 14

3 Answers3

3

Using pyparsing, it is not hard to work through a structured text format like this.

Here is what the parser might look like:

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)

Here's how to apply the parser and access the parsed data:

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

With this output:

['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
Wolkenarchitekt
  • 20,170
  • 29
  • 111
  • 174
PaulMcG
  • 62,419
  • 16
  • 94
  • 130
0

I use snipplet like this:

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)
BaZZiliO
  • 232
  • 1
  • 6
0

I create a dict with the host conf file, like this :

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()

Then, I have a dict easy to parse.