# This file is part of CloudControl. # # CloudControl is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # CloudControl is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with CloudControl. If not, see . import socket import logging import logging.config from StringIO import StringIO from itertools import ifilterfalse from ConfigParser import SafeConfigParser, NoOptionError, NoSectionError from cloudcontrol.common.client.exc import ConfigError logger = logging.getLogger(__name__) class _ConfigProxy(object): """Simple ConfigParser proxy that provide default values for get* methods. """ def __init__(self, config_parser): self.config = config_parser @staticmethod def config_error(msg): logger.error(msg) raise ConfigError(msg) def __getattr__(self, name): if name.startswith('get'): def getter(section, option, *default): assert not default or len(default) == 1 try: return getattr(self.config, name)(section, option) except NoSectionError: self.config_error('Section "%s" is not present in config' ' file' % section) except NoOptionError: if default: return default[0] self.config_error( 'Attribute "%s" not specified in config' ' file (section "%s")' % (option, section)) except ValueError: self.config_error( 'Configuration attribute "%s" value is invalid' ' (section "%s")' % (option, section)) return getter # else return getattr(self.config, name) class NodeConfigParser(object): """ConfigParser for ccnode config file.""" def __init__(self, file_path): config = _ConfigProxy(SafeConfigParser()) config.read(file_path) # ccserver settings self.server_host = config.get('node', 'address') self.server_port = config.getint('node', 'port', 1984) self.server_user = config.get('node', 'login') self.server_passwd = config.get('node', 'password') # node settings try: self.logging_level = config.getint('node', 'verbosity', 0) except ConfigError: try: self.logging_level = dict( debug=3, info=2, warning=1, error=0, )[config.get('node', 'verbosity')] except KeyError: _ConfigProxy.config_error( 'Configuration attribute "verbosity"' ' is invalid (section "node")') self.debug = config.getboolean('node', 'debug', False) self.logging_output = 'console' if self.debug else 'syslog' # path settings self.jobs_store_path = config.get('node', 'jobs_store_path', '/var/lib/cc-node/jobs') # plugins persistance self.plugins_store_path = config.get('node', 'plugins_store_path', '/var/lib/cc-node/plugins') # Libvirt URI to export to cc-server (vir_uri tag) default_libvirt_uri = 'qemu+tcp://%s/system' % socket.gethostbyname(socket.gethostname()) self.libvirt_uri = config.get('node', 'libvirt_uri', default_libvirt_uri) # Path to define script default_define_script = 'hkvm-define' self.define_script = config.get('node', 'define_script', default_define_script) default_rescue_script = 'hkvm-rescue' self.rescue_script = config.get('node', 'rescue_script', default_rescue_script) default_vlan_script = 'hkvm-vlan' self.vlan_script = config.get('node', 'vlan_script', default_vlan_script) default_attach_script = 'hkvm-attach' self.attach_script = config.get('node', 'attach_script', default_attach_script) default_detach_script = 'hkvm-detach' self.detach_script = config.get('node', 'detach_script', default_detach_script) # RPC handler ACLs acl_section_name = 'node_handler' if config.has_section(acl_section_name): self.forbidden_handlers = set(ifilterfalse( lambda o: config.getboolean(acl_section_name, o, True), config.options(acl_section_name), )) else: self.forbidden_handlers = set() # backward compatibility command_execution_handlers = set(('shutdown', 'execute')) if config.getboolean('node', 'command_execution', None) == False: self.forbidden_handlers |= command_execution_handlers else: self.forbidden_handlers -= command_execution_handlers # deprecated options for o in ('detect_hypervisor', 'force_xen'): if config.get('node', o, None) is not None: logger.warning('%s config option is not supported anymore', o) def configure_logging(level, output): level = { 0: 'ERROR', 1: 'WARNING', 2: 'INFO', 3: 'DEBUG', }[level] output = dict( console=""" [handler_output] class=StreamHandler formatter=simpleFormatter args=(sys.stderr,) [formatter_simpleFormatter] format=cc-node - %(asctime)s - %(name)s - %(levelname)s - %(message)s """, syslog=""" [handler_output] class=handlers.SysLogHandler formatter=simpleFormatter args=('/dev/log', handlers.SysLogHandler.LOG_DAEMON) [formatter_simpleFormatter] class=cloudcontrol.common.helpers.formatter.EncodingFormatter format=cc-node - %(name)s - %(levelname)s - %(message)s """, )[output] # create config parser for logging configuration logging.config.fileConfig(StringIO(""" [loggers] keys=root,ccnode,cccommon,sjrpc [handlers] keys=output [formatters] keys=simpleFormatter [logger_root] level=ERROR handlers=output [logger_ccnode] level=%(level)s handlers= qualname=cloudcontrol.node [logger_cccommon] level=%(level)s handlers= qualname=cloudcontrol.common [logger_sjrpc] level=ERROR handlers= qualname=sjrpc %(output)s """ % dict(level=level, output=output)))