From 4261f7238e3b7eb169fcb0f672e7fdb86d722189 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Thu, 27 Jun 2013 10:31:47 -0400 Subject: Options: migrated generic database stuff to new parser --- src/lib/Bcfg2/Server/models.py | 115 ++++++++++++++++----------------- src/lib/Bcfg2/settings.py | 143 +++++++++++++++++++---------------------- 2 files changed, 123 insertions(+), 135 deletions(-) (limited to 'src/lib/Bcfg2') diff --git a/src/lib/Bcfg2/Server/models.py b/src/lib/Bcfg2/Server/models.py index 370854881..51cc835dc 100644 --- a/src/lib/Bcfg2/Server/models.py +++ b/src/lib/Bcfg2/Server/models.py @@ -1,44 +1,64 @@ """ Django database models for all plugins """ import sys -import copy import logging import Bcfg2.Options import Bcfg2.Server.Plugins from Bcfg2.Compat import walk_packages -from django.db import models LOGGER = logging.getLogger('Bcfg2.Server.models') MODELS = [] -def load_models(plugins=None, cfile='/etc/bcfg2.conf', quiet=True): +def _get_all_plugins(): + rv = [] + for submodule in walk_packages(path=Bcfg2.Server.Plugins.__path__, + prefix="Bcfg2.Server.Plugins."): + module = submodule[1].rsplit('.', 1)[-1] + if submodule[1] == "Bcfg2.Server.Plugins.%s" % module: + # we only include direct children of + # Bcfg2.Server.Plugins -- e.g., all_plugins should + # include Bcfg2.Server.Plugins.Cfg, but not + # Bcfg2.Server.Plugins.Cfg.CfgInfoXML + rv.append(module) + return rv + + +_ALL_PLUGINS = _get_all_plugins() + + +class _OptionContainer(object): + # we want to provide a different default plugin list -- + # namely, _all_ plugins, so that the database is guaranteed to + # work, even if /etc/bcfg2.conf isn't set up properly + options = [ + Bcfg2.Options.Option( + cf=('server', 'plugins'), type=Bcfg2.Options.Types.comma_list, + default=_ALL_PLUGINS, dest="models_plugins", + action=Bcfg2.Options.PluginsAction)] + + @staticmethod + def options_parsed_hook(): + # basic invocation to ensure that a default set of models is + # loaded, and thus that this module will always work. + load_models() + +Bcfg2.Options.get_parser().add_component(_OptionContainer) + + +def load_models(plugins=None): """ load models from plugins specified in the config """ + # this has to be imported after options are parsed, because Django + # finalizes its settings as soon as it's loaded, which means that + # if we import this before Bcfg2.settings has been populated, + # Django gets a null configuration, and subsequent updates to + # Bcfg2.settings won't help. + from django.db import models global MODELS - if plugins is None: - # we want to provide a different default plugin list -- - # namely, _all_ plugins, so that the database is guaranteed to - # work, even if /etc/bcfg2.conf isn't set up properly - plugin_opt = copy.deepcopy(Bcfg2.Options.SERVER_PLUGINS) - all_plugins = [] - for submodule in walk_packages(path=Bcfg2.Server.Plugins.__path__, - prefix="Bcfg2.Server.Plugins."): - module = submodule[1].rsplit('.', 1)[-1] - if submodule[1] == "Bcfg2.Server.Plugins.%s" % module: - # we only include direct children of - # Bcfg2.Server.Plugins -- e.g., all_plugins should - # include Bcfg2.Server.Plugins.Cfg, but not - # Bcfg2.Server.Plugins.Cfg.CfgInfoXML - all_plugins.append(module) - plugin_opt.default = all_plugins - - setup = Bcfg2.Options.get_option_parser() - setup.add_option("plugins", plugin_opt) - setup.add_option("configfile", Bcfg2.Options.CFILE) - setup.reparse(argv=[Bcfg2.Options.CFILE.cmd, cfile]) - plugins = setup['plugins'] + if not plugins: + plugins = Bcfg2.Options.setup.models_plugins if MODELS: # load_models() has been called once, so first unload all of @@ -49,45 +69,22 @@ def load_models(plugins=None, cfile='/etc/bcfg2.conf', quiet=True): delattr(sys.modules[__name__], model) MODELS = [] - for plugin in plugins: - try: - mod = getattr(__import__("Bcfg2.Server.Plugins.%s" % - plugin).Server.Plugins, plugin) - except ImportError: - try: - err = sys.exc_info()[1] - mod = __import__(plugin) - except: # pylint: disable=W0702 - if plugins != plugin_opt.default: - # only produce errors if the default plugin list - # was not used -- i.e., if the config file was set - # up. don't produce errors when trying to load - # all plugins, IOW. the error from the first - # attempt to import is probably more accurate than - # the second attempt. - LOGGER.error("Failed to load plugin %s: %s" % (plugin, - err)) - continue + for mod in plugins: for sym in dir(mod): obj = getattr(mod, sym) - if hasattr(obj, "__bases__") and models.Model in obj.__bases__: + if isinstance(obj, type) and issubclass(obj, models.Model): setattr(sys.modules[__name__], sym, obj) MODELS.append(sym) -# basic invocation to ensure that a default set of models is loaded, -# and thus that this module will always work. -load_models(quiet=True) - - -class InternalDatabaseVersion(models.Model): - """ Object that tell us to which version the database is """ - version = models.IntegerField() - updated = models.DateTimeField(auto_now_add=True) + class InternalDatabaseVersion(models.Model): + """ Object that tell us to which version the database is """ + version = models.IntegerField() + updated = models.DateTimeField(auto_now_add=True) - def __str__(self): - return "version %d updated the %s" % (self.version, + def __str__(self): + return "version %d updated %s" % (self.version, self.updated.isoformat()) - class Meta: # pylint: disable=C0111,W0232 - app_label = "reports" - get_latest_by = "version" + class Meta: # pylint: disable=C0111,W0232 + app_label = "reports" + get_latest_by = "version" diff --git a/src/lib/Bcfg2/settings.py b/src/lib/Bcfg2/settings.py index c06074845..a26330a79 100644 --- a/src/lib/Bcfg2/settings.py +++ b/src/lib/Bcfg2/settings.py @@ -1,7 +1,6 @@ """ Django settings for the Bcfg2 server """ import os -import sys import Bcfg2.Options try: @@ -17,7 +16,7 @@ try: except ImportError: HAS_SOUTH = False -DATABASES = dict() +DATABASES = dict(default=dict()) # Django < 1.2 compat DATABASE_ENGINE = None @@ -29,85 +28,13 @@ DATABASE_PORT = None TIME_ZONE = None -DEBUG = False -TEMPLATE_DEBUG = DEBUG +TEMPLATE_DEBUG = DEBUG = False ALLOWED_HOSTS = ['*'] MEDIA_URL = '/site_media/' - -def _default_config(): - """ get the default config file. returns /etc/bcfg2-web.conf, - UNLESS /etc/bcfg2.conf exists AND /etc/bcfg2-web.conf does not - exist. """ - setup = Bcfg2.Options.get_option_parser() - setup.add_option("configfile", Bcfg2.Options.CFILE) - setup.add_option("web_configfile", Bcfg2.Options.WEB_CFILE) - setup.reparse(argv=sys.argv[1:], do_getopt=False) - if (not os.path.exists(setup['web_configfile']) and - os.path.exists(setup['configfile'])): - return setup['configfile'] - else: - return setup['web_configfile'] - -DEFAULT_CONFIG = _default_config() - - -def read_config(cfile=DEFAULT_CONFIG, repo=None): - """ read the config file and set django settings based on it """ - # pylint: disable=W0602,W0603 - global DATABASE_ENGINE, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD, \ - DATABASE_HOST, DATABASE_PORT, DEBUG, TEMPLATE_DEBUG, TIME_ZONE, \ - MEDIA_URL - # pylint: enable=W0602,W0603 - - if not os.path.exists(cfile) and os.path.exists(DEFAULT_CONFIG): - print("%s does not exist, using %s for database configuration" % - (cfile, DEFAULT_CONFIG)) - cfile = DEFAULT_CONFIG - - # when setting a different config file, it has to be set in either - # sys.argv or in the OptionSet() constructor AS WELL AS the argv - # that's passed to setup.parse() - argv = [Bcfg2.Options.CFILE.cmd, cfile, - Bcfg2.Options.WEB_CFILE.cmd, cfile] - setup = Bcfg2.Options.get_option_parser() - setup.add_options(Bcfg2.Options.DATABASE_COMMON_OPTIONS) - setup.add_option("repo", Bcfg2.Options.SERVER_REPOSITORY) - setup.reparse(argv=argv) - - if repo is None: - repo = setup['repo'] - - DATABASES['default'] = \ - dict(ENGINE="django.db.backends.%s" % setup['db_engine'], - NAME=setup['db_name'], - USER=setup['db_user'], - PASSWORD=setup['db_password'], - HOST=setup['db_host'], - PORT=setup['db_port']) - - # dropping the version check. This was added in 1.1.2 - TIME_ZONE = setup['time_zone'] - - DEBUG = setup['django_debug'] - TEMPLATE_DEBUG = DEBUG - if DEBUG: - print("Warning: Setting web_debug to True causes extraordinary memory " - "leaks. Only use this setting if you know what you're doing.") - - if setup['web_prefix']: - MEDIA_URL = setup['web_prefix'].rstrip('/') + MEDIA_URL - else: - MEDIA_URL = '/site_media/' - -# initialize settings from /etc/bcfg2-web.conf or /etc/bcfg2.conf, or -# set up basic defaults. this lets manage.py work in all cases -read_config() - -ADMINS = (('Root', 'root')) -MANAGERS = ADMINS +MANAGERS = ADMINS = (('Root', 'root')) # Language code for this installation. All choices can be found here: # http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes @@ -189,3 +116,67 @@ TEMPLATE_CONTEXT_PROCESSORS = ( 'django.core.context_processors.media', 'django.core.context_processors.request' ) + + +def read_config(): + """ read the config file and set django settings based on it """ + global DEBUG, TEMPLATE_DEBUG, TIME_ZONE, MEDIA_URL # pylint: disable=W0603 + + DATABASES['default'] = \ + dict(ENGINE="django.db.backends.%s" % Bcfg2.Options.setup.db_engine, + NAME=Bcfg2.Options.setup.db_name, + USER=Bcfg2.Options.setup.db_user, + PASSWORD=Bcfg2.Options.setup.db_password, + HOST=Bcfg2.Options.setup.db_host, + PORT=Bcfg2.Options.setup.db_port) + + TIME_ZONE = Bcfg2.Options.setup.timezone + + TEMPLATE_DEBUG = DEBUG = Bcfg2.Options.setup.web_debug + if DEBUG: + print("Warning: Setting web_debug to True causes extraordinary memory " + "leaks. Only use this setting if you know what you're doing.") + + if Bcfg2.Options.setup.web_prefix: + MEDIA_URL = Bcfg2.Options.setup.web_prefix.rstrip('/') + MEDIA_URL + + +class _OptionContainer(object): + options = [ + Bcfg2.Options.Common.repository, + Bcfg2.Options.PathOption( + '-W', '--web-config', cf=('reporting', 'config'), + default="/etc/bcfg2-web.conf", + action=Bcfg2.Options.ConfigFileAction, + help='Web interface configuration file'), + Bcfg2.Options.Option( + cf=('database', 'engine'), default='sqlite3', + help='Database engine', dest='db_engine'), + Bcfg2.Options.Option( + cf=('database', 'name'), default='/etc/bcfg2.sqlite', + help="Database name", dest="db_name"), + Bcfg2.Options.Option( + cf=('database', 'user'), help='Database username', dest='db_user'), + Bcfg2.Options.Option( + cf=('database', 'password'), help='Database password', + dest='db_password'), + Bcfg2.Options.Option( + cf=('database', 'host'), help='Database host', dest='db_host'), + Bcfg2.Options.Option( + cf=('database', 'port'), help='Database port', dest='db_port'), + Bcfg2.Options.Option( + cf=('reporting', 'timezone'), help='Django timezone'), + Bcfg2.Options.BooleanOption( + cf=('reporting', 'web_debug'), help='Django debug'), + Bcfg2.Options.Option( + cf=('reporting', 'web_prefix'), help='Web prefix')] + + @staticmethod + def options_parsed_hook(): + """ initialize settings from /etc/bcfg2-web.conf or + /etc/bcfg2.conf, or set up basic defaults. this lets + manage.py work in all cases """ + read_config() + + +Bcfg2.Options.get_parser().add_component(_OptionContainer) -- cgit v1.2.3-1-g7c22