From 00358434594bf5621f62235c2ef7ac3d1d21d80e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20K=C3=A1cha?= <ph@cesnet.cz> Date: Mon, 12 Sep 2016 13:38:59 +0200 Subject: [PATCH] Refactored configuration for outside world usage (also simplified and got rid of ugly globals()) --- warden3/warden_server/warden_server.py | 211 ++++++++++++++----------- 1 file changed, 115 insertions(+), 96 deletions(-) diff --git a/warden3/warden_server/warden_server.py b/warden3/warden_server/warden_server.py index 736a437..3d30fce 100755 --- a/warden3/warden_server/warden_server.py +++ b/warden3/warden_server/warden_server.py @@ -1193,7 +1193,95 @@ def fallback_wsgi(environ, start_response, exc_info=None): return [output] -def build_server(conf): +# Order in which the base objects must get initialized +section_order = ("log", "db", "auth", "validator", "handler", "server") + +# List of sections and objects, configured by them +# First object in each object list is the default one, otherwise +# "type" keyword in section may be used to choose other +section_def = { + "log": [FileLogger, SysLogger], + "db": [MySQL], + "auth": [X509Authenticator, PlainAuthenticator, X509NameAuthenticator, X509MixMatchAuthenticator], + "validator": [JSONSchemaValidator, NoValidator], + "handler": [WardenHandler], + "server": [Server] +} + +# Object parameter conversions and defaults +param_def = { + FileLogger: { + "req": {"type": "obj", "default": "req"}, + "filename": {"type": "filepath", "default": path.join(path.dirname(__file__), path.splitext(path.split(__file__)[1])[0] + ".log")}, + "level": {"type": "loglevel", "default": "info"}, + }, + SysLogger: { + "req": {"type": "obj", "default": "req"}, + "socket": {"type": "filepath", "default": "/dev/log"}, + "facility": {"type": "facility", "default": "daemon"}, + "level": {"type": "loglevel", "default": "info"} + }, + PlainAuthenticator: { + "req": {"type": "obj", "default": "req"}, + "log": {"type": "obj", "default": "log"}, + "db": {"type": "obj", "default": "db"} + }, + X509Authenticator: { + "req": {"type": "obj", "default": "req"}, + "log": {"type": "obj", "default": "log"}, + "db": {"type": "obj", "default": "db"} + }, + X509NameAuthenticator: { + "req": {"type": "obj", "default": "req"}, + "log": {"type": "obj", "default": "log"}, + "db": {"type": "obj", "default": "db"} + }, + NoValidator: { + "req": {"type": "obj", "default": "req"}, + "log": {"type": "obj", "default": "log"}, + }, + JSONSchemaValidator: { + "req": {"type": "obj", "default": "req"}, + "log": {"type": "obj", "default": "log"}, + "filename": {"type": "filepath", "default": path.join(path.dirname(__file__), "idea.schema")} + }, + MySQL: { + "req": {"type": "obj", "default": "req"}, + "log": {"type": "obj", "default": "log"}, + "host": {"type": "str", "default": "localhost"}, + "user": {"type": "str", "default": "warden"}, + "password": {"type": "str", "default": ""}, + "dbname": {"type": "str", "default": "warden3"}, + "port": {"type": "natural", "default": 3306}, + "retry_pause": {"type": "natural", "default": 5}, + "retry_count": {"type": "natural", "default": 3}, + "event_size_limit": {"type": "natural", "default": 5*1024*1024}, + "catmap_filename": {"type": "filepath", "default": path.join(path.dirname(__file__), "catmap_mysql.json")}, + "tagmap_filename": {"type": "filepath", "default": path.join(path.dirname(__file__), "tagmap_mysql.json")} + }, + WardenHandler: { + "req": {"type": "obj", "default": "req"}, + "log": {"type": "obj", "default": "log"}, + "validator": {"type": "obj", "default": "validator"}, + "db": {"type": "obj", "default": "DB"}, + "auth": {"type": "obj", "default": "auth"}, + "send_events_limit": {"type": "natural", "default": 500}, + "get_events_limit": {"type": "natural", "default": 1000}, + "description": {"type": "str", "default": ""} + }, + Server: { + "req": {"type": "obj", "default": "req"}, + "log": {"type": "obj", "default": "log"}, + "auth": {"type": "obj", "default": "auth"}, + "handler": {"type": "obj", "default": "handler"} + } +} + + +def build_server(conf, section_order=section_order, section_def=section_def, param_def=param_def): + + objects = {} # Already initialized objects + # Functions for validation and conversion of config values def facility(name): @@ -1212,93 +1300,20 @@ def build_server(conf): # Make paths relative to dir of this script return path.join(path.dirname(__file__), name) - def objdef(name): + def obj(name): return objects[name.lower()] - obj = objdef # Draw into local namespace for init_obj - objects = {} # Already initialized objects - - # List of sections and objects, configured by them - # First object in each object list is the default one, otherwise - # "type" keyword in section may be used to choose other - section_def = { - "log": ["FileLogger", "SysLogger"], - "db": ["MySQL"], - "auth": ["X509Authenticator", "PlainAuthenticator", "X509NameAuthenticator", "X509MixMatchAuthenticator"], - "validator": ["JSONSchemaValidator", "NoValidator"], - "handler": ["WardenHandler"], - "server": ["Server"] + # Typedef dictionary + conv_dict = { + "facility": facility, + "loglevel": loglevel, + "natural": natural, + "filepath": filepath, + "obj": obj, + "str": str } - # Object parameter conversions and defaults - param_def = { - "FileLogger": { - "req": {"type": obj, "default": "req"}, - "filename": {"type": filepath, "default": path.join(path.dirname(__file__), path.splitext(path.split(__file__)[1])[0] + ".log")}, - "level": {"type": loglevel, "default": "info"}, - }, - "SysLogger": { - "req": {"type": obj, "default": "req"}, - "socket": {"type": filepath, "default": "/dev/log"}, - "facility": {"type": facility, "default": "daemon"}, - "level": {"type": loglevel, "default": "info"} - }, - "PlainAuthenticator": { - "req": {"type": obj, "default": "req"}, - "log": {"type": obj, "default": "log"}, - "db": {"type": obj, "default": "db"} - }, - "X509Authenticator": { - "req": {"type": obj, "default": "req"}, - "log": {"type": obj, "default": "log"}, - "db": {"type": obj, "default": "db"} - }, - "X509NameAuthenticator": { - "req": {"type": obj, "default": "req"}, - "log": {"type": obj, "default": "log"}, - "db": {"type": obj, "default": "db"} - }, - "NoValidator": { - "req": {"type": obj, "default": "req"}, - "log": {"type": obj, "default": "log"}, - }, - "JSONSchemaValidator": { - "req": {"type": obj, "default": "req"}, - "log": {"type": obj, "default": "log"}, - "filename": {"type": filepath, "default": path.join(path.dirname(__file__), "idea.schema")} - }, - "MySQL": { - "req": {"type": obj, "default": "req"}, - "log": {"type": obj, "default": "log"}, - "host": {"type": str, "default": "localhost"}, - "user": {"type": str, "default": "warden"}, - "password": {"type": str, "default": ""}, - "dbname": {"type": str, "default": "warden3"}, - "port": {"type": natural, "default": 3306}, - "retry_pause": {"type": natural, "default": 5}, - "retry_count": {"type": natural, "default": 3}, - "event_size_limit": {"type": natural, "default": 5*1024*1024}, - "catmap_filename": {"type": filepath, "default": path.join(path.dirname(__file__), "catmap_mysql.json")}, - "tagmap_filename": {"type": filepath, "default": path.join(path.dirname(__file__), "tagmap_mysql.json")} - }, - "WardenHandler": { - "req": {"type": obj, "default": "req"}, - "log": {"type": obj, "default": "log"}, - "validator": {"type": obj, "default": "validator"}, - "db": {"type": obj, "default": "DB"}, - "auth": {"type": obj, "default": "auth"}, - "send_events_limit": {"type": natural, "default": 500}, - "get_events_limit": {"type": natural, "default": 1000}, - "description": {"type": str, "default": ""} - }, - "Server": { - "req": {"type": obj, "default": "req"}, - "log": {"type": obj, "default": "log"}, - "auth": {"type": obj, "default": "auth"}, - "handler": {"type": obj, "default": "handler"} - } - } def init_obj(sect_name): config = conf.get(sect_name, {}) @@ -1309,17 +1324,21 @@ def build_server(conf): objtype = config["type"] del config["type"] except KeyError: # No, fetch default object type for this section - objtype = sect_def[0] - else: - if not objtype in sect_def: + cls = sect_def[0] + else: # Yes, get corresponding class/callable + names = [o.__name__ for o in sect_def] + try: + idx = names.index(objtype) + except ValueError: raise KeyError("Unknown type %s in section %s" % (objtype, sect_name)) + cls = sect_def[idx] - params = param_def[objtype] + params = param_def[cls] # No surplus parameters? Disallow also 'obj' attributes, these are only # to provide default referenced section for name in config: - if name not in params or (name in params and params[name]["type"] is objdef): + if name not in params or (name in params and params[name]["type"] == "obj"): raise KeyError("Unknown key %s in section %s" % (name, sect_name)) # Process parameters @@ -1327,24 +1346,24 @@ def build_server(conf): for name, definition in params.iteritems(): raw_val = config.get(name, definition["default"]) try: - val = definition["type"](raw_val) + type_callable = conv_dict[definition["type"]] + val = type_callable(raw_val) except Exception: raise KeyError("Bad value \"%s\" for %s in section %s" % (raw_val, name, sect_name)) kwargs[name] = val - cls = globals()[objtype] # get class/function type try: - obj = cls(**kwargs) # run it + obj_inst = cls(**kwargs) # run it except Exception as e: raise KeyError("Cannot initialize %s from section %s: %s" % ( objtype, sect_name, str(e))) - if isinstance(obj, Object): + if isinstance(obj_inst, Object): # Log only objects here, functions must take care of themselves - logging.getLogger(__name__).info("Initialized %s" % str(obj)) + logging.getLogger(__name__).info("Initialized %s" % str(obj_inst)) - objects[sect_name] = obj - return obj + objects[sect_name] = obj_inst + return obj_inst # Init logging with at least simple stderr StreamLogger # Dunno if it's ok within wsgi, but we have no other choice, let's @@ -1356,7 +1375,7 @@ def build_server(conf): try: # Now try to init required objects - for o in ("log", "db", "auth", "validator", "handler", "server"): + for o in section_order: init_obj(o) except Exception as e: logging.getLogger(__name__).critical(str(e)) -- GitLab