From e8c9ba57d10d174c79ac1aae9b53661ee8464d0f Mon Sep 17 00:00:00 2001 From: Robert Gogolok Date: Sun, 30 Dec 2007 19:26:51 +0000 Subject: Settings class to remove redundant code for parsing config file. If a module wants to access bcfg2 settings: from Bcfg2.Settings import settings git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@4131 ce84e21b-d406-0410-9b95-82705330c041 --- src/lib/Client/Proxy.py | 62 +++++----------- src/lib/Component.py | 39 ++++------ src/lib/Options.py | 25 +------ src/lib/Server/Admin/__init__.py | 2 +- src/lib/Server/Core.py | 23 +++--- src/lib/Server/Plugins/Metadata.py | 6 +- src/lib/Settings.py | 145 +++++++++++++++++++++++++++++++++++++ src/sbin/bcfg2 | 10 ++- src/sbin/bcfg2-info | 10 ++- src/sbin/bcfg2-server | 9 ++- 10 files changed, 217 insertions(+), 114 deletions(-) create mode 100644 src/lib/Settings.py (limited to 'src') diff --git a/src/lib/Client/Proxy.py b/src/lib/Client/Proxy.py index b56ccbfa5..8e34a0fb5 100644 --- a/src/lib/Client/Proxy.py +++ b/src/lib/Client/Proxy.py @@ -6,6 +6,7 @@ from Bcfg2.tlslite.integration.XMLRPCTransport import XMLRPCTransport from Bcfg2.tlslite.integration.HTTPTLSConnection import HTTPTLSConnection from Bcfg2.tlslite.TLSConnection import TLSConnection import Bcfg2.tlslite.errors +from Bcfg2.Settings import settings #FIXME need to reimplement _binadaddress support for XMLRPCTransport @@ -49,63 +50,36 @@ class SafeProxy: _retries = 4 _authinfo = () - _components = {} def __init__(self, component, args={}): self.component = component self.log = logging.getLogger(component) - if args.has_key('server'): - # processing from command line args - self._components[component] = args['server'] - else: - if args.has_key('setup'): - # processing from specified config file - _cfpath = args['setup'] - else: - _cfpath = '/etc/bcfg2.conf' - self._cfile = ConfigParser.ConfigParser() - self._cfile.read([_cfpath]) - try: - self._components = self._cfile._sections['components'] - except: - self.log.error("%s doesn't contain a valid components section" % (_cfpath)) - raise SystemExit, 1 - if args.has_key('password'): - # get passwd from cmdline + password = settings.COMMUNICATION_PASSWORD + if args['password']: password = args['password'] - else: - try: - password = self._cfile.get('communication', 'password') - except: - self.log.error("%s doesn't contain a valid password" % (_cfpath)) - raise SystemExit, 1 - if args.has_key('user'): + + user = settings.COMMUNICATION_USER + if args['user']: user = args['user'] - else: - try: - user = self._cfile.get('communication', 'user') - except: - user = 'root' self._authinfo = (user, password) - if args.has_key('fingerprint'): + self.fingerprint = False + if args['fingerprint']: self.fingerprint = args['fingerprint'] - else: - self.fingerprint = False - _bindaddress = "" - try: - _bindaddress = self._cfile.get('communication', 'bindaddress') - except: - pass - - if args.has_key('server'): + address = settings.COMPONENTS_BCFG2 + if args['server']: address = args['server'] - else: - address = self.__get_location(component) - + + # NOT USED + #_bindaddress = "" + #try: + # _bindaddress = self._cfile.get('communication', 'bindaddress') + #except: + # pass try: + # NOT USED # if _bindaddress != "": # self.log.info("Binding client to address %s" % _bindaddress) # self.proxy = xmlrpclib.ServerProxy(address, transport=Bcfg2SafeTransport()) diff --git a/src/lib/Component.py b/src/lib/Component.py index a6f3e9aa2..442ea8112 100644 --- a/src/lib/Component.py +++ b/src/lib/Component.py @@ -3,6 +3,7 @@ __revision__ = '$Revision$' import atexit, logging, select, signal, socket, sys, time, urlparse, xmlrpclib, cPickle, ConfigParser, os from base64 import decodestring + import BaseHTTPServer, SimpleXMLRPCServer import Bcfg2.tlslite.errors import Bcfg2.tlslite.api @@ -10,6 +11,8 @@ import Bcfg2.tlslite.api import Bcfg2.Client.Proxy as Proxy from Bcfg2.tlslite.TLSConnection import TLSConnection +from Bcfg2.Settings import settings + log = logging.getLogger('Component') class ComponentInitError(Exception): @@ -144,34 +147,20 @@ class Component(TLSServer, signal.signal(signal.SIGINT, self.start_shutdown) signal.signal(signal.SIGTERM, self.start_shutdown) self.logger = logging.getLogger('Component') - self.cfile = ConfigParser.ConfigParser() self.children = [] - if setup['configfile']: - cfilename = setup['configfile'] - else: - cfilename = '/etc/bcfg2.conf' - self.cfile.read([cfilename]) - if not self.cfile.has_section('communication'): - print "Configfile missing communication section" - raise SystemExit, 1 - self.static = False - if not self.cfile.has_section('components'): - print "Configfile missing components section" - raise SystemExit, 1 - if self.cfile._sections['components'].has_key(self.__name__): - self.static = True - location = urlparse.urlparse(self.cfile.get('components', self.__name__))[1].split(':') + self.static = True + + location = settings.COMPONENTS_BCFG2 + if settings.COMPONENTS_BCFG2_STATIC: + location = urlparse.urlparse(settings.COMPONENTS_BCFG2)[1].split(':') location = (location[0], int(location[1])) - else: - location = (socket.gethostname(), 0) - try: - keyfile = self.cfile.get('communication', 'key') - #keyfile = '/tmp/keys/server.pkey' - except ConfigParser.NoOptionError: - print "No key specified in cobalt.conf" + + if not settings.COMMUNICATION_KEY: + print "No key specified in '%s'" % settings.CONFIG_FILE raise SystemExit, 1 + keyfile = settings.COMMUNICATION_KEY - self.password = self.cfile.get('communication', 'password') + self.password = settings.COMMUNICATION_PASSWORD try: TLSServer.__init__(self, location, keyfile, CobaltXMLRPCRequestHandler) @@ -182,7 +171,7 @@ class Component(TLSServer, self.logger.error("Failed to parse key" % (keyfile)) raise ComponentInitError except: - self.logger.error("Failed to load ssl key %s" % (keyfile), exc_info=1) + self.logger.error("Failed to load ssl key '%s'" % (keyfile), exc_info=1) raise ComponentInitError try: SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self) diff --git a/src/lib/Options.py b/src/lib/Options.py index 4c97b1ca5..aab329f4d 100644 --- a/src/lib/Options.py +++ b/src/lib/Options.py @@ -2,20 +2,15 @@ __revision__ = '$Revision$' import getopt, os, sys, ConfigParser -# (option, env, cfpath, default value, option desc, boolean, arg desc) -# ((option, arg desc, opt desc), env, cfpath, default, boolean) -bootstrap = {'configfile': (('-C', '', 'Path to config file'), - 'BCFG2_CONF', False, '/etc/bcfg2.conf', False)} class OptionFailure(Exception): pass class BasicOptionParser: '''Basic OptionParser takes input from command line arguments, environment variables, and defaults''' - def __init__(self, name, optionspec, configfile=False, dogetopt=False): + def __init__(self, name, optionspec, dogetopt=False): self.name = name self.dogetopt = dogetopt - self.configfile = configfile self.optionspec = optionspec if dogetopt: self.shortopt = '' @@ -52,13 +47,6 @@ class BasicOptionParser: print "%s Usage:" % (self.name) print self.helpmsg raise SystemExit, 1 - if self.configfile: - cf = ConfigParser.ConfigParser() - try: - cf.readfp(open(self.configfile)) - except Exception, e: - print "Failed to read configfile: %s\n%s\n" % (self.configfile, e) - raise SystemExit, 1 for key, (option, envvar, cfpath, default, boolean) in self.optionspec.iteritems(): if self.dogetopt: optinfo = [opt[1] for opt in opts if opt[0] == option[0]] @@ -77,19 +65,10 @@ class BasicOptionParser: if envvar and os.environ.has_key(envvar): ret[key] = os.environ[envvar] continue - if self.configfile and cfpath: - try: - value = apply(cf.get, cfpath) - ret[key] = value - continue - except: - pass ret[key] = default return ret class OptionParser(BasicOptionParser): '''OptionParser bootstraps option parsing, getting the value of the config file''' def __init__(self, name, ospec): - # first find the cf file - cfpath = BasicOptionParser('bootstrap', bootstrap).parse()['configfile'] - BasicOptionParser.__init__(self, name, ospec, cfpath, dogetopt=True) + BasicOptionParser.__init__(self, name, ospec, dogetopt=True) diff --git a/src/lib/Server/Admin/__init__.py b/src/lib/Server/Admin/__init__.py index d059e0a1d..57b9d2a86 100644 --- a/src/lib/Server/Admin/__init__.py +++ b/src/lib/Server/Admin/__init__.py @@ -1,4 +1,4 @@ -__revision__ = '$Revision: $' +__revision__ = '$Revision$' __all__ = ['Mode', 'Client', 'Compare', 'Fingerprint', 'Init', 'Minestruct', 'Pull', 'Tidy', 'Viz'] diff --git a/src/lib/Server/Core.py b/src/lib/Server/Core.py index 76cbb8073..7e347bc23 100644 --- a/src/lib/Server/Core.py +++ b/src/lib/Server/Core.py @@ -4,6 +4,7 @@ __revision__ = '$Revision$' from time import time from Bcfg2.Server.Plugin import PluginInitError, PluginExecutionError from Bcfg2.Server.Statistics import Statistics +from Bcfg2.Settings import settings import logging, lxml.etree, os, stat, ConfigParser import Bcfg2.Server.Plugins.Metadata @@ -198,11 +199,9 @@ except ImportError: class Core(object): '''The Core object is the container for all Bcfg2 Server logic, and modules''' - def __init__(self, setup, configfile): + def __init__(self): object.__init__(self) - self.cfile = ConfigParser.ConfigParser() - self.cfile.read([configfile]) - self.datastore = self.cfile.get('server','repository') + self.datastore = settings.SERVER_REPOSITORY try: self.fam = monitor() except IOError: @@ -211,20 +210,22 @@ class Core(object): self.generators = [] self.structures = [] self.cron = {} - self.setup = setup self.plugins = {} self.revision = '-1' + try: - self.svn = self.cfile.get('server', 'svn') == 'yes' - self.read_svn_revision() + if settings.SERVER_SVN: + self.read_svn_revision() except: - self.svn = False + settings.SERVER_SVN = False + + self.svn = settings.SERVER_SVN - mpath = self.cfile.get('server','repository') + mpath = settings.SERVER_REPOSITORY self.stats = Statistics("%s/etc/statistics.xml" % (mpath)) - structures = self.cfile.get('server', 'structures').replace(' ', '').split(',') - generators = self.cfile.get('server', 'generators').replace(' ', '').split(',') + structures = settings.SERVER_STRUCTURES + generators = settings.SERVER_GENERATORS [data.remove('') for data in [structures, generators] if '' in data] for plugin in structures + generators + ['Metadata']: diff --git a/src/lib/Server/Plugins/Metadata.py b/src/lib/Server/Plugins/Metadata.py index ce9d18f7a..5f3262ec0 100644 --- a/src/lib/Server/Plugins/Metadata.py +++ b/src/lib/Server/Plugins/Metadata.py @@ -1,7 +1,9 @@ '''This file stores persistent metadata for the BCFG Configuration Repository''' __revision__ = '$Revision$' -import lxml.etree, re, socket, time, sys, ConfigParser +from Bcfg2.Settings import settings + +import lxml.etree, re, socket, time, sys import Bcfg2.Server.Plugin class MetadataConsistencyError(Exception): @@ -67,7 +69,7 @@ class Metadata(Bcfg2.Server.Plugin.Plugin): self.ptimes = {} self.pctime = 0 self.extra = {'groups.xml':[], 'clients.xml':[]} - self.password = core.cfile.get('communication', 'password') + self.password = settings.COMMUNICATION_PASSWORD def HandleEvent(self, event): '''Handle update events for data files''' diff --git a/src/lib/Settings.py b/src/lib/Settings.py new file mode 100644 index 000000000..4a47c6f8d --- /dev/null +++ b/src/lib/Settings.py @@ -0,0 +1,145 @@ +""" +Settings for bcfg2. +FIXME: simplify code! +FIXME: add statistics configuration +""" + +__revision__ = '$Revision$' + +import logging, socket, ConfigParser + +class Settings(object): + + def __init__(self): + self.CONFIG_FILE = self.default_config_file() + + self.SERVER_GENERATORS = self.default_server_generators() + self.SERVER_REPOSITORY = self.default_server_repository() + self.SERVER_STRUCTURES = self.default_server_structures() + self.SERVER_SVN = self.default_server_svn() + + self.COMMUNICATION_KEY = self.default_communication_key() + self.COMMUNICATION_PASSWORD = self.default_communication_password() + self.COMMUNICATION_PROTOCOL = self.default_communication_protocol() + self.COMMUNICATION_USER = self.default_communication_user() + + self.COMPONENTS_BCFG2 = self.default_components_bcfg2() + self.COMPONENTS_BCFG2_STATIC = self.default_components_bcfg2_static() + + + def __getattr__(self, name): + print "name = %s\n" % name + if name == '__members__': + return self.name() + return getattr(self, name) + + def read_config_file(self, filename): + + logger = logging.getLogger('bcfg2 settings') + + # set config file + if not filename: + logger.info("No config file given. Trying default config file '%s'." % self.CONFIG_FILE) + else: + logger.debug("Trying user specified config file '%s'." % filename) + self.CONFIG_FILE = filename + + # open config file + try: + cf = open(self.CONFIG_FILE) + except IOError: + logger.info("Skipping not accessable config file '%s'." % self.CONFIG_FILE) + return + + # parse config file + cfp = ConfigParser.ConfigParser() + try: + cfp.readfp(cf) + except Exception, e: + logger.error("Content of config file '%s' is not valid. Correct it!\n%s\n" % (self.CONFIG_FILE, e)) + raise SystemExit, 1 + # communication config + if cfp.has_section('communication'): + try: + self.COMMUNICATION_PROTOCOL = cfp.get('communication','protocol') + except: + pass + try: + self.COMMUNICATION_PASSWORD = cfp.get('communication','password') + except: + pass + try: + self.COMMUNICATION_KEY = cfp.get('communication','key') + except: + pass + try: + self.COMMUNICATION_USER = cfp.get('communication','user') + except: + pass + # components config + if cfp.has_section('components'): + try: + self.COMPONENTS_BCFG2 = cfp.get('components', 'bcfg2') + self.COMPONENTS_BCFG2_STATIC = True + except: + pass + # server config + if cfp.has_section('server'): + try: + self.SERVER_GENERATORS = cfp.get('server','generators').replace(' ','').split(',') + except: + pass + try: + self.SERVER_REPOSITORY = cfp.get('server','repository') + except: + pass + try: + self.SERVER_STRUCTURES = cfp.get('server','structures').replace(' ','').split(',') + except: + pass + try: + self.SERVER_SVN = cfp.get('server','svn') + except: + pass + + return + + def default_config_file(self): + return '/etc/bcfg2.conf' + + def default_server_generators(self): + return ['SSHbase', 'Cfg', 'Pkgmgr', 'Rules'] + + def default_server_structures(self): + return ['Bundler', 'Base'] + + def default_server_repository(self): + return '/var/lib/bcfg2/' + + def default_communication_key(self): + return False + + def default_communication_password(self): + return 'password' + + def default_communication_protocol(self): + return 'xmlrpc/ssl' + + def default_communication_user(self): + return 'root' + + def default_components_bcfg2(self): + return (socket.gethostname(), 0) + + def default_components_bcfg2_static(self): + return False + + def default_sendmail_path(self): + return '/usr/sbin/sendmail' + + def default_server_svn(self): + return None + + + +settings = Settings() diff --git a/src/sbin/bcfg2 b/src/sbin/bcfg2 index a25bab65f..62f2e1775 100755 --- a/src/sbin/bcfg2 +++ b/src/sbin/bcfg2 @@ -78,11 +78,11 @@ class Client: 'setup': (('-C', '', "use given config file (default /etc/bcfg2.conf)"), False, False, '/etc/bcfg2.conf', False), 'server': (('-S', '', 'the server hostname to connect to'), - False, ('components', 'bcfg2'), 'https://localhost:6789', False), + False, ('components', 'bcfg2'), False, False), 'user': (('-u', '', 'the user to provide for authentication'), - False, ('communication', 'user'), 'root', False), + False, ('communication', 'user'), False, False), 'password': (('-x', '', 'the password to provide for authentication'), - False, ('communication', 'password'), 'password', False), + False, ('communication', 'password'), False, False), 'retries': (('-R', '', 'the number of times to retry network communication'), False, ('communication', 'retries'), '3', False), 'kevlar': (('-k', False, "run in kevlar (bulletproof) mode"), @@ -99,6 +99,10 @@ class Client: optparser = Bcfg2.Options.OptionParser('bcfg2', optinfo) self.setup = optparser.parse() + + # override default settings + settings.read_config_file(self.setup['setup']) + if getopt.getopt(sys.argv[1:], optparser.shortopt, optparser.longopt)[1]: print "Bcfg2 takes no arguments, only options" diff --git a/src/sbin/bcfg2-info b/src/sbin/bcfg2-info index f40ef3e60..6693efea2 100755 --- a/src/sbin/bcfg2-info +++ b/src/sbin/bcfg2-info @@ -6,6 +6,7 @@ import copy, logging, lxml.etree, sys, time, cmd import Bcfg2.Logging, Bcfg2.Server.Core, os import Bcfg2.Server.Plugins.Metadata, Bcfg2.Server.Plugin import Bcfg2.Options +from Bcfg2.Settings import settings logger = logging.getLogger('bcfg2-info') @@ -23,10 +24,10 @@ def printTabular(rows): print fstring % row class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): - def __init__(self, cfpath): + def __init__(self): cmd.Cmd.__init__(self) try: - Bcfg2.Server.Core.Core.__init__(self, {}, cfpath) + Bcfg2.Server.Core.Core.__init__(self) except Bcfg2.Server.Core.CoreInitError, msg: print "Core load failed because %s" % msg raise SystemExit(1) @@ -270,6 +271,9 @@ if __name__ == '__main__': optparser = Bcfg2.Options.OptionParser('bcfg2-info', optinfo) setup = optparser.parse() - loop = infoCore(setup['configfile']) + # override default settings + settings.read_config_file(setup['configfile']) + + loop = infoCore() loop.plugins['Metadata'].load_probedata() loop.do_loop() diff --git a/src/sbin/bcfg2-server b/src/sbin/bcfg2-server index e6a00efbc..554a5ae24 100755 --- a/src/sbin/bcfg2-server +++ b/src/sbin/bcfg2-server @@ -5,6 +5,7 @@ __revision__ = '$Revision$' import Bcfg2.Server.Plugins.Metadata +from Bcfg2.Settings import settings from Bcfg2.Server.Core import Core, CoreInitError from xmlrpclib import Fault from lxml.etree import XML, Element, tostring @@ -39,7 +40,7 @@ class Bcfg2Serv(Bcfg2.Component.Component): raise SetupError try: - self.Core = Core(setup, setup['configfile']) + self.Core = Core() except CoreInitError, msg: logger.critical("Fatal error: %s" % (msg)) raise SystemExit, 1 @@ -184,7 +185,7 @@ if __name__ == '__main__': 'daemon': (('-D', '', 'daemonize the server, storing PID'), False, False, False, False), 'configfile': (('-C', '', 'use this config file'), - False, False, '/etc/bcfg2.conf', False), + False, False, False, False), } SSETUP = Bcfg2.Options.OptionParser('bcfg2', OPTINFO).parse() @@ -195,6 +196,10 @@ if __name__ == '__main__': Bcfg2.Logging.setup_logging('bcfg2-server', level=level) if SSETUP['daemon']: Bcfg2.Daemon.daemonize(SSETUP['daemon']) + + # override default settings + settings.read_config_file(SSETUP['configfile']) + try: BSERV = Bcfg2Serv(SSETUP) except SetupError: -- cgit v1.2.3-1-g7c22