Skip to content
config.py 6.11 KiB
Newer Older
# 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 <http://www.gnu.org/licenses/>.


Antoine Millet's avatar
Antoine Millet committed
import socket
import logging
import logging.config
from StringIO import StringIO
Anael Beutot's avatar
Anael Beutot committed
from itertools import ifilterfalse
from ConfigParser import SafeConfigParser, NoOptionError, NoSectionError

from cloudcontrol.common.client.exc import ConfigError
logger = logging.getLogger(__name__)
Anael Beutot's avatar
Anael Beutot committed
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):
Anael Beutot's avatar
Anael Beutot committed
        config = _ConfigProxy(SafeConfigParser())
        config.read(file_path)
        # ccserver settings
Anael Beutot's avatar
Anael Beutot committed
        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')
Anael Beutot's avatar
Anael Beutot committed
        # 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")')
Anael Beutot's avatar
Anael Beutot committed
        self.debug = config.getboolean('node', 'debug', False)
        self.logging_output = 'console' if self.debug else 'syslog'
Anael Beutot's avatar
Anael Beutot committed
        # path settings
Anael Beutot's avatar
Anael Beutot committed
        self.jobs_store_path = config.get('node', 'jobs_store_path',
Anael Beutot's avatar
Anael Beutot committed
                                          '/var/lib/cc-node/jobs')
        # plugins persistance
Anael Beutot's avatar
Anael Beutot committed
        self.plugins_store_path = config.get('node', 'plugins_store_path',
                                             '/var/lib/cc-node/plugins')
Anael Beutot's avatar
Anael Beutot committed

Antoine Millet's avatar
Antoine Millet committed
        # 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)

Anael Beutot's avatar
Anael Beutot committed
        # 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'))
Anael Beutot's avatar
Anael Beutot committed
        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

    # create config parser for logging configuration
    logging.config.fileConfig(StringIO("""
[loggers]
Anael Beutot's avatar
Anael Beutot committed
keys=root,ccnode,cccommon,sjrpc

[formatters]
keys=simpleFormatter

[logger_root]
level=ERROR

[logger_ccnode]
Anael Beutot's avatar
Anael Beutot committed
level=%(level)s
handlers=
qualname=cloudcontrol.node

Anael Beutot's avatar
Anael Beutot committed
[logger_cccommon]
level=%(level)s
handlers=
qualname=cloudcontrol.common

[logger_sjrpc]
level=ERROR
handlers=
qualname=sjrpc

%(output)s
    """ % dict(level=level, output=output)))