linspector-old/lib/config/parser.py

266 lines
10 KiB
Python
Raw Normal View History

2013-06-11 04:52:20 +02:00
from os.path import isfile
from os.path import join
from os import getcwd
2013-06-11 01:21:18 +02:00
import json
2013-06-18 00:10:14 +02:00
import sys
import imp
2013-06-11 01:21:18 +02:00
from layouts import Layout
from hostgroups import HostGroup
2013-06-18 00:10:14 +02:00
from members import Member
from periods import CronPeriod, DatePeriod, IntervalPeriod
2013-06-11 01:21:18 +02:00
2013-06-18 00:10:14 +02:00
from lib.services.service import Service
2013-06-19 03:26:25 +02:00
#print id(Service)
2013-06-18 00:10:14 +02:00
from lib.processors.processor import Processor
from lib.parsers.parser import Parser
from lib.tasks.task import Task
2013-06-18 01:50:01 +02:00
2013-06-18 00:10:14 +02:00
MOD_SERVICES = "services"
MOD_PROCESSORS = "processors"
MOD_PARSERS = "parsers"
MOD_TASKS = "tasks"
KEY_LAYOUTS = "layouts"
KEY_HOSTGROUPS = "hostgroups"
KEY_MEMBERS = "members"
KEY_PERIODS = "periods"
KEY_CORE = "core"
2013-06-19 03:26:25 +02:00
2013-06-11 01:21:18 +02:00
class ConfigurationException(Exception):
def __init__(self, msg, log):
log.e(msg)
self.msg = msg
def __str__(self):
return repr(self.msg)
class ConfigParser:
def __init__(self, log):
2013-06-18 02:58:40 +02:00
"""
2013-06-11 01:21:18 +02:00
initializes a new ConfigParser Object
2013-06-19 03:26:25 +02:00
:param log: pre configured logger Object to post messages while parsing"
2013-06-18 02:58:40 +02:00
"""
2013-06-11 01:21:18 +02:00
self.log = log
self.hostgroups = {}
self.members = {}
self.periods = {}
2013-06-18 00:10:14 +02:00
self.layouts = {}
2013-06-19 03:26:25 +02:00
self._loadedMods = {MOD_SERVICES: {}, MOD_PROCESSORS: {}, MOD_TASKS: {}, MOD_PARSERS: {}}
2013-06-18 00:10:14 +02:00
def _create_new_config_dict(self):
2013-06-19 01:56:04 +02:00
return {"members": {}, "periods": {}, "hostgroups": {}, "layouts": {}, "core": {}}
2013-06-18 00:10:14 +02:00
def create_config(self, config):
configDict = self._create_new_config_dict()
for layout in config.get_layouts():
layout._to_config_dict(configDict)
2013-06-11 04:52:20 +02:00
2013-06-11 01:21:18 +02:00
def _read_json_config(self, configFilename):
2013-06-18 02:58:40 +02:00
"""
2013-06-11 01:21:18 +02:00
reads the config File and returns a dictionary, while lowering the first keys
2013-06-19 03:26:25 +02:00
:param configFilename: the path under which the configuration file should be found
2013-06-18 02:58:40 +02:00
"""
2013-06-11 04:52:20 +02:00
if not isfile(configFilename):
2013-06-11 01:21:18 +02:00
msg = "config file not found at " + str(configFilename)
raise ConfigurationException(msg, self.log)
2013-06-19 03:26:25 +02:00
self.configFilename = configFilename
2013-06-11 01:21:18 +02:00
with open(configFilename) as cfgFile:
config = cfgFile.read()
self.log.i("reading Config: " + configFilename)
return json.loads(config)
2013-06-18 00:10:14 +02:00
def _create_raw_Object(self, jsonDict, msgName, creator):
2013-06-19 02:20:30 +02:00
"""
creates an Main object from the configuration, but just parses raw data and hands it to the object
:param jsonDict: the configuration file part as dict
:param msgName: name of object for error message
:param creator: function pointer which is taking two arguments: identifier of the object and arguments.
:should return an object
:return: a list of objects returned by creator
"""
2013-06-18 00:10:14 +02:00
items = []
for key, val in jsonDict.items():
try:
item = creator(key, val)
items.append(item)
except Exception:
self.log.w("ignoring " + msgName + ": " + key + "! reason:")
self.log.w(str(Exception))
return items
2013-06-11 01:21:18 +02:00
2013-06-18 00:10:14 +02:00
def _load_module(self, clazz, modPart):
2013-06-19 02:20:30 +02:00
"""
imports and caches a module.
2013-06-19 03:26:25 +02:00
2013-06-19 02:20:30 +02:00
:param clazz: the filename of the module (i.e email, ping...)
:param modPart: the folder of the module. (i.e services, parsers...)
:return: the imported/cached module, or throws an error if it couldn't find it
"""
2013-06-18 00:10:14 +02:00
mods = self._loadedMods[modPart]
if clazz in mods:
return mods["class"]
else:
2013-06-18 02:19:50 +02:00
mod = __import__(clazz)
#path = join(getcwd(), "lib", modPart, clazz + ".py")
#self.log.w(path)
#mod = imp.load_source(clazz, path)
2013-06-18 02:19:50 +02:00
mods[clazz] = mod
2013-06-18 02:19:09 +02:00
return mod
2013-06-18 00:10:14 +02:00
def replace_with_import(self, objList, modPart, items_func, class_check):
2013-06-19 02:20:30 +02:00
"""
replaces configuration dicts with their objects by importing and creating it in the first step.
In the second step the original list of json config dicts gets replaced by the loaded objects
2013-06-19 03:26:25 +02:00
2013-06-19 02:20:30 +02:00
:param objList: the list of objects which is iterated on
:param modPart: the folder from the module (i.e tasks, parsers)
:param items_func: function to get a pointer on the list of json-config-objects to replace. Takes one argument and
:param class_check: currently unsupported
"""
2013-06-18 00:10:14 +02:00
for obj in objList:
repl = []
items = items_func(obj)
for clazzItem in items:
try:
if "class" not in clazzItem:
self.log.w("python says class is not in class item!")
self.log.w(modPart)
self.log.w(clazzItem)
self.log.w(clazzItem["class"])
2013-06-18 00:10:14 +02:00
clazz = clazzItem["class"]
path = "lib/" + modPart
sys.path.append(path)
2013-06-18 00:10:14 +02:00
mod = self._load_module(clazz, modPart)
item = mod.create(clazzItem)
repl.append(item)
#TODO: activate the crappy classcheck if answer is provided
#http://stackoverflow.com/questions/17179440/
self.log.d("warning: instance_check isn't working yet! TRUST_ALL = TRUE")
#if class_check(item):
# repl.append(item)
#else:
# self.log.w(" ignoring class " + clazzItem["class"] + "! It does not pass the class check!")
2013-06-18 00:10:14 +02:00
except ImportError, err:
self.log.w("could not import " + clazz + ": " + str(clazzItem) + "! reason")
self.log.w(str(err))
except KeyError, k:
self.log.w("Key " + str(k) + " not in classItem " + str(clazzItem))
except Exception, e:
2013-06-19 02:25:37 +02:00
self.log.w("Error while replacing class ( " + clazz + " ):" + str(e))
finally:
if path in sys.path:
del sys.path[sys.path.index(path)]
2013-06-18 00:10:14 +02:00
del items[:]
items.extend(repl)
def replace_pointer(self, objectList, replObjectList, id_list_func, id_get_func):
2013-06-19 02:20:30 +02:00
"""
replaces objects from the config by ids.
2013-06-19 03:26:25 +02:00
2013-06-19 02:20:30 +02:00
:param objectList: the list of objects to be iterated on
:param replObjectList: the list of objects to replace
:param id_list_func: function taking one argument as object and should return a list of config ids to replace
:param id_get_func: function taking one config-object as argument and should return the config id to compare
"""
for obj in objectList:
replacements = []
idList = id_list_func(obj)
for id in idList:
repl = [o for o in replObjectList if id == id_get_func(o)]
if len(repl) == 1:
replacements.append(repl[0])
del idList[:]
idList.extend(replacements)
2013-06-11 01:21:18 +02:00
def parse_config(self, configFilename):
2013-06-19 01:56:04 +02:00
pass
2013-06-18 00:10:14 +02:00
def parsePeriodList(name, values):
if "date" in values:
return DatePeriod(name, **values)
comp = ["weeks", "days", "hours", "minutes", "seconds", "start_date"]
if len([i for i in comp if i in values]) > 0 :
return IntervalPeriod(name, **values)
comp = ["year", "month", "day", "week", "day_of_week", "hour", "minute", "second"]
if len([i for i in comp if i in values]) > 0 :
return CronPeriod(name, **values)
else:
raise ConfigurationException("could not determine correct Period(" + repr(values)+").")
2013-06-18 02:58:40 +02:00
2013-06-18 00:10:14 +02:00
class FullConfigParser(ConfigParser):
def parse_config(self, configFilename):
2013-06-18 02:58:40 +02:00
"""
2013-06-18 00:10:14 +02:00
parses the json configuration and returns a list of layouts,
2013-06-19 03:26:25 +02:00
which contains all necessary information of the config file.
2013-06-18 00:10:14 +02:00
parses the full config
Parsing will be done in 3 steps:
1. get raw Config Objects by just passing the values defined inside the config
2. replace references by objects, import services, tasks, parsers and processors
3. do sanity checks
2013-06-19 03:26:25 +02:00
:param configFilename: the configuration file to parse
2013-06-18 02:58:40 +02:00
"""
2013-06-18 00:10:14 +02:00
self.jsonDict = self._read_json_config(configFilename)
# first step
creator = lambda name, values: Layout(name,**values)
layouts = self._create_raw_Object(self.jsonDict[KEY_LAYOUTS], "Layout", creator)
creator = lambda name, values: Member(name, **values)
members = self._create_raw_Object(self.jsonDict[KEY_MEMBERS], "Member", creator)
creator = lambda name, values: HostGroup(name, **values)
hostgroups = self._create_raw_Object(self.jsonDict[KEY_HOSTGROUPS], "Hostgroup", creator)
creator = parsePeriodList
periods = self._create_raw_Object(self.jsonDict[KEY_PERIODS], "Period", creator)
2013-06-18 00:10:14 +02:00
#2. import and replace
items_func = lambda hostgroup: hostgroup.get_services()
class_check = lambda service: isinstance(service, Service)
self.replace_with_import(hostgroups, MOD_SERVICES, items_func, class_check)
items_func = lambda hostgroup: hostgroup.get_processors()
class_check = lambda processor: isinstance(processor, Processor)
self.replace_with_import(hostgroups, MOD_PROCESSORS, items_func, class_check)
services = []
for hg in hostgroups:
services.extend(hg.get_services())
2013-06-18 00:10:14 +02:00
items_func = lambda service: service.get_parser()
class_check = lambda parser: isinstance(parser, Parser)
self.replace_with_import(services, MOD_PARSERS, items_func, class_check)
2013-06-18 00:10:14 +02:00
items_func = lambda member: member.get_tasks()
class_check = lambda task: isinstance(task, Task)
self.replace_with_import(members, MOD_TASKS, items_func, class_check)
#replace object pointer
id_list_func = lambda hostgroup: hostgroup.get_members()
id_get_func = lambda member: member.id
self.replace_pointer(hostgroups, members, id_list_func, id_get_func)
id_list_func = lambda service: service.get_periods()
id_get_func = lambda period: period.get_name()
self.replace_pointer(services, periods, id_list_func, id_get_func)
id_list_func = lambda layout: layout.get_hostgroups()
id_get_func = lambda hostgroup: hostgroup.get_name()
self.replace_pointer(layouts, hostgroups, id_list_func, id_get_func)
2013-06-18 02:58:40 +02:00
return layouts