From a20a06edac1ed54982833dbc3c6798050feb64c0 Mon Sep 17 00:00:00 2001 From: Joshua Harlow Date: Thu, 15 Mar 2012 14:22:14 -0700 Subject: [PATCH] Initial attempt/work for personas --- conf/distros/ubuntu-oneiric.yaml | 13 +- conf/personas/devstack.sh.yaml | 31 ++++ devstack/cfg.py | 11 ++ devstack/cfg_helpers.py | 6 +- devstack/component.py | 112 ++++++------ devstack/components/db.py | 6 +- devstack/components/glance.py | 16 +- devstack/components/horizon.py | 29 ++- devstack/components/keystone.py | 36 ++-- devstack/components/keystone_client.py | 2 - devstack/components/melange.py | 24 ++- devstack/components/melange_client.py | 2 - devstack/components/nova.py | 146 +++++++-------- devstack/components/nova_client.py | 2 - devstack/components/novnc.py | 6 +- devstack/components/quantum.py | 18 +- devstack/components/quantum_client.py | 2 - devstack/components/rabbit.py | 2 - devstack/components/swift.py | 46 +++-- devstack/distro.py | 35 ++-- devstack/distros/oneiric.py | 2 +- devstack/env.py | 2 +- devstack/env_rc.py | 18 +- devstack/importer.py | 29 ++- devstack/libvirt.py | 15 +- devstack/opts.py | 32 ++-- devstack/progs/actions.py | 240 ++++++++++++------------- devstack/progs/common.py | 190 -------------------- devstack/settings.py | 34 +--- devstack/utils.py | 99 +--------- stack | 59 +++--- 31 files changed, 470 insertions(+), 795 deletions(-) create mode 100644 conf/personas/devstack.sh.yaml delete mode 100644 devstack/progs/common.py diff --git a/conf/distros/ubuntu-oneiric.yaml b/conf/distros/ubuntu-oneiric.yaml index 34b6c3bc..f35095a8 100644 --- a/conf/distros/ubuntu-oneiric.yaml +++ b/conf/distros/ubuntu-oneiric.yaml @@ -18,6 +18,8 @@ commands: status: ["service", "apache2", "status"] settings: conf-link-target: /etc/apache2/sites-enabled/000-default + + libvirt-daemon: 'libvirt-bin' mysql: start: ["service", "mysql", 'start'] @@ -31,7 +33,12 @@ commands: drop_db: ['mysql', '--user=%USER%', '--password=%PASSWORD%', '-e', 'DROP DATABASE IF EXISTS %DB%;'] grant_all: ["mysql", "--user=%USER%", "--password=%PASSWORD%", '-e', "\"GRANT ALL PRIVILEGES ON *.* TO '%USER%'@'%' IDENTIFIED BY '%PASSWORD%'; FLUSH PRIVILEGES;\""] - + iscsi: + start: ['service', 'tgt', 'start'] + stop: ['service', 'tgt', 'stop'] + restart: ['service', 'tgt', 'restart'] + status: ['service', 'tgt', 'status'] + components: db: @@ -435,7 +442,7 @@ components: removable: True version: 0.14.* - n-vnc: + no-vnc: install: devstack.components.novnc:NoVNCInstaller uninstall: devstack.components.novnc:NoVNCUninstaller start: devstack.components.novnc:NoVNCRuntime @@ -664,7 +671,7 @@ components: removable: True version: 1.12* - rabbit: + rabbit-mq: install: devstack.components.rabbit:RabbitInstaller uninstall: devstack.components.rabbit:RabbitUninstaller start: devstack.components.rabbit:RabbitRuntime diff --git a/conf/personas/devstack.sh.yaml b/conf/personas/devstack.sh.yaml new file mode 100644 index 00000000..7ed3ba0a --- /dev/null +++ b/conf/personas/devstack.sh.yaml @@ -0,0 +1,31 @@ +--- +created_on: Wed, 14 Mar 2012 17:28:24 -0700 +description: Devstack.sh matching component installation (as of the above date). +supports: +- rhel-6 +- ubuntu-oneiric +- fedora-16 +components: +- db +- rabbit-mq +- keystone-client +- keystone +- glance +- nova +- no-vnc +- quantum-client +- nova-client +- horizon +subsystems: + glance: + - api + - reg + nova: + - api + - cauth + - cert + - cpu + - net + - sched + - vol + - xvnc diff --git a/devstack/cfg.py b/devstack/cfg.py index d75c0efe..f7f4e1be 100644 --- a/devstack/cfg.py +++ b/devstack/cfg.py @@ -22,6 +22,7 @@ from devstack import date from devstack import env from devstack import exceptions as excp from devstack import log as logging +from devstack import settings from devstack import shell as sh from devstack import utils @@ -31,6 +32,16 @@ SUB_MATCH = re.compile(r"(?:\$\(([\w\d]+):([\w\d]+))\)") CACHE_MSG = "(value will now be internally cached)" +def get_config(cfg_fn=None, cfg_cls=None): + if not cfg_fn: + cfg_fn = sh.canon_path(settings.STACK_CONFIG_LOCATION) + if not cfg_cls: + cfg_cls = StackConfigParser + config_instance = cfg_cls() + config_instance.read(cfg_fn) + return config_instance + + class IgnoreMissingConfigParser(ConfigParser.RawConfigParser): DEF_INT = 0 DEF_FLOAT = 0.0 diff --git a/devstack/cfg_helpers.py b/devstack/cfg_helpers.py index cd64cb61..eddab6dc 100644 --- a/devstack/cfg_helpers.py +++ b/devstack/cfg_helpers.py @@ -32,12 +32,10 @@ def make_id(section, option): def fetch_run_type(config): run_type = config.getdefaulted("default", "run_type", settings.RUN_TYPE_DEF) - run_type = run_type.upper() - return run_type + return run_type.upper() def fetch_dbdsn(config, pw_gen, dbname=''): - #check the dsn cache user = config.get("db", "sql_user") host = config.get("db", "sql_host") port = config.get("db", "port") @@ -65,5 +63,5 @@ def fetch_dbdsn(config, pw_gen, dbname=''): dsn += "/" + dbname else: dsn += "/" - LOG.debug("For database [%s] fetched dsn [%s]" % (dbname, dsn)) + LOG.audit("For database [%s] fetched dsn [%s]" % (dbname, dsn)) return dsn diff --git a/devstack/component.py b/devstack/component.py index c2f96ff6..2e7809e2 100644 --- a/devstack/component.py +++ b/devstack/component.py @@ -53,37 +53,40 @@ BASE_LINK_DIR = "/etc" class ComponentBase(object): - def __init__(self, component_name, runner, - root_dir, component_options, - instances=None, - **kwds): - self.component_name = component_name + def __init__(self, + subsystems, + runner, + component_dir, + all_instances, + name, + *args, + **kargs): + + # Required vars + self.subsystems = subsystems + self.instances = all_instances # The runner has a reference to us, so use a weakref here to # avoid breaking garbage collection. self.runner = weakref.proxy(runner) - self.root = root_dir - self.component_opts = component_options or {} - self.instances = instances or {} - # Parts of the global runner context that we use self.cfg = runner.cfg self.pw_gen = runner.pw_gen self.packager = runner.pkg_manager self.distro = runner.distro - - self.component_root = sh.joinpths(self.root, component_name) - self.tracedir = sh.joinpths(self.component_root, + + # What this component is called + self.component_name = name + + # Required component directories + self.component_dir = component_dir + self.trace_dir = sh.joinpths(self.component_dir, settings.COMPONENT_TRACE_DIR) - self.appdir = sh.joinpths(self.component_root, + self.app_dir = sh.joinpths(self.component_dir, settings.COMPONENT_APP_DIR) - self.cfgdir = sh.joinpths(self.component_root, + self.cfg_dir = sh.joinpths(self.component_dir, settings.COMPONENT_CONFIG_DIR) - self.kargs = kwds - - def get_dependencies(self): - return self.runner.distro.components[self.component_name].get('dependencies', [])[:] def verify(self): pass @@ -92,26 +95,25 @@ class ComponentBase(object): pass def is_started(self): - reader = tr.TraceReader(tr.trace_fn(self.tracedir, tr.START_TRACE)) + reader = tr.TraceReader(tr.trace_fn(self.trace_dir, tr.START_TRACE)) return reader.exists() def is_installed(self): - return tr.TraceReader(tr.trace_fn(self.tracedir, tr.IN_TRACE)).exists() + return tr.TraceReader(tr.trace_fn(self.trace_dir, tr.IN_TRACE)).exists() class PkgInstallComponent(ComponentBase): - def __init__(self, component_name, **kargs): - ComponentBase.__init__(self, component_name, **kargs) - self.tracewriter = tr.TraceWriter(tr.trace_fn(self.tracedir, - tr.IN_TRACE) - ) + def __init__(self, *args, **kargs): + ComponentBase.__init__(self, *args, **kargs) + self.tracewriter = tr.TraceWriter(tr.trace_fn(self.trace_dir, + tr.IN_TRACE)) def _get_download_locations(self): return list() def download(self): locations = self._get_download_locations() - base_dir = self.appdir + base_dir = self.app_dir for location_info in locations: uri_tuple = location_info["uri"] branch_tuple = location_info.get("branch") @@ -164,7 +166,7 @@ class PkgInstallComponent(ComponentBase): else: LOG.info('No packages to install for %s', self.component_name) - return self.tracedir + return self.trace_dir def pre_install(self): pkgs = self.component_opts.get('packages', []) @@ -185,7 +187,7 @@ class PkgInstallComponent(ComponentBase): return contents def _get_target_config_name(self, config_fn): - return sh.joinpths(self.cfgdir, config_fn) + return sh.joinpths(self.cfg_dir, config_fn) def _get_source_config(self, config_fn): return utils.load_template(self.component_name, config_fn) @@ -246,12 +248,12 @@ class PkgInstallComponent(ComponentBase): class PythonInstallComponent(PkgInstallComponent): - def __init__(self, component_name, *args, **kargs): - PkgInstallComponent.__init__(self, component_name, *args, **kargs) + def __init__(self, *args, **kargs): + PkgInstallComponent.__init__(self, *args, **kargs) def _get_python_directories(self): py_dirs = dict() - py_dirs[self.component_name] = self.appdir + py_dirs[self.component_name] = self.app_dir return py_dirs def _install_pips(self): @@ -273,7 +275,7 @@ class PythonInstallComponent(PkgInstallComponent): LOG.info("Setting up %s python directories (%s)", len(pydirs), pydirs) for (name, wkdir) in pydirs.items(): - working_dir = wkdir or self.appdir + working_dir = wkdir or self.app_dir #ensure working dir is there self.tracewriter.dirs_made(*sh.mkdirslist(working_dir)) #do this before write just incase it craps out half way through @@ -283,7 +285,7 @@ class PythonInstallComponent(PkgInstallComponent): cwd=working_dir, run_as_root=True) py_trace_name = "%s-%s" % (tr.PY_TRACE, name) - py_writer = tr.TraceWriter(tr.trace_fn(self.tracedir, + py_writer = tr.TraceWriter(tr.trace_fn(self.trace_dir, py_trace_name)) py_writer.trace("CMD", " ".join(PY_INSTALL)) py_writer.trace("STDOUT", stdout) @@ -301,11 +303,11 @@ class PythonInstallComponent(PkgInstallComponent): class PkgUninstallComponent(ComponentBase): - def __init__(self, component_name, keep_old=None, **kargs): - ComponentBase.__init__(self, component_name, **kargs) - self.tracereader = tr.TraceReader(tr.trace_fn(self.tracedir, + def __init__(self, *args, **kargs): + ComponentBase.__init__(self, *args, **kargs) + self.tracereader = tr.TraceReader(tr.trace_fn(self.trace_dir, tr.IN_TRACE)) - self.keep_old = keep_old + self.keep_old = kargs.get('keep_old') def unconfigure(self): if not self.keep_old: @@ -321,7 +323,7 @@ class PkgUninstallComponent(ComponentBase): if RUNNER_CLS_MAPPING: LOG.info("Unconfiguring %s runners.", len(RUNNER_CLS_MAPPING)) for (_, cls) in RUNNER_CLS_MAPPING.items(): - instance = cls(self.cfg, self.component_name, self.tracedir) + instance = cls(self.cfg, self.component_name, self.trace_dir) instance.unconfigure() def _unconfigure_links(self): @@ -386,8 +388,8 @@ class PkgUninstallComponent(ComponentBase): class PythonUninstallComponent(PkgUninstallComponent): - def __init__(self, component_name, *args, **kargs): - PkgUninstallComponent.__init__(self, component_name, *args, **kargs) + def __init__(self, *args, **kargs): + PkgUninstallComponent.__init__(self, *args, **kargs) def uninstall(self): self._uninstall_python() @@ -409,10 +411,10 @@ class PythonUninstallComponent(PkgUninstallComponent): class ProgramRuntime(ComponentBase): - def __init__(self, component_name, **kargs): - ComponentBase.__init__(self, component_name, **kargs) - self.tracewriter = tr.TraceWriter(tr.trace_fn(self.tracedir, tr.START_TRACE)) - self.tracereader = tr.TraceReader(tr.trace_fn(self.tracedir, tr.START_TRACE)) + def __init__(self, *args, **kargs): + ComponentBase.__init__(self, *args, **kargs) + self.tracewriter = tr.TraceWriter(tr.trace_fn(self.trace_dir, tr.START_TRACE)) + self.tracereader = tr.TraceReader(tr.trace_fn(self.trace_dir, tr.START_TRACE)) def _get_apps_to_start(self): return list() @@ -422,7 +424,7 @@ class ProgramRuntime(ComponentBase): def _get_param_map(self, app_name): return { - 'ROOT': self.appdir, + 'ROOT': self.app_dir, } def pre_start(self): @@ -435,12 +437,12 @@ class ProgramRuntime(ComponentBase): # First make a pass and make sure all runtime (e.g. upstart) # config files are in place.... cls = RUNNER_CLS_MAPPING[cfg_helpers.fetch_run_type(self.cfg)] - instance = cls(self.cfg, self.component_name, self.tracedir) + instance = cls(self.cfg, self.component_name, self.trace_dir) tot_am = 0 for app_info in self._get_apps_to_start(): app_name = app_info["name"] app_pth = app_info.get("path", app_name) - app_dir = app_info.get("app_dir", self.appdir) + app_dir = app_info.get("app_dir", self.app_dir) # Adjust the program options now that we have real locations program_opts = utils.param_replace_list( self._get_app_options(app_name), @@ -458,12 +460,12 @@ class ProgramRuntime(ComponentBase): def start(self): # Select how we are going to start it cls = RUNNER_CLS_MAPPING[cfg_helpers.fetch_run_type(self.cfg)] - instance = cls(self.cfg, self.component_name, self.tracedir) + instance = cls(self.cfg, self.component_name, self.trace_dir) am_started = 0 for app_info in self._get_apps_to_start(): app_name = app_info["name"] app_pth = app_info.get("path", app_name) - app_dir = app_info.get("app_dir", self.appdir) + app_dir = app_info.get("app_dir", self.app_dir) # Adjust the program options now that we have real locations program_opts = utils.param_replace_list( self._get_app_options(app_name), @@ -500,7 +502,7 @@ class ProgramRuntime(ComponentBase): else: killer = killcls(self.cfg, self.component_name, - self.tracedir, + self.trace_dir, ) killer_instances[killcls] = killer to_kill.append((app_name, killer)) @@ -526,14 +528,14 @@ class ProgramRuntime(ComponentBase): class PythonRuntime(ProgramRuntime): - def __init__(self, component_name, *args, **kargs): - ProgramRuntime.__init__(self, component_name, *args, **kargs) + def __init__(self, *args, **kargs): + ProgramRuntime.__init__(self, *args, **kargs) class EmptyRuntime(ComponentBase): - def __init__(self, component_name, **kargs): - ComponentBase.__init__(self, component_name, **kargs) - self.tracereader = tr.TraceReader(tr.trace_fn(self.tracedir, tr.IN_TRACE)) + def __init__(self, *args, **kargs): + ComponentBase.__init__(self, *args, **kargs) + self.tracereader = tr.TraceReader(tr.trace_fn(self.trace_dir, tr.IN_TRACE)) def configure(self): return 0 diff --git a/devstack/components/db.py b/devstack/components/db.py index 93929392..24ad2ed1 100644 --- a/devstack/components/db.py +++ b/devstack/components/db.py @@ -21,8 +21,6 @@ from devstack import settings from devstack import shell as sh from devstack import utils -#id -TYPE = settings.DB LOG = logging.getLogger("devstack.components.db") #used for special setups @@ -239,7 +237,7 @@ class DBRuntime(comp.EmptyRuntime): def drop_db(cfg, pw_gen, distro, dbname): dbtype = cfg.get("db", "type") - dbactions = distro.commands[dbtype] + dbactions = distro.get_command(dbtype) if dbactions and dbactions.get('drop_db'): dropcmd = dbactions.get('drop_db') params = dict() @@ -259,7 +257,7 @@ def drop_db(cfg, pw_gen, distro, dbname): def create_db(cfg, pw_gen, distro, dbname): dbtype = cfg.get("db", "type") - dbactions = distro.commands[dbtype] + dbactions = distro.get_command(dbtype) if dbactions and dbactions.get('create_db'): createcmd = dbactions.get('create_db') params = dict() diff --git a/devstack/components/glance.py b/devstack/components/glance.py index 4b532ba2..73b1876b 100644 --- a/devstack/components/glance.py +++ b/devstack/components/glance.py @@ -28,8 +28,6 @@ from devstack.components import keystone from devstack.image import creator -#id -TYPE = settings.GLANCE LOG = logging.getLogger("devstack.components.glance") #config files/sections @@ -82,13 +80,13 @@ BIN_DIR = 'bin' class GlanceUninstaller(comp.PythonUninstallComponent): def __init__(self, *args, **kargs): comp.PythonUninstallComponent.__init__(self, *args, **kargs) - self.cfgdir = sh.joinpths(self.appdir, CONFIG_DIR) + self.cfg_dir = sh.joinpths(self.app_dir, CONFIG_DIR) class GlanceInstaller(comp.PythonInstallComponent): def __init__(self, *args, **kargs): comp.PythonInstallComponent.__init__(self, *args, **kargs) - self.cfgdir = sh.joinpths(self.appdir, CONFIG_DIR) + self.cfg_dir = sh.joinpths(self.app_dir, CONFIG_DIR) def _get_download_locations(self): places = list() @@ -112,11 +110,11 @@ class GlanceInstaller(comp.PythonInstallComponent): def _get_source_config(self, config_fn): if config_fn == POLICY_JSON: - fn = sh.joinpths(self.cfgdir, POLICY_JSON) + fn = sh.joinpths(self.cfg_dir, POLICY_JSON) contents = sh.load_file(fn) return (fn, contents) elif config_fn == LOGGING_CONF: - fn = sh.joinpths(self.cfgdir, LOGGING_SOURCE_FN) + fn = sh.joinpths(self.cfg_dir, LOGGING_SOURCE_FN) contents = sh.load_file(fn) return (fn, contents) return comp.PythonInstallComponent._get_source_config(self, config_fn) @@ -171,7 +169,7 @@ class GlanceInstaller(comp.PythonInstallComponent): #this dict will be used to fill in the configuration #params with actual values mp = dict() - mp['DEST'] = self.appdir + mp['DEST'] = self.app_dir mp['SYSLOG'] = self.cfg.getboolean("default", "syslog") mp['SQL_CONN'] = cfg_helpers.fetch_dbdsn(self.cfg, self.pw_gen, DB_NAME) mp['SERVICE_HOST'] = self.cfg.get('host', 'ip') @@ -183,11 +181,11 @@ class GlanceInstaller(comp.PythonInstallComponent): class GlanceRuntime(comp.PythonRuntime): def __init__(self, *args, **kargs): comp.PythonRuntime.__init__(self, *args, **kargs) - self.cfgdir = sh.joinpths(self.appdir, CONFIG_DIR) + self.cfg_dir = sh.joinpths(self.app_dir, CONFIG_DIR) def _get_apps_to_start(self): apps = [{'name': app_name, - 'path': sh.joinpths(self.appdir, BIN_DIR, app_name), + 'path': sh.joinpths(self.app_dir, BIN_DIR, app_name), } for app_name in APP_OPTIONS.keys() ] diff --git a/devstack/components/horizon.py b/devstack/components/horizon.py index f6fc933c..0aadb231 100644 --- a/devstack/components/horizon.py +++ b/devstack/components/horizon.py @@ -21,8 +21,6 @@ from devstack import settings from devstack import shell as sh from devstack import utils -#id -TYPE = settings.HORIZON LOG = logging.getLogger("devstack.components.horizon") #actual dir names @@ -52,11 +50,12 @@ APACHE_ACCESS_LOG_FN = "access.log" APACHE_DEF_PORT = 80 #TODO: maybe this should be a subclass that handles these differences -APACHE_FIXUPS = { - 'SOCKET_CONF': "/etc/httpd/conf.d/wsgi-socket-prefix.conf", - 'HTTPD_CONF': '/etc/httpd/conf/httpd.conf', -} -APACHE_FIXUPS_DISTROS = [settings.RHEL6, settings.FEDORA16] +# APACHE_FIXUPS = { +# 'SOCKET_CONF': "/etc/httpd/conf.d/wsgi-socket-prefix.conf", +# 'HTTPD_CONF': '/etc/httpd/conf/httpd.conf', +# } +# APACHE_FIXUPS_DISTROS = [settings.RHEL6, settings.FEDORA16] +APACHE_FIXUPS_DISTROS = [] #for when quantum client is not need we need some fake files so python doesn't croak FAKE_QUANTUM_FILES = ['__init__.py', 'client.py'] @@ -76,9 +75,9 @@ class HorizonUninstaller(comp.PythonUninstallComponent): class HorizonInstaller(comp.PythonInstallComponent): def __init__(self, *args, **kargs): comp.PythonInstallComponent.__init__(self, *args, **kargs) - self.horizon_dir = sh.joinpths(self.appdir, ROOT_HORIZON) - self.dash_dir = sh.joinpths(self.appdir, ROOT_DASH) - self.log_dir = sh.joinpths(self.component_root, LOGS_DIR) + self.horizon_dir = sh.joinpths(self.app_dir, ROOT_HORIZON) + self.dash_dir = sh.joinpths(self.app_dir, ROOT_DASH) + self.log_dir = sh.joinpths(self.component_dir, LOGS_DIR) def _get_download_locations(self): places = list() @@ -98,7 +97,7 @@ class HorizonInstaller(comp.PythonInstallComponent): if utils.service_enabled(settings.QUANTUM_CLIENT, self.instances, False): #TODO remove this junk, blah, puke that we have to do this qc = self.instances[settings.QUANTUM_CLIENT] - src_pth = sh.joinpths(qc.appdir, 'quantum') + src_pth = sh.joinpths(qc.app_dir, 'quantum') tgt_dir = sh.joinpths(self.dash_dir, 'quantum') links[src_pth] = tgt_dir return links @@ -126,13 +125,13 @@ class HorizonInstaller(comp.PythonInstallComponent): def _setup_blackhole(self): #create an empty directory that apache uses as docroot - self.tracewriter.dirs_made(*sh.mkdirslist(sh.joinpths(self.appdir, BLACKHOLE_DIR))) + self.tracewriter.dirs_made(*sh.mkdirslist(sh.joinpths(self.app_dir, BLACKHOLE_DIR))) def _sync_db(self): #Initialize the horizon database (it stores sessions and notices shown to users). #The user system is external (keystone). LOG.info("Initializing the horizon database.") - sh.execute(*DB_SYNC_CMD, cwd=self.appdir) + sh.execute(*DB_SYNC_CMD, cwd=self.app_dir) def _ensure_db_access(self): # ../openstack-dashboard/local needs to be writeable by the runtime user @@ -208,10 +207,10 @@ class HorizonInstaller(comp.PythonInstallComponent): mp['ACCESS_LOG'] = sh.joinpths(self.log_dir, APACHE_ACCESS_LOG_FN) mp['ERROR_LOG'] = sh.joinpths(self.log_dir, APACHE_ERROR_LOG_FN) mp['GROUP'] = group - mp['HORIZON_DIR'] = self.appdir + mp['HORIZON_DIR'] = self.app_dir mp['HORIZON_PORT'] = self.cfg.getdefaulted('horizon', 'port', APACHE_DEF_PORT) mp['USER'] = user - mp['VPN_DIR'] = sh.joinpths(self.appdir, "vpn") + mp['VPN_DIR'] = sh.joinpths(self.app_dir, "vpn") else: mp['OPENSTACK_HOST'] = self.cfg.get('host', 'ip') return mp diff --git a/devstack/components/keystone.py b/devstack/components/keystone.py index 2734931f..d42894aa 100644 --- a/devstack/components/keystone.py +++ b/devstack/components/keystone.py @@ -28,8 +28,6 @@ from devstack import utils from devstack.components import db -#id -TYPE = settings.KEYSTONE LOG = logging.getLogger("devstack.components.keystone") #this db will be dropped then created @@ -86,15 +84,15 @@ QUANTUM_TEMPL_ADDS = ['catalog.RegionOne.network.publicURL = http://%SERVICE_HOS class KeystoneUninstaller(comp.PythonUninstallComponent): def __init__(self, *args, **kargs): comp.PythonUninstallComponent.__init__(self, *args, **kargs) - self.cfgdir = sh.joinpths(self.appdir, CONFIG_DIR) - self.bindir = sh.joinpths(self.appdir, BIN_DIR) + self.cfg_dir = sh.joinpths(self.app_dir, CONFIG_DIR) + self.bin_dir = sh.joinpths(self.app_dir, BIN_DIR) class KeystoneInstaller(comp.PythonInstallComponent): def __init__(self, *args, **kargs): comp.PythonInstallComponent.__init__(self, *args, **kargs) - self.cfgdir = sh.joinpths(self.appdir, CONFIG_DIR) - self.bindir = sh.joinpths(self.appdir, BIN_DIR) + self.cfg_dir = sh.joinpths(self.app_dir, CONFIG_DIR) + self.bin_dir = sh.joinpths(self.app_dir, BIN_DIR) def _get_download_locations(self): places = list() @@ -113,9 +111,9 @@ class KeystoneInstaller(comp.PythonInstallComponent): def _sync_db(self): LOG.info("Syncing keystone to database named %s.", DB_NAME) params = dict() - params['BINDIR'] = self.bindir + params['BINDIR'] = self.bin_dir cmds = [{'cmd': SYNC_DB_CMD}] - utils.execute_template(*cmds, cwd=self.bindir, params=params) + utils.execute_template(*cmds, cwd=self.bin_dir, params=params) def _get_config_files(self): return list(CONFIGS) @@ -130,7 +128,7 @@ class KeystoneInstaller(comp.PythonInstallComponent): (_, contents) = utils.load_template(self.component_name, MANAGE_DATA_CONF) params = self._get_param_map(MANAGE_DATA_CONF) contents = utils.param_replace(contents, params, True) - tgt_fn = sh.joinpths(self.bindir, MANAGE_DATA_CONF) + tgt_fn = sh.joinpths(self.bin_dir, MANAGE_DATA_CONF) sh.write_file(tgt_fn, contents) sh.chmod(tgt_fn, 0755) self.tracewriter.file_touched(tgt_fn) @@ -175,7 +173,7 @@ class KeystoneInstaller(comp.PythonInstallComponent): def _get_source_config(self, config_fn): if config_fn == LOGGING_CONF: - fn = sh.joinpths(self.cfgdir, LOGGING_SOURCE_FN) + fn = sh.joinpths(self.cfg_dir, LOGGING_SOURCE_FN) contents = sh.load_file(fn) return (fn, contents) return comp.PythonInstallComponent._get_source_config(self, config_fn) @@ -188,12 +186,12 @@ class KeystoneInstaller(comp.PythonInstallComponent): #params with actual values mp = dict() mp['SERVICE_HOST'] = self.cfg.get('host', 'ip') - mp['DEST'] = self.appdir - mp['BIN_DIR'] = self.bindir - mp['CONFIG_FILE'] = sh.joinpths(self.cfgdir, ROOT_CONF) + mp['DEST'] = self.app_dir + mp['BIN_DIR'] = self.bin_dir + mp['CONFIG_FILE'] = sh.joinpths(self.cfg_dir, ROOT_CONF) if config_fn == ROOT_CONF: mp['SQL_CONN'] = cfg_helpers.fetch_dbdsn(self.cfg, self.pw_gen, DB_NAME) - mp['KEYSTONE_DIR'] = self.appdir + mp['KEYSTONE_DIR'] = self.app_dir mp.update(get_shared_params(self.cfg, self.pw_gen)) elif config_fn == MANAGE_DATA_CONF: mp.update(get_shared_params(self.cfg, self.pw_gen)) @@ -203,11 +201,11 @@ class KeystoneInstaller(comp.PythonInstallComponent): class KeystoneRuntime(comp.PythonRuntime): def __init__(self, *args, **kargs): comp.PythonRuntime.__init__(self, *args, **kargs) - self.cfgdir = sh.joinpths(self.appdir, CONFIG_DIR) - self.bindir = sh.joinpths(self.appdir, BIN_DIR) + self.cfg_dir = sh.joinpths(self.app_dir, CONFIG_DIR) + self.bin_dir = sh.joinpths(self.app_dir, BIN_DIR) def post_start(self): - tgt_fn = sh.joinpths(self.bindir, MANAGE_DATA_CONF) + tgt_fn = sh.joinpths(self.bin_dir, MANAGE_DATA_CONF) if sh.isfile(tgt_fn): #still there, run it #these environment additions are important @@ -216,7 +214,7 @@ class KeystoneRuntime(comp.PythonRuntime): sh.sleep(WAIT_ONLINE_TO) env = dict() env['ENABLED_SERVICES'] = ",".join(self.instances.keys()) - env['BIN_DIR'] = self.bindir + env['BIN_DIR'] = self.bin_dir setup_cmd = MANAGE_CMD_ROOT + [tgt_fn] LOG.info("Running (%s) command to initialize keystone." % (" ".join(setup_cmd))) sh.execute(*setup_cmd, env_overrides=env, run_as_root=False) @@ -228,7 +226,7 @@ class KeystoneRuntime(comp.PythonRuntime): for app_name in APP_OPTIONS.keys(): apps.append({ 'name': app_name, - 'path': sh.joinpths(self.bindir, app_name), + 'path': sh.joinpths(self.bin_dir, app_name), }) return apps diff --git a/devstack/components/keystone_client.py b/devstack/components/keystone_client.py index bf4bbb43..040b6f89 100644 --- a/devstack/components/keystone_client.py +++ b/devstack/components/keystone_client.py @@ -18,8 +18,6 @@ from devstack import component as comp from devstack import log as logging from devstack import settings -#id -TYPE = settings.KEYSTONE_CLIENT LOG = logging.getLogger("devstack.components.keystone_client") diff --git a/devstack/components/melange.py b/devstack/components/melange.py index 7d6c5f6e..688fad99 100644 --- a/devstack/components/melange.py +++ b/devstack/components/melange.py @@ -26,8 +26,6 @@ from devstack import utils from devstack.components import db -#id -TYPE = settings.MELANGE LOG = logging.getLogger("devstack.components.melange") #this db will be dropped then created @@ -47,7 +45,7 @@ DEF_CIDR_RANGE = 'FE-EE-DD-00-00-00/24' #how we sync melange with the db DB_SYNC_CMD = [ - {'cmd': ['%BINDIR%/melange-manage', '--config-file=%CFG_FILE%', 'db_sync']}, + {'cmd': ['%BIN_DIR%/melange-manage', '--config-file=%CFG_FILE%', 'db_sync']}, ] #??? @@ -73,8 +71,8 @@ class MelangeUninstaller(comp.PythonUninstallComponent): class MelangeInstaller(comp.PythonInstallComponent): def __init__(self, *args, **kargs): comp.PythonInstallComponent.__init__(self, *args, **kargs) - self.bindir = sh.joinpths(self.appdir, BIN_DIR) - self.cfgdir = sh.joinpths(self.appdir, *CFG_LOC) + self.bin_dir = sh.joinpths(self.app_dir, BIN_DIR) + self.cfg_dir = sh.joinpths(self.app_dir, *CFG_LOC) def _get_download_locations(self): places = list() @@ -97,8 +95,8 @@ class MelangeInstaller(comp.PythonInstallComponent): def _sync_db(self): LOG.info("Syncing the database with melange.") mp = dict() - mp['BINDIR'] = self.bindir - mp['CFG_FILE'] = sh.joinpths(self.cfgdir, ROOT_CONF_REAL_NAME) + mp['BIN_DIR'] = self.bin_dir + mp['CFG_FILE'] = sh.joinpths(self.cfg_dir, ROOT_CONF_REAL_NAME) utils.execute_template(*DB_SYNC_CMD, params=mp) def _get_config_files(self): @@ -123,7 +121,7 @@ class MelangeInstaller(comp.PythonInstallComponent): def _get_source_config(self, config_fn): if config_fn == ROOT_CONF: - srcfn = sh.joinpths(self.cfgdir, config_fn) + srcfn = sh.joinpths(self.cfg_dir, config_fn) contents = sh.load_file(srcfn) return (srcfn, contents) else: @@ -131,7 +129,7 @@ class MelangeInstaller(comp.PythonInstallComponent): def _get_target_config_name(self, config_fn): if config_fn == ROOT_CONF: - return sh.joinpths(self.cfgdir, ROOT_CONF_REAL_NAME) + return sh.joinpths(self.cfg_dir, ROOT_CONF_REAL_NAME) else: return comp.PythonInstallComponent._get_target_config_name(self, config_fn) @@ -139,15 +137,15 @@ class MelangeInstaller(comp.PythonInstallComponent): class MelangeRuntime(comp.PythonRuntime): def __init__(self, *args, **kargs): comp.PythonRuntime.__init__(self, *args, **kargs) - self.bindir = sh.joinpths(self.appdir, BIN_DIR) - self.cfgdir = sh.joinpths(self.appdir, *CFG_LOC) + self.bin_dir = sh.joinpths(self.app_dir, BIN_DIR) + self.cfg_dir = sh.joinpths(self.app_dir, *CFG_LOC) def _get_apps_to_start(self): apps = list() for app_name in APP_OPTIONS.keys(): apps.append({ 'name': app_name, - 'path': sh.joinpths(self.bindir, app_name), + 'path': sh.joinpths(self.bin_dir, app_name), }) return apps @@ -156,7 +154,7 @@ class MelangeRuntime(comp.PythonRuntime): def _get_param_map(self, app_name): pmap = comp.PythonRuntime._get_param_map(self, app_name) - pmap['CFG_FILE'] = sh.joinpths(self.cfgdir, ROOT_CONF_REAL_NAME) + pmap['CFG_FILE'] = sh.joinpths(self.cfg_dir, ROOT_CONF_REAL_NAME) return pmap def post_start(self): diff --git a/devstack/components/melange_client.py b/devstack/components/melange_client.py index ee6ad7f1..07864c4a 100644 --- a/devstack/components/melange_client.py +++ b/devstack/components/melange_client.py @@ -18,8 +18,6 @@ from devstack import component as comp from devstack import log as logging from devstack import settings -#id -TYPE = settings.MELANGE_CLIENT LOG = logging.getLogger("devstack.components.melange_client") diff --git a/devstack/components/nova.py b/devstack/components/nova.py index e36e6068..8fa9bfef 100644 --- a/devstack/components/nova.py +++ b/devstack/components/nova.py @@ -29,17 +29,15 @@ from devstack import utils from devstack.components import db from devstack.components import keystone -#id -TYPE = settings.NOVA LOG = logging.getLogger('devstack.components.nova') -#special generated conf +# Special generated conf API_CONF = 'nova.conf' -#how we reference some config files (in applications) +# How we reference some config files (in applications) CFG_FILE_OPT = '--config-file' -#normal conf +# Normal conf PASTE_CONF = 'nova-api-paste.ini' PASTE_SOURCE_FN = 'api-paste.ini' POLICY_CONF = 'policy.json' @@ -48,19 +46,19 @@ LOGGING_CONF = "logging.conf" CONFIGS = [PASTE_CONF, POLICY_CONF, LOGGING_CONF] ADJUST_CONFIGS = [PASTE_CONF] -#this is a special conf +# This is a special conf NET_INIT_CONF = 'nova-network-init.sh' NET_INIT_CMD_ROOT = [sh.joinpths("/", "bin", 'bash')] -#this db will be dropped then created +# This db will be dropped then created DB_NAME = 'nova' -#this makes the database be in sync with nova +# This makes the database be in sync with nova DB_SYNC_CMD = [ - {'cmd': ['%BINDIR%/nova-manage', CFG_FILE_OPT, '%CFGFILE%', 'db', 'sync']}, + {'cmd': ['%BIN_DIR%/nova-manage', CFG_FILE_OPT, '%CFGFILE%', 'db', 'sync']}, ] -#these are used for nova volumens +# These are used for nova volumes VG_CHECK_CMD = [ {'cmd': ['vgs', '%VOLUME_GROUP%'], 'run_as_root': True} @@ -82,21 +80,6 @@ VG_LVREMOVE_CMD = [ 'run_as_root': True} ] -# iscsi restart commands -RESTART_TGT_CMD = { - settings.UBUNTU11: [ - {'cmd': ['stop', 'tgt'], 'run_as_root': True}, - {'cmd': ['start', 'tgt'], 'run_as_root': True} - ], - settings.RHEL6: [ - {'cmd': ['service', 'tgtd', 'stop'], 'run_as_root': True}, - {'cmd': ['service', 'tgtd', 'start'], 'run_as_root': True} - ], - settings.FEDORA16: [ - {'cmd': ['service', 'tgtd', 'stop'], 'run_as_root': True}, - {'cmd': ['service', 'tgtd', 'start'], 'run_as_root': True} - ], -} # NCPU, NVOL, NAPI ... are here as possible subcomponents of nova NCPU = "cpu" @@ -187,16 +170,15 @@ CLEANER_CMD_ROOT = [sh.joinpths("/", "bin", 'bash')] #rhel6/fedora libvirt policy #http://wiki.libvirt.org/page/SSHPolicyKitSetup -LIBVIRT_POLICY_FN = "/etc/polkit-1/localauthority/50-local.d/50-libvirt-remote-access.pkla" -LIBVIRT_POLICY_CONTENTS = """ -[libvirt Management Access] -Identity=unix-group:libvirtd -Action=org.libvirt.unix.manage -ResultAny=yes -ResultInactive=yes -ResultActive=yes -""" -POLICY_DISTROS = [settings.RHEL6, settings.FEDORA16] +#LIBVIRT_POLICY_FN = "/etc/polkit-1/localauthority/50-local.d/50-libvirt-remote-access.pkla" +#LIBVIRT_POLICY_CONTENTS = """ +#[libvirt Management Access] +#Identity=unix-group:libvirtd +#Action=org.libvirt.unix.manage +#ResultAny=yes +#ResultInactive=yes +#ResultActive=yes +#""" #xenserver specific defaults XS_DEF_INTERFACE = 'eth1' @@ -245,8 +227,8 @@ def _canon_libvirt_type(virt_type): class NovaUninstaller(comp.PythonUninstallComponent): def __init__(self, *args, **kargs): comp.PythonUninstallComponent.__init__(self, *args, **kargs) - self.bindir = sh.joinpths(self.appdir, BIN_DIR) - self.cfgdir = sh.joinpths(self.appdir, CONFIG_DIR) + self.bin_dir = sh.joinpths(self.app_dir, BIN_DIR) + self.cfg_dir = sh.joinpths(self.app_dir, CONFIG_DIR) def pre_uninstall(self): self._clear_libvirt_domains() @@ -256,10 +238,10 @@ class NovaUninstaller(comp.PythonUninstallComponent): #these environment additions are important #in that they eventually affect how this script runs env = dict() - env['ENABLED_SERVICES'] = ",".join(SUBCOMPONENTS) - env['BIN_DIR'] = self.bindir + env['ENABLED_SERVICES'] = ",".join(self.subsystems) + env['BIN_DIR'] = self.bin_dir env['VOLUME_NAME_PREFIX'] = self.cfg.getdefaulted('nova', 'volume_name_prefix', DEF_VOL_PREFIX) - cleaner_fn = sh.joinpths(self.bindir, CLEANER_DATA_CONF) + cleaner_fn = sh.joinpths(self.bin_dir, CLEANER_DATA_CONF) if sh.isfile(cleaner_fn): LOG.info("Cleaning up your system by running nova cleaner script [%s]." % (cleaner_fn)) cmd = CLEANER_CMD_ROOT + [cleaner_fn] @@ -270,28 +252,25 @@ class NovaUninstaller(comp.PythonUninstallComponent): if virt_driver == 'libvirt': inst_prefix = self.cfg.getdefaulted('nova', 'instance_name_prefix', DEF_INSTANCE_PREFIX) libvirt_type = _canon_libvirt_type(self.cfg.get('nova', 'libvirt_type')) - virsh.clear_libvirt_domains(self.distro.name, libvirt_type, inst_prefix) + virsh.clear_libvirt_domains(self.distro, libvirt_type, inst_prefix) class NovaInstaller(comp.PythonInstallComponent): def __init__(self, *args, **kargs): comp.PythonInstallComponent.__init__(self, *args, **kargs) - self.bindir = sh.joinpths(self.appdir, BIN_DIR) - self.cfgdir = sh.joinpths(self.appdir, CONFIG_DIR) + self.bin_dir = sh.joinpths(self.app_dir, BIN_DIR) + self.cfg_dir = sh.joinpths(self.app_dir, CONFIG_DIR) self.paste_conf_fn = self._get_target_config_name(PASTE_CONF) self.volumes_enabled = False - package_names = [p['name'] - for p in self.component_opts.get('packages', []) - ] - if NVOL in package_names: + if NVOL in self.subsystems: self.volumes_enabled = True self.xvnc_enabled = False - if NXVNC in package_names: + if NXVNC in self.subsystems: self.xvnc_enabled = True def _get_symlinks(self): links = comp.PythonInstallComponent._get_symlinks(self) - source_fn = sh.joinpths(self.cfgdir, API_CONF) + source_fn = sh.joinpths(self.cfg_dir, API_CONF) links[source_fn] = sh.joinpths(self._get_link_dir(), API_CONF) return links @@ -318,7 +297,7 @@ class NovaInstaller(comp.PythonInstallComponent): (_, contents) = utils.load_template(self.component_name, NET_INIT_CONF) params = self._get_param_map(NET_INIT_CONF) contents = utils.param_replace(contents, params, True) - tgt_fn = sh.joinpths(self.bindir, NET_INIT_CONF) + tgt_fn = sh.joinpths(self.bin_dir, NET_INIT_CONF) sh.write_file(tgt_fn, contents) sh.chmod(tgt_fn, 0755) self.tracewriter.file_touched(tgt_fn) @@ -326,8 +305,8 @@ class NovaInstaller(comp.PythonInstallComponent): def _sync_db(self): LOG.info("Syncing the database with nova.") mp = dict() - mp['BINDIR'] = self.bindir - mp['CFGFILE'] = sh.joinpths(self.cfgdir, API_CONF) + mp['BIN_DIR'] = self.bin_dir + mp['CFGFILE'] = sh.joinpths(self.cfg_dir, API_CONF) utils.execute_template(*DB_SYNC_CMD, params=mp) def post_install(self): @@ -345,7 +324,7 @@ class NovaInstaller(comp.PythonInstallComponent): def _setup_cleaner(self): LOG.info("Configuring cleaner template %s.", CLEANER_DATA_CONF) (_, contents) = utils.load_template(self.component_name, CLEANER_DATA_CONF) - tgt_fn = sh.joinpths(self.bindir, CLEANER_DATA_CONF) + tgt_fn = sh.joinpths(self.bin_dir, CLEANER_DATA_CONF) sh.write_file(tgt_fn, contents) sh.chmod(tgt_fn, 0755) self.tracewriter.file_touched(tgt_fn) @@ -372,15 +351,15 @@ class NovaInstaller(comp.PythonInstallComponent): return comp.PythonInstallComponent._get_source_config(self, PASTE_SOURCE_FN) elif config_fn == LOGGING_CONF: name = LOGGING_SOURCE_FN - srcfn = sh.joinpths(self.cfgdir, "nova", name) + srcfn = sh.joinpths(self.cfg_dir, "nova", name) contents = sh.load_file(srcfn) return (srcfn, contents) def _get_param_map(self, config_fn): mp = dict() if config_fn == NET_INIT_CONF: - mp['NOVA_DIR'] = self.appdir - mp['CFG_FILE'] = sh.joinpths(self.cfgdir, API_CONF) + mp['NOVA_DIR'] = self.app_dir + mp['CFG_FILE'] = sh.joinpths(self.cfg_dir, API_CONF) mp['FLOATING_RANGE'] = self.cfg.getdefaulted('nova', 'floating_range', '172.24.4.224/28') mp['TEST_FLOATING_RANGE'] = self.cfg.getdefaulted('nova', 'test_floating_range', '192.168.253.0/29') mp['TEST_FLOATING_POOL'] = self.cfg.getdefaulted('nova', 'test_floating_pool', 'test') @@ -394,15 +373,16 @@ class NovaInstaller(comp.PythonInstallComponent): configs_made = comp.PythonInstallComponent.configure(self) self._generate_nova_conf() configs_made += 1 - # TODO: maybe this should be a subclass that handles these differences driver_canon = _canon_virt_driver(self.cfg.get('nova', 'virt_driver')) - if (self.distro.name in POLICY_DISTROS) and driver_canon == 'libvirt': + # TODO maybe move this?? + if driver_canon == 'libvirt' and self.distro.get_command('virt-policy', quiet=True): + (fn, contents) = self.distro.get_command('virt-policy') dirs_made = list() with sh.Rooted(True): - dirs_made = sh.mkdirslist(sh.dirname(LIBVIRT_POLICY_FN)) - sh.write_file(LIBVIRT_POLICY_FN, LIBVIRT_POLICY_CONTENTS) + dirs_made = sh.mkdirslist(sh.dirname(fn)) + sh.write_file(fn, contents) self.tracewriter.dirs_made(*dirs_made) - self.tracewriter.cfg_file_written(LIBVIRT_POLICY_FN) + self.tracewriter.cfg_file_written(fn) configs_made += 1 return configs_made @@ -410,11 +390,11 @@ class NovaInstaller(comp.PythonInstallComponent): class NovaRuntime(comp.PythonRuntime): def __init__(self, *args, **kargs): comp.PythonRuntime.__init__(self, *args, **kargs) - self.cfgdir = sh.joinpths(self.appdir, CONFIG_DIR) - self.bindir = sh.joinpths(self.appdir, BIN_DIR) + self.cfg_dir = sh.joinpths(self.app_dir, CONFIG_DIR) + self.bin_dir = sh.joinpths(self.app_dir, BIN_DIR) def _setup_network_init(self): - tgt_fn = sh.joinpths(self.bindir, NET_INIT_CONF) + tgt_fn = sh.joinpths(self.bin_dir, NET_INIT_CONF) if sh.isfile(tgt_fn): LOG.info("Creating your nova network to be used with instances.") #still there, run it @@ -434,16 +414,9 @@ class NovaRuntime(comp.PythonRuntime): def post_start(self): self._setup_network_init() - def get_dependencies(self): - deps = comp.PythonRuntime.get_dependencies(self) - # FIXME: This should come from a persona. - if utils.service_enabled(settings.QUANTUM, self.instances, False): - deps.append(settings.QUANTUM) - return deps - def _get_apps_to_start(self): result = [{'name': app_name, - 'path': sh.joinpths(self.bindir, app_name), + 'path': sh.joinpths(self.bin_dir, app_name), } for app_name in sorted(APP_OPTIONS.keys()) ] @@ -456,15 +429,15 @@ class NovaRuntime(comp.PythonRuntime): if virt_driver == 'libvirt': virt_type = _canon_libvirt_type(self.cfg.get('nova', 'libvirt_type')) LOG.info("Checking that your selected libvirt virtualization type [%s] is working and running." % (virt_type)) - if not virsh.virt_ok(virt_type, self.distro.name): - msg = ("Libvirt type %s for distro %s does not seem to be active or configured correctly, " - "perhaps you should be using %s instead." % (virt_type, self.distro.name, DEF_VIRT_TYPE)) + if not virsh.virt_ok(virt_type, self.distro): + msg = ("Libvirt type %s does not seem to be active or configured correctly, " + "perhaps you should be using %s instead." % (virt_type, DEF_VIRT_TYPE)) raise exceptions.StartException(msg) - virsh.restart(self.distro.name) + virsh.restart(self.distro) def _get_param_map(self, app_name): params = comp.PythonRuntime._get_param_map(self, app_name) - params['CFGFILE'] = sh.joinpths(self.cfgdir, API_CONF) + params['CFGFILE'] = sh.joinpths(self.cfg_dir, API_CONF) return params def _get_app_options(self, app): @@ -476,7 +449,7 @@ class NovaRuntime(comp.PythonRuntime): class NovaVolumeConfigurator(object): def __init__(self, ni): self.cfg = ni.cfg - self.appdir = ni.appdir + self.app_dir = ni.app_dir self.distro = ni.distro def setup_volumes(self): @@ -485,7 +458,7 @@ class NovaVolumeConfigurator(object): def _setup_vol_groups(self): LOG.info("Attempting to setup volume groups for nova volume management.") mp = dict() - backing_file = self.cfg.getdefaulted('nova', 'volume_backing_file', sh.joinpths(self.appdir, 'nova-volumes-backing-file')) + backing_file = self.cfg.getdefaulted('nova', 'volume_backing_file', sh.joinpths(self.app_dir, 'nova-volumes-backing-file')) vol_group = self.cfg.getdefaulted('nova', 'volume_group', 'nova-volumes') backing_file_size = utils.to_bytes(self.cfg.getdefaulted('nova', 'volume_backing_file_size', '2052M')) mp['VOLUME_GROUP'] = vol_group @@ -512,7 +485,10 @@ class NovaVolumeConfigurator(object): # logical volumes self._process_lvs(mp) # Finish off by restarting tgt, and ignore any errors - utils.execute_template(*RESTART_TGT_CMD[self.distro.name], check_exit_code=False) + iscsi_cmds = self.distro.get_command('iscsi', quiet=True) + if iscsi_cmds: + restart_cmd = iscsi_cmds['restart'] + utils.execute_template(*restart_cmd, run_as_root=True, check_exit_code=False) def _process_lvs(self, mp): LOG.info("Attempting to setup logical volumes for nova volume management.") @@ -548,12 +524,12 @@ class NovaConfConfigurator(object): self.cfg = ni.cfg self.pw_gen = ni.pw_gen self.instances = ni.instances - self.component_root = ni.component_root - self.appdir = ni.appdir + self.component_dir = ni.component_dir + self.app_dir = ni.app_dir self.tracewriter = ni.tracewriter self.paste_conf_fn = ni.paste_conf_fn self.distro = ni.distro - self.cfgdir = ni.cfgdir + self.cfg_dir = ni.cfg_dir self.xvnc_enabled = ni.xvnc_enabled self.volumes_enabled = ni.volumes_enabled self.novnc_enabled = utils.service_enabled(settings.NOVNC, self.instances) @@ -649,7 +625,7 @@ class NovaConfConfigurator(object): nova_conf.add('rabbit_password', self.cfg.get("passwords", "rabbit")) #where instances will be stored - instances_path = self._getstr('instances_path', sh.joinpths(self.component_root, 'instances')) + instances_path = self._getstr('instances_path', sh.joinpths(self.component_dir, 'instances')) self._configure_instances_path(instances_path, nova_conf) #is this a multihost setup? @@ -766,7 +742,7 @@ class NovaConfConfigurator(object): nova_conf.add('network_manager', NET_MANAGER_TEMPLATE % (self._getstr('network_manager', DEF_NET_MANAGER))) #dhcp bridge stuff??? - nova_conf.add('dhcpbridge_flagfile', sh.joinpths(self.cfgdir, API_CONF)) + nova_conf.add('dhcpbridge_flagfile', sh.joinpths(self.cfg_dir, API_CONF)) #Network prefix for the IP network that all the projects for future VM guests reside on. Example: 192.168.0.0/12 nova_conf.add('fixed_range', self._getstr('fixed_range')) diff --git a/devstack/components/nova_client.py b/devstack/components/nova_client.py index 6468dd87..eacae024 100644 --- a/devstack/components/nova_client.py +++ b/devstack/components/nova_client.py @@ -18,8 +18,6 @@ from devstack import component as comp from devstack import log as logging from devstack import settings -#id -TYPE = settings.NOVA_CLIENT LOG = logging.getLogger("devstack.components.nova_client") diff --git a/devstack/components/novnc.py b/devstack/components/novnc.py index 90a7c756..b92cc989 100644 --- a/devstack/components/novnc.py +++ b/devstack/components/novnc.py @@ -22,8 +22,6 @@ from devstack import utils from devstack.components import nova -#id -TYPE = settings.NOVNC LOG = logging.getLogger("devstack.components.novnc") #where the application is really @@ -67,7 +65,7 @@ class NoVNCRuntime(comp.ProgramRuntime): for app_name in APP_OPTIONS.keys(): apps.append({ 'name': app_name, - 'path': sh.joinpths(self.appdir, UTIL_DIR, app_name), + 'path': sh.joinpths(self.app_dir, UTIL_DIR, app_name), }) return apps @@ -76,7 +74,7 @@ class NoVNCRuntime(comp.ProgramRuntime): if app_name == VNC_PROXY_APP and utils.service_enabled(settings.NOVA, self.instances, False): #have to reach into the nova conf (puke) nova_runtime = self.instances[settings.NOVA] - root_params['NOVA_CONF'] = sh.joinpths(nova_runtime.cfgdir, nova.API_CONF) + root_params['NOVA_CONF'] = sh.joinpths(nova_runtime.cfg_dir, nova.API_CONF) return root_params def _get_app_options(self, app): diff --git a/devstack/components/quantum.py b/devstack/components/quantum.py index 314c998d..6936057a 100644 --- a/devstack/components/quantum.py +++ b/devstack/components/quantum.py @@ -26,8 +26,6 @@ from devstack import utils from devstack.components import db -#id -TYPE = settings.QUANTUM LOG = logging.getLogger("devstack.components.quantum") #vswitch pkgs @@ -117,10 +115,10 @@ class QuantumInstaller(comp.PkgInstallComponent): def _get_target_config_name(self, config_fn): if config_fn == PLUGIN_CONF: - tgt_loc = [self.appdir] + PLUGIN_LOC + [config_fn] + tgt_loc = [self.app_dir] + PLUGIN_LOC + [config_fn] return sh.joinpths(*tgt_loc) elif config_fn == AGENT_CONF: - tgt_loc = [self.appdir] + AGENT_LOC + [config_fn] + tgt_loc = [self.app_dir] + AGENT_LOC + [config_fn] return sh.joinpths(*tgt_loc) else: return comp.PkgInstallComponent._get_target_config_name(self, config_fn) @@ -190,12 +188,12 @@ class QuantumInstaller(comp.PkgInstallComponent): def _get_source_config(self, config_fn): if config_fn == PLUGIN_CONF: - srcloc = [self.appdir] + PLUGIN_LOC + [config_fn] + srcloc = [self.app_dir] + PLUGIN_LOC + [config_fn] srcfn = sh.joinpths(*srcloc) contents = sh.load_file(srcfn) return (srcfn, contents) elif config_fn == AGENT_CONF: - srcloc = [self.appdir] + AGENT_LOC + [config_fn] + srcloc = [self.app_dir] + AGENT_LOC + [config_fn] srcfn = sh.joinpths(*srcloc) contents = sh.load_file(srcfn) return (srcfn, contents) @@ -225,10 +223,10 @@ class QuantumRuntime(comp.ProgramRuntime): if self.q_vswitch_service: app_list.append({ 'name': APP_Q_SERVER, - 'path': sh.joinpths(self.appdir, BIN_DIR, APP_Q_SERVER), + 'path': sh.joinpths(self.app_dir, BIN_DIR, APP_Q_SERVER), }) if self.q_vswitch_agent: - full_pth = [self.appdir] + AGENT_BIN_LOC + [APP_Q_AGENT] + full_pth = [self.app_dir] + AGENT_BIN_LOC + [APP_Q_AGENT] app_list.append({ 'name': APP_Q_AGENT, 'path': sh.joinpths(*full_pth) @@ -241,8 +239,8 @@ class QuantumRuntime(comp.ProgramRuntime): def _get_param_map(self, app_name): param_dict = comp.ProgramRuntime._get_param_map(self, app_name) if app_name == APP_Q_AGENT: - tgt_loc = [self.appdir] + AGENT_LOC + [AGENT_CONF] + tgt_loc = [self.app_dir] + AGENT_LOC + [AGENT_CONF] param_dict['OVS_CONFIG_FILE'] = sh.joinpths(*tgt_loc) elif app_name == APP_Q_SERVER: - param_dict['QUANTUM_CONFIG_FILE'] = sh.joinpths(self.appdir, CONFIG_DIR, QUANTUM_CONF) + param_dict['QUANTUM_CONFIG_FILE'] = sh.joinpths(self.app_dir, CONFIG_DIR, QUANTUM_CONF) return param_dict diff --git a/devstack/components/quantum_client.py b/devstack/components/quantum_client.py index c8fc235b..3483cab6 100644 --- a/devstack/components/quantum_client.py +++ b/devstack/components/quantum_client.py @@ -18,8 +18,6 @@ from devstack import component as comp from devstack import log as logging from devstack import settings -#id -TYPE = settings.QUANTUM_CLIENT LOG = logging.getLogger("devstack.components.quantum_client") diff --git a/devstack/components/rabbit.py b/devstack/components/rabbit.py index e1e3ef2d..a3665abd 100644 --- a/devstack/components/rabbit.py +++ b/devstack/components/rabbit.py @@ -21,8 +21,6 @@ from devstack import log as logging from devstack import settings from devstack import shell as sh -#id -TYPE = settings.RABBIT LOG = logging.getLogger("devstack.components.rabbit") #hopefully these are distro independent.. diff --git a/devstack/components/swift.py b/devstack/components/swift.py index e1f00393..d0caf7e9 100644 --- a/devstack/components/swift.py +++ b/devstack/components/swift.py @@ -22,8 +22,6 @@ from devstack import settings from devstack import shell as sh from devstack import utils -#id -TYPE = settings.SWIFT LOG = logging.getLogger("devstack.components.swift") #swift has alot of config files! @@ -71,9 +69,9 @@ WARMUP_PWS = ['service_token', 'swift_hash'] class SwiftUninstaller(comp.PythonUninstallComponent): def __init__(self, *args, **kargs): comp.PythonUninstallComponent.__init__(self, *args, **kargs) - self.datadir = sh.joinpths(self.appdir, self.cfg.getdefaulted('swift', 'data_location', 'data')) - self.cfgdir = sh.joinpths(self.appdir, CONFIG_DIR) - self.bindir = sh.joinpths(self.appdir, BIN_DIR) + self.datadir = sh.joinpths(self.app_dir, self.cfg.getdefaulted('swift', 'data_location', 'data')) + self.cfg_dir = sh.joinpths(self.app_dir, CONFIG_DIR) + self.bin_dir = sh.joinpths(self.app_dir, BIN_DIR) self.logdir = sh.joinpths(self.datadir, LOG_DIR) def pre_uninstall(self): @@ -88,12 +86,12 @@ class SwiftUninstaller(comp.PythonUninstallComponent): class SwiftInstaller(comp.PythonInstallComponent): def __init__(self, *args, **kargs): comp.PythonInstallComponent.__init__(self, *args, **kargs) - self.cfgdir = sh.joinpths(self.appdir, CONFIG_DIR) - self.bindir = sh.joinpths(self.appdir, BIN_DIR) - self.datadir = sh.joinpths(self.appdir, self.cfg.getdefaulted('swift', 'data_location', 'data')) + self.cfg_dir = sh.joinpths(self.app_dir, CONFIG_DIR) + self.bin_dir = sh.joinpths(self.app_dir, BIN_DIR) + self.datadir = sh.joinpths(self.app_dir, self.cfg.getdefaulted('swift', 'data_location', 'data')) self.logdir = sh.joinpths(self.datadir, LOG_DIR) - self.startmain_file = sh.joinpths(self.bindir, SWIFT_STARTMAIN) - self.makerings_file = sh.joinpths(self.bindir, SWIFT_MAKERINGS) + self.startmain_file = sh.joinpths(self.bin_dir, SWIFT_STARTMAIN) + self.makerings_file = sh.joinpths(self.bin_dir, SWIFT_MAKERINGS) self.fs_dev = sh.joinpths(self.datadir, DEVICE_PATH) self.fs_image = sh.joinpths(self.datadir, SWIFT_IMG) self.auth_server = AUTH_SERVICE @@ -118,7 +116,7 @@ class SwiftInstaller(comp.PythonInstallComponent): 'USER': self.cfg.getdefaulted('swift', 'swift_user', sh.getuser()), 'GROUP': self.cfg.getdefaulted('swift', 'swift_group', sh.getgroupname()), 'SWIFT_DATA_LOCATION': self.datadir, - 'SWIFT_CONFIG_LOCATION': self.cfgdir, + 'SWIFT_CONFIG_LOCATION': self.cfg_dir, 'SERVICE_TOKEN': self.cfg.get('passwords', 'service_token'), 'AUTH_SERVER': self.auth_server, 'SWIFT_HASH': self.cfg.get('passwords', 'swift_hash'), @@ -145,8 +143,8 @@ class SwiftInstaller(comp.PythonInstallComponent): def _create_node_config(self, node_number, port): for t in ['object', 'container', 'account']: - src_fn = sh.joinpths(self.cfgdir, '%s-server.conf' % t) - tgt_fn = sh.joinpths(self.cfgdir, '%s-server/%d.conf' % (t, node_number)) + src_fn = sh.joinpths(self.cfg_dir, '%s-server.conf' % t) + tgt_fn = sh.joinpths(self.cfg_dir, '%s-server/%d.conf' % (t, node_number)) adjustments = { '%NODE_PATH%': sh.joinpths(self.datadir, str(node_number)), '%BIND_PORT%': str(port), @@ -157,7 +155,7 @@ class SwiftInstaller(comp.PythonInstallComponent): def _delete_templates(self): for t in ['object', 'container', 'account']: - sh.unlink(sh.joinpths(self.cfgdir, '%s-server.conf' % t)) + sh.unlink(sh.joinpths(self.cfg_dir, '%s-server.conf' % t)) def _create_nodes(self): for i in range(1, 5): @@ -170,20 +168,20 @@ class SwiftInstaller(comp.PythonInstallComponent): self._delete_templates() def _turn_on_rsync(self): - sh.symlink(sh.joinpths(self.cfgdir, RSYNC_CONF), RSYNCD_CONF_LOC) + sh.symlink(sh.joinpths(self.cfg_dir, RSYNC_CONF), RSYNCD_CONF_LOC) self.tracewriter.symlink_made(RSYNCD_CONF_LOC) sh.replace_in(RSYNC_CONF_LOC, RSYNC_ON_OFF_RE, 'RSYNC_ENABLE=true', True) def _create_log_dirs(self): self.tracewriter.dirs_made(*sh.mkdirslist(sh.joinpths(self.logdir, 'hourly'))) - sh.symlink(sh.joinpths(self.cfgdir, SYSLOG_CONF), SWIFT_RSYNC_LOC) + sh.symlink(sh.joinpths(self.cfg_dir, SYSLOG_CONF), SWIFT_RSYNC_LOC) self.tracewriter.symlink_made(SWIFT_RSYNC_LOC) def _setup_binaries(self): - sh.move(sh.joinpths(self.cfgdir, SWIFT_MAKERINGS), self.makerings_file) + sh.move(sh.joinpths(self.cfg_dir, SWIFT_MAKERINGS), self.makerings_file) sh.chmod(self.makerings_file, 0777) self.tracewriter.file_touched(self.makerings_file) - sh.move(sh.joinpths(self.cfgdir, SWIFT_STARTMAIN), self.startmain_file) + sh.move(sh.joinpths(self.cfg_dir, SWIFT_STARTMAIN), self.startmain_file) sh.chmod(self.startmain_file, 0777) self.tracewriter.file_touched(self.startmain_file) @@ -202,21 +200,21 @@ class SwiftInstaller(comp.PythonInstallComponent): class SwiftRuntime(comp.PythonRuntime): def __init__(self, *args, **kargs): comp.PythonRuntime.__init__(self, *args, **kargs) - self.datadir = sh.joinpths(self.appdir, self.cfg.getdefaulted('swift', 'data_location', 'data')) - self.cfgdir = sh.joinpths(self.appdir, CONFIG_DIR) - self.bindir = sh.joinpths(self.appdir, BIN_DIR) + self.datadir = sh.joinpths(self.app_dir, self.cfg.getdefaulted('swift', 'data_location', 'data')) + self.cfg_dir = sh.joinpths(self.app_dir, CONFIG_DIR) + self.bin_dir = sh.joinpths(self.app_dir, BIN_DIR) self.logdir = sh.joinpths(self.datadir, LOG_DIR) def start(self): sh.execute(*RSYSLOG_SERVICE_RESTART, run_as_root=True) sh.execute(*RSYNC_SERVICE_RESTART, run_as_root=True) - swift_start_cmd = [sh.joinpths(self.bindir, SWIFT_INIT)] + ['all', 'start'] + swift_start_cmd = [sh.joinpths(self.bin_dir, SWIFT_INIT)] + ['all', 'start'] sh.execute(*swift_start_cmd, run_as_root=True) def stop(self): - swift_stop_cmd = [sh.joinpths(self.bindir, SWIFT_INIT)] + ['all', 'stop'] + swift_stop_cmd = [sh.joinpths(self.bin_dir, SWIFT_INIT)] + ['all', 'stop'] sh.execute(*swift_stop_cmd, run_as_root=True) def restart(self): - swift_restart_cmd = [sh.joinpths(self.bindir, SWIFT_INIT)] + ['all', 'restart'] + swift_restart_cmd = [sh.joinpths(self.bin_dir, SWIFT_INIT)] + ['all', 'restart'] sh.execute(*swift_restart_cmd, run_as_root=True) diff --git a/devstack/distro.py b/devstack/distro.py index 9c5a88de..80926df7 100644 --- a/devstack/distro.py +++ b/devstack/distro.py @@ -64,7 +64,7 @@ class Distro(object): LOG.debug('Looking for distro data for %s (%s)', plt, distname) for p in cls.load_all(): if p.supports_distro(plt): - LOG.info('Using distro "%s" for "%s"', p.name, plt) + LOG.info('Using distro "%s" for platform "%s"', p.name, plt) return p else: raise RuntimeError( @@ -78,6 +78,15 @@ class Distro(object): self.commands = commands self.components = components + def __repr__(self): + return "\"%s\" using packager \"%s\"" % (self.name, self.packager_name) + + def get_command(self, cmd_key, quiet=False): + if not quiet: + return self.commands[cmd_key] + else: + return self.commands.get(cmd_key) + def supports_distro(self, distro_name): """Does this distro support the named Linux distro? @@ -97,27 +106,3 @@ class Distro(object): raise RuntimeError('No class configured to %s %s on %s' % (action, name, self.name)) return importer.import_entry_point(entry_point) - - def resolve_component_dependencies(self, components): - """Returns list of all components needed for the named components.""" - all_components = {} - active_names = [(c, None) for c in components] - while active_names: - component, parent = active_names.pop() - try: - component_details = self.components[component] - except KeyError: - if parent: - raise RuntimeError( - 'Could not find details about component %r, a dependency of %s, for %s' % - (component, parent, self.name)) - else: - raise RuntimeError( - 'Could not find details about component %r for %s' % - (component, self.name)) - deps = set(component_details.get('dependencies', [])) - all_components[component] = deps - for d in deps: - if d not in all_components and d not in active_names: - active_names.append((d, component)) - return all_components diff --git a/devstack/distros/oneiric.py b/devstack/distros/oneiric.py index eb98ffef..2f08d56f 100644 --- a/devstack/distros/oneiric.py +++ b/devstack/distros/oneiric.py @@ -10,7 +10,7 @@ LOG = logging.getLogger(__name__) class OneiricDBInstaller(db.DBInstaller): - + def _configure_db_confs(self): LOG.info("Fixing up %s mysql configs.", self.distro.name) fc = sh.load_file('/etc/mysql/my.cnf') diff --git a/devstack/env.py b/devstack/env.py index f1a5fb10..bed5a417 100644 --- a/devstack/env.py +++ b/devstack/env.py @@ -43,5 +43,5 @@ def get_key(key, default_value=None): LOG.debug("Could not find anything in environment variable [%s]" % (key)) value = default_value else: - LOG.debug("Found [%s] in environment variable [%s]" % (value, key)) + LOG.audit("Found [%s] in environment variable [%s]" % (value, key)) return value diff --git a/devstack/env_rc.py b/devstack/env_rc.py index 37fd5af3..3c9e70f4 100644 --- a/devstack/env_rc.py +++ b/devstack/env_rc.py @@ -246,11 +246,25 @@ class RcReader(object): def __init__(self): pass + def _is_comment(self, line): + if line.lstrip().startswith("#"): + return True + return False + def extract(self, fn): extracted_vars = dict() - contents = sh.load_file(fn) + contents = '' + #not using shell here since + #we don't want this to be "nulled" in a dry-run + LOG.audit("Loading rc file [%s]" % (fn)) + try: + with open(fn, 'r') as fh: + contents = fh.read() + except IOError as e: + LOG.warn("Failed extracting rc file [%s] due to [%s]" % (fn, e.message)) + return extracted_vars for line in contents.splitlines(): - if line.lstrip().startswith("#"): + if self._is_comment(line): continue m = EXP_PAT.search(line) if m: diff --git a/devstack/importer.py b/devstack/importer.py index 31204f42..5d18ff05 100644 --- a/devstack/importer.py +++ b/devstack/importer.py @@ -1,13 +1,36 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (C) 2012 Yahoo! Inc. All Rights Reserved. +# Copyright (C) 2012 Dreamhost Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. -def import_entry_point(fullname): - """Given a name import the class and return it. - +def partition(fullname): + """ The name should be in dotted.path:ClassName syntax. """ if ':' not in fullname: raise ValueError('Invalid entry point specifier %r' % fullname) module_name, ignore, classname = fullname.partition(':') + return (module_name, ignore, classname) + + +def import_entry_point(fullname): + """ + Given a name import the class and return it. + """ + module_name, ignore, classname = partition(fullname) try: module = __import__(module_name) for submodule in module_name.split('.')[1:]: diff --git a/devstack/libvirt.py b/devstack/libvirt.py index 34bce9b5..6553d032 100644 --- a/devstack/libvirt.py +++ b/devstack/libvirt.py @@ -32,13 +32,6 @@ LIBVIRT_PROTOCOL_MAP = { } VIRT_LIB = 'libvirt' -#distros name the libvirt service differently :-( -SV_NAME_MAP = { - settings.RHEL6: 'libvirtd', - settings.FEDORA16: 'libvirtd', - settings.UBUNTU11: 'libvirt-bin', -} - #how libvirt is restarted LIBVIRT_RESTART_CMD = ['service', '%SERVICE%', 'restart'] @@ -71,7 +64,7 @@ def _status(distro): 'run_as_root': True, }) mp = dict() - mp['SERVICE'] = SV_NAME_MAP[distro] + mp['SERVICE'] = distro.get_command('libvirt-daemon') result = utils.execute_template(*cmds, check_exit_code=False, params=mp) @@ -104,7 +97,7 @@ def restart(distro): 'run_as_root': True, }) mp = dict() - mp['SERVICE'] = SV_NAME_MAP[distro] + mp['SERVICE'] = distro.get_command('libvirt-daemon') utils.execute_template(*cmds, params=mp) LOG.info("Restarting the libvirt service, please wait %s seconds until its started." % (WAIT_ALIVE_TIME)) sh.sleep(WAIT_ALIVE_TIME) @@ -117,7 +110,7 @@ def virt_ok(virt_type, distro): try: restart(distro) except excp.ProcessExecutionError, e: - LOG.warn("Could not restart libvirt on distro [%s] due to [%s]" % (distro, e.message)) + LOG.warn("Could not restart libvirt due to [%s]" % (e)) return False try: cmds = list() @@ -148,7 +141,7 @@ def clear_libvirt_domains(distro, virt_type, inst_prefix): try: restart(distro) except excp.ProcessExecutionError, e: - LOG.warn("Could not restart libvirt on distro [%s] due to [%s]" % (distro, e.message)) + LOG.warn("Could not restart libvirt due to [%s]" % (e)) return try: conn = libvirt.open(virt_protocol) diff --git a/devstack/opts.py b/devstack/opts.py index 06b3766d..fe6315a8 100644 --- a/devstack/opts.py +++ b/devstack/opts.py @@ -35,10 +35,8 @@ def parse(): version_str = "%prog v" + version.version_string() help_formatter = IndentedHelpFormatter(width=HELP_WIDTH) parser = OptionParser(version=version_str, formatter=help_formatter) - parser.add_option("-c", "--component", - action="append", - dest="component", - help="openstack component: %s" % (_format_list(settings.COMPONENT_NAMES))) + + #root options parser.add_option("-v", "--verbose", action="append_const", const=1, @@ -52,7 +50,14 @@ def parse(): help=("perform ACTION but do not actually run any of the commands" " that would normally complete ACTION: (default: %default)")) + #install/start/stop/uninstall specific options base_group = OptionGroup(parser, "Install & uninstall & start & stop specific options") + base_group.add_option("-p", "--persona", + action="store", + type="string", + dest="persona_fn", + metavar="FILE", + help="required persona yaml file to apply") base_group.add_option("-a", "--action", action="store", type="string", @@ -66,28 +71,15 @@ def parse(): metavar="DIR", help=("empty root DIR for install or " "DIR with existing components for start/stop/uninstall")) - base_group.add_option("-i", "--ignore-deps", - action="store_false", - dest="ensure_deps", - help="ignore dependencies when performing ACTION") base_group.add_option("--no-prompt-passwords", action="store_false", dest="prompt_for_passwords", default=True, help="do not prompt the user for passwords", ) - base_group.add_option("-e", "--ensure-deps", - action="store_true", - dest="ensure_deps", - help="ensure dependencies when performing ACTION (default: %default)", - default=True) - base_group.add_option("-r", "--ref-component", - action="append", - dest="ref_components", - metavar="COMPONENT", - help="component which will not have ACTION applied but will be referenced as if it was (ACTION dependent)") parser.add_option_group(base_group) + #uninstall and stop options stop_un_group = OptionGroup(parser, "Uninstall & stop specific options") stop_un_group.add_option("-n", "--no-force", action="store_true", @@ -107,15 +99,13 @@ def parse(): #extract only what we care about (options, args) = parser.parse_args() output = dict() - output['components'] = options.component or list() output['dir'] = options.dir or "" output['dryrun'] = options.dryrun or False - output['ref_components'] = options.ref_components or list() output['action'] = options.action or "" output['force'] = not options.force - output['ignore_deps'] = not options.ensure_deps output['keep_old'] = options.keep_old output['extras'] = args + output['persona_fn'] = options.persona_fn output['verbosity'] = len(options.verbosity) output['prompt_for_passwords'] = options.prompt_for_passwords diff --git a/devstack/progs/actions.py b/devstack/progs/actions.py index 60c787af..6019947b 100644 --- a/devstack/progs/actions.py +++ b/devstack/progs/actions.py @@ -14,22 +14,23 @@ # License for the specific language governing permissions and limitations # under the License.. +import yaml + from devstack import env_rc from devstack import exceptions as excp from devstack import log as logging from devstack import settings from devstack import shell as sh from devstack import utils - -from devstack.progs import common +from devstack import passwords LOG = logging.getLogger("devstack.progs.actions") # For actions in this list we will reverse the component order -_REVERSE_ACTIONS = [settings.UNINSTALL, settings.STOP] +REVERSE_ACTIONS = [settings.UNINSTALL, settings.STOP] # For these actions we will attempt to make an rc file if it does not exist -_RC_FILE_MAKE_ACTIONS = [settings.INSTALL] +RC_FILE_MAKE_ACTIONS = [settings.INSTALL] # The order of which uninstalls happen + message of what is happening # (before and after) @@ -138,125 +139,93 @@ PREQ_ACTIONS = { class ActionRunner(object): - def __init__(self, distro, action, directory, config, - pw_gen, pkg_manager, - **kargs): + def __init__(self, distro, action, cfg, **kargs): self.distro = distro self.action = action - self.directory = directory - self.cfg = config - self.pw_gen = pw_gen - self.pkg_manager = pkg_manager - self.kargs = kargs - self.components = dict() - def_components = common.get_default_components() - unclean_components = kargs.pop("components") - if not unclean_components: - self.components = def_components - else: - for (c, opts) in unclean_components.items(): - if opts is None and c in def_components: - self.components[c] = def_components[c] - elif opts is None: - self.components[c] = list() - else: - self.components[c] = opts + self.cfg = cfg + self.pw_gen = passwords.PasswordGenerator(self.cfg, kargs.get('prompt_for_passwords', True)) + pkg_cls = distro.get_packager_factory() + self.pkg_manager = pkg_cls(self.distro.name, kargs.get('keep_old', False)) self.force = kargs.get('force', False) - self.ignore_deps = kargs.get('ignore_deps', False) - self.ref_components = kargs.get("ref_components") - self.gen_rc = action in _RC_FILE_MAKE_ACTIONS + self.kargs = kargs - def _get_components(self): - return dict(self.components) + def _apply_reverse(self, action, component_order): + if not component_order: + component_order = list() + else: + component_order = list(component_order) + adjusted_order = list(component_order) + if action in REVERSE_ACTIONS: + adjusted_order.reverse() + return adjusted_order - def _order_components(self, components): - adjusted_components = dict(components) - if self.ignore_deps: - return (adjusted_components, list(components.keys())) - all_components = self.distro.resolve_component_dependencies( - list(components.keys()) - ) - component_diff = set(all_components.keys()).difference(components.keys()) - if component_diff: - LOG.info("Activating dependencies: [%s]", - ", ".join(sorted(component_diff)) - ) - for new_component in component_diff: - adjusted_components[new_component] = [] - return (adjusted_components, utils.get_components_order(all_components)) + def _load_persona(self, persona_fn): + persona_fn = sh.abspth(persona_fn) + LOG.audit("Loading persona from file [%s]", persona_fn) + contents = '' + with open(persona_fn, "r") as fh: + contents = fh.read() + return self._verify_persona(yaml.load(contents), persona_fn) - def _inject_references(self, components): - ref_components = utils.parse_components(self.ref_components) - adjusted_components = dict(components) - for c in ref_components.keys(): - if c not in components: - adjusted_components[c] = ref_components.get(c) - return adjusted_components - - def _instantiate_components(self, components): - all_instances = dict() - for component in components.keys(): - cls = self.distro.get_component_action_class(component, - self.action) - LOG.debug('instantiating %s to handle %s for %s', - cls, self.action, component) - instance = cls(component_name=component, - instances=all_instances, - runner=self, - root_dir=self.directory, - component_options=self.distro.components[component], - keep_old=self.kargs.get("keep_old") - ) - all_instances[component] = instance - return all_instances - - def _run_preqs(self, components, component_order): - if not (self.action in PREQ_ACTIONS): - return - (check_functor, preq_action) = PREQ_ACTIONS[self.action] - instances = self._instantiate_components(components) - preq_components = dict() + def _verify_persona(self, persona, fn): + # Some sanity checks + try: + if self.distro.name not in persona['supports']: + raise RuntimeError("Persona does not support distro %s" + % (self.distro.name)) + for c in persona['components']: + if c not in self.distro.components: + raise RuntimeError("Distro %s does not support component %s" % + (self.distro.name, c)) + except (KeyError, RuntimeError) as e: + msg = ("Could not validate persona defined in [%s] due to: %s" + % (fn, e)) + raise excp.ConfigException(msg) + return persona + + def _construct_instances(self, persona, action, root_dir): + components = persona['components'] # Required + subsystems = persona.get('subsystems') or dict() # Not required + instances = dict() + for c in components: + cls = self.distro.get_component_action_class(c, action) + LOG.debug("Constructing class %s" % (cls)) + cls_kvs = dict() + cls_kvs['runner'] = self + cls_kvs['component_dir'] = sh.joinpths(root_dir, c) + cls_kvs['subsystems'] = set(subsystems.get(c, list())) + cls_kvs['all_instances'] = instances + cls_kvs['name'] = c + # FIXME: + cls_kvs['keep_old'] = False + LOG.debug("Using k/v map %s", cls_kvs) + instances[c] = cls(*list(), **cls_kvs) + return instances + + def _verify_components(self, component_order, instances): + LOG.info("Verifying that the components are ready to rock-n-roll.") for c in component_order: instance = instances[c] - if check_functor(instance): - preq_components[c] = components[c] - if preq_components: - LOG.info("Having to activate prerequisite action [%s] for %s components." % (preq_action, len(preq_components))) - preq_runner = ActionRunner(distro=self.distro, - action=preq_action, - directory=self.directory, - config=self.cfg, - pw_gen=self.pw_gen, - pkg_manager=self.pkg_manager, - components=preq_components, - **self.kargs) - preq_runner.run() - - def _pre_run(self, instances, component_order): - if not sh.isdir(self.directory): - sh.mkdir(self.directory) - LOG.info("Verifying that the components are ready to rock-n-roll.") - for component in component_order: - inst = instances[component] - inst.verify() + instance.verify() + + def _warm_components(self, component_order, instances): LOG.info("Warming up your component configurations (ie so you won't be prompted later)") - for component in component_order: - inst = instances[component] - inst.warm_configs() - if self.gen_rc: - writer = env_rc.RcWriter(self.cfg, self.pw_gen, self.directory) - if not sh.isfile(settings.OSRC_FN): - LOG.info("Generating a file at [%s] that will contain your environment settings." % (settings.OSRC_FN)) - writer.write(settings.OSRC_FN) - else: - LOG.info("Updating a file at [%s] that contains your environment settings." % (settings.OSRC_FN)) - am_upd = writer.update(settings.OSRC_FN) - LOG.info("Updated [%s] settings in rc file [%s]" % (am_upd, settings.OSRC_FN)) - - def _run_instances(self, instances, component_order): - component_order = self._apply_reverse(component_order) - LOG.info("Running in the following order: %s" % ("->".join(component_order))) - for (start_msg, functor, end_msg) in ACTION_MP[self.action]: + for c in component_order: + instance = instances[c] + instance.warm_configs() + + def _write_rc_file(self, root_dir): + writer = env_rc.RcWriter(self.cfg, self.pw_gen, root_dir) + if not sh.isfile(settings.OSRC_FN): + LOG.info("Generating a file at [%s] that will contain your environment settings." % (settings.OSRC_FN)) + writer.write(settings.OSRC_FN) + else: + LOG.info("Updating a file at [%s] that contains your environment settings." % (settings.OSRC_FN)) + am_upd = writer.update(settings.OSRC_FN) + LOG.info("Updated [%s] settings in rc file [%s]" % (am_upd, settings.OSRC_FN)) + + def _run_instances(self, action, component_order, instances): + for (start_msg, functor, end_msg) in ACTION_MP[action]: for c in component_order: instance = instances[c] if start_msg: @@ -271,19 +240,30 @@ class ActionRunner(object): else: raise - def _apply_reverse(self, component_order): - adjusted_order = list(component_order) - if self.action in _REVERSE_ACTIONS: - adjusted_order.reverse() - return adjusted_order - - def _start(self, components, component_order): - LOG.info("Activating components required to complete action [%s]" % (self.action)) - instances = self._instantiate_components(components) - self._pre_run(instances, component_order) - self._run_preqs(components, component_order) - self._run_instances(instances, component_order) - - def run(self): - (components, component_order) = self._order_components(self._get_components()) - self._start(self._inject_references(components), component_order) + def _run_action(self, persona, action, root_dir): + LOG.info("Running action [%s] using root directory [%s]" % (action, root_dir)) + instances = self._construct_instances(persona, action, root_dir) + if action in PREQ_ACTIONS: + (check_functor, preq_action) = PREQ_ACTIONS[action] + checks_passed_components = list() + for (c, instance) in instances.items(): + if check_functor(instance): + checks_passed_components.append(c) + if checks_passed_components: + LOG.info("Activating prerequisite action [%s] requested by (%s) components." + % (preq_action, ", ".join(checks_passed_components))) + self._run_action(persona, preq_action, root_dir) + component_order = self._apply_reverse(action, persona['components']) + LOG.info("Activating components [%s] (in that order) for action [%s]" % + ("->".join(component_order), action)) + self._verify_components(component_order, instances) + self._warm_components(component_order, instances) + if action in RC_FILE_MAKE_ACTIONS: + self._write_rc_file(root_dir) + self._run_instances(action, component_order, instances) + + def run(self, persona_fn, root_dir): + persona = self._load_persona(persona_fn) + if not sh.isdir(root_dir): + sh.mkdir(root_dir) + self._run_action(persona, self.action, root_dir) diff --git a/devstack/progs/common.py b/devstack/progs/common.py deleted file mode 100644 index fdbbc6f6..00000000 --- a/devstack/progs/common.py +++ /dev/null @@ -1,190 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (C) 2012 Yahoo! Inc. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import tempfile - -from devstack import cfg -from devstack import exceptions as excp -from devstack import settings -from devstack import shell as sh - -from devstack.components import db -from devstack.components import glance -from devstack.components import horizon -from devstack.components import keystone -from devstack.components import keystone_client -from devstack.components import melange -from devstack.components import melange_client -from devstack.components import nova -from devstack.components import nova_client -from devstack.components import novnc -from devstack.components import quantum -from devstack.components import quantum_client -from devstack.components import rabbit -from devstack.components import swift - -from devstack.packaging import apt -from devstack.packaging import yum - -# This determines what classes to use to install/uninstall/... -# ACTION_CLASSES = { -# settings.INSTALL: { -# settings.DB: db.DBInstaller, -# settings.GLANCE: glance.GlanceInstaller, -# settings.HORIZON: horizon.HorizonInstaller, -# settings.KEYSTONE: keystone.KeystoneInstaller, -# settings.KEYSTONE_CLIENT: keystone_client.KeyStoneClientInstaller, -# settings.MELANGE: melange.MelangeInstaller, -# settings.MELANGE_CLIENT: melange_client.MelangeClientInstaller, -# settings.NOVA: nova.NovaInstaller, -# settings.NOVA_CLIENT: nova_client.NovaClientInstaller, -# settings.NOVNC: novnc.NoVNCInstaller, -# settings.QUANTUM: quantum.QuantumInstaller, -# settings.QUANTUM_CLIENT: quantum_client.QuantumClientInstaller, -# settings.RABBIT: rabbit.RabbitInstaller, -# settings.SWIFT: swift.SwiftInstaller, -# }, -# settings.UNINSTALL: { -# settings.DB: db.DBUninstaller, -# settings.GLANCE: glance.GlanceUninstaller, -# settings.HORIZON: horizon.HorizonUninstaller, -# settings.KEYSTONE: keystone.KeystoneUninstaller, -# settings.KEYSTONE_CLIENT: keystone_client.KeyStoneClientUninstaller, -# settings.MELANGE: melange.MelangeUninstaller, -# settings.MELANGE_CLIENT: melange_client.MelangeClientUninstaller, -# settings.NOVA: nova.NovaUninstaller, -# settings.NOVA_CLIENT: nova_client.NovaClientUninstaller, -# settings.NOVNC: novnc.NoVNCUninstaller, -# settings.QUANTUM: quantum.QuantumUninstaller, -# settings.QUANTUM_CLIENT: quantum_client.QuantumClientUninstaller, -# settings.RABBIT: rabbit.RabbitUninstaller, -# settings.SWIFT: swift.SwiftUninstaller, -# }, -# settings.START: { -# settings.DB: db.DBRuntime, -# settings.GLANCE: glance.GlanceRuntime, -# settings.HORIZON: horizon.HorizonRuntime, -# settings.KEYSTONE: keystone.KeystoneRuntime, -# settings.KEYSTONE_CLIENT: keystone_client.KeyStoneClientRuntime, -# settings.MELANGE: melange.MelangeRuntime, -# settings.MELANGE_CLIENT: melange_client.MelangeClientRuntime, -# settings.NOVA: nova.NovaRuntime, -# settings.NOVA_CLIENT: nova_client.NovaClientRuntime, -# settings.NOVNC: novnc.NoVNCRuntime, -# settings.QUANTUM: quantum.QuantumRuntime, -# settings.QUANTUM_CLIENT: quantum_client.QuantumClientRuntime, -# settings.RABBIT: rabbit.RabbitRuntime, -# settings.SWIFT: swift.SwiftRuntime, -# }, -# } - -# # Just a copy -# ACTION_CLASSES[settings.STOP] = ACTION_CLASSES[settings.START] - -# Used only for figuring out deps -_FAKE_ROOT_DIR = tempfile.gettempdir() - -# This map controls which distro has -# which package management class -_PKGR_MAP = { - settings.UBUNTU11: apt.AptPackager, - settings.RHEL6: yum.YumPackager, - settings.FEDORA16: yum.YumPackager, -} - - -def get_default_components(): - def_components = dict() - def_components[settings.GLANCE] = [ - glance.GAPI, - glance.GREG, - ] - def_components[settings.KEYSTONE] = [] - def_components[settings.NOVA] = [ - nova.NAPI, - nova.NCAUTH, - nova.NCERT, - nova.NCPU, - nova.NNET, - nova.NOBJ, - nova.NSCHED, - nova.NXVNC, - nova.NVOL, - ] - def_components[settings.NOVNC] = [] - def_components[settings.HORIZON] = [] - def_components[settings.DB] = [] - def_components[settings.RABBIT] = [] - return def_components - - -def format_secs_taken(secs): - output = "%.03f seconds" % (secs) - output += " or %.02f minutes" % (secs / 60.0) - return output - - -# def get_action_cls(action_name, component_name, distro=None): -# action_cls_map = ACTION_CLASSES.get(action_name) -# if not action_cls_map: -# raise excp.StackException("Action %s has no component to class mapping" % (action_name)) -# cls = action_cls_map.get(component_name) -# if not cls: -# raise excp.StackException("Action %s has no class entry for component %s" % (action_name, component_name)) -# return cls - - -def get_packager(distro, keep_packages): - cls = _PKGR_MAP.get(distro) - if not cls: - msg = "No package manager found for distro %s!" % (distro) - raise excp.StackException(msg) - return cls(distro, keep_packages) - - -def get_config(cfg_fn=None): - if not cfg_fn: - cfg_fn = sh.canon_path(settings.STACK_CONFIG_LOCATION) - config_instance = cfg.StackConfigParser() - config_instance.read(cfg_fn) - return config_instance - - -# def get_components_deps(runner, -# action_name, -# base_components, -# root_dir=None, -# distro=None, -# ): -# all_components = dict() -# active_names = list(base_components) -# root_dir = root_dir or _FAKE_ROOT_DIR -# while len(active_names): -# component = active_names.pop() -# component_opts = base_components.get(component) or list() -# cls = get_action_cls(action_name, component, distro) -# instance = cls(instances=list(), -# runner=runner, -# root_dir=root_dir, -# component_options=component_opts, -# keep_old=False -# ) -# deps = instance.get_dependencies() or set() -# all_components[component] = set(deps) -# for d in deps: -# if d not in all_components and d not in active_names: -# active_names.append(d) -# return all_components diff --git a/devstack/settings.py b/devstack/settings.py index cbfc1e3f..9a9d40d6 100644 --- a/devstack/settings.py +++ b/devstack/settings.py @@ -18,13 +18,6 @@ import os import re import sys -# These also have meaning outside python, -# ie in the pkg/pip listings so update there also! -# FIXME: Delete -UBUNTU11 = "ubuntu-oneiric" -RHEL6 = "rhel-6" -FEDORA16 = "fedora-16" - # What this program is called PROG_NICE_NAME = "DEVSTACKpy" @@ -36,7 +29,7 @@ POST_INSTALL = 'post-install' IPV4 = 'IPv4' IPV6 = 'IPv6' -#how long to wait for a service to startup +# How long to wait for a service to startup WAIT_ALIVE_SECS = 5 # Component name mappings @@ -68,29 +61,6 @@ COMPONENT_NAMES = [ MELANGE, MELANGE_CLIENT, ] -# When a component is asked for it may -# need another component, that dependency -# mapping is listed here. A topological sort -# will be applied to determine the exact order. -# COMPONENT_DEPENDENCIES = { -# DB: [], -# KEYSTONE_CLIENT: [], -# RABBIT: [], -# GLANCE: [KEYSTONE, DB], -# KEYSTONE: [DB, KEYSTONE_CLIENT], -# NOVA: [KEYSTONE, GLANCE, DB, RABBIT, NOVA_CLIENT], -# SWIFT: [KEYSTONE_CLIENT], -# NOVA_CLIENT: [], -# # Horizon depends on glances client (which should really be a client package) -# HORIZON: [KEYSTONE_CLIENT, GLANCE, NOVA_CLIENT, QUANTUM_CLIENT], -# # More of quantums deps come from its module function get_dependencies -# QUANTUM: [], -# NOVNC: [NOVA], -# QUANTUM_CLIENT: [], -# MELANGE: [DB], -# MELANGE_CLIENT: [], -# } - # Different run types supported RUN_TYPE_FORK = "FORK" RUN_TYPE_UPSTART = "UPSTART" @@ -126,6 +96,4 @@ ACTIONS = [INSTALL, UNINSTALL, START, STOP] STACK_BIN_DIR = os.path.abspath(os.path.dirname(sys.argv[0])) STACK_CONFIG_DIR = os.path.join(STACK_BIN_DIR, "conf") STACK_TEMPLATE_DIR = os.path.join(STACK_CONFIG_DIR, "templates") -STACK_PKG_DIR = os.path.join(STACK_CONFIG_DIR, "pkgs") -STACK_PIP_DIR = os.path.join(STACK_CONFIG_DIR, "pips") STACK_CONFIG_LOCATION = os.path.join(STACK_CONFIG_DIR, "stack.ini") diff --git a/devstack/utils.py b/devstack/utils.py index 2bfe8216..635781b3 100644 --- a/devstack/utils.py +++ b/devstack/utils.py @@ -257,79 +257,10 @@ def get_interfaces(): return interfaces -def get_components_order(components): - if not components: - return dict() - #deep copy so components isn't messed with - all_components = dict() - for (name, deps) in components.items(): - all_components[name] = set(deps) - #figure out which ones have no one depending on them - no_deps_components = set() - for (name, deps) in all_components.items(): - referenced = False - for (_name, _deps) in all_components.items(): - if _name == name: - continue - else: - if name in _deps: - referenced = True - break - if not referenced: - no_deps_components.add(name) - if not no_deps_components: - msg = "Components specifed have no root components, there is most likely a dependency cycle!" - raise excp.DependencyException(msg) - #now we have to do a quick check to ensure no component is causing a cycle - for (root, deps) in all_components.items(): - #DFS down through the "roots" deps and there deps and so on and - #ensure that nobody is referencing the "root" component name, - #that would mean there is a cycle if a dependency of the "root" is. - active_deps = list(deps) - checked_deps = dict() - while len(active_deps): - dep = active_deps.pop() - itsdeps = all_components.get(dep) - checked_deps[dep] = True - if root in itsdeps: - msg = "Circular dependency between component %s and component %s!" % (root, dep) - raise excp.DependencyException(msg) - else: - for d in itsdeps: - if d not in checked_deps and d not in active_deps: - active_deps.append(d) - #now form the order - #basically a topological sorting - #https://en.wikipedia.org/wiki/Topological_sorting - ordering = list() - no_edges = set(no_deps_components) - while len(no_edges): - node = no_edges.pop() - ordering.append(node) - its_deps = all_components.get(node) - while len(its_deps): - name = its_deps.pop() - referenced = False - for (_name, _deps) in all_components.items(): - if _name == name: - continue - else: - if name in _deps: - referenced = True - break - if not referenced: - no_edges.add(name) - #should now be no edges else something bad happended - for (_, deps) in all_components.items(): - if len(deps): - msg = "Your specified components have at least one cycle!" - raise excp.DependencyException(msg) - #reverse so its in the right order for us since we just determined - #the pkgs that have no one depending on them (which should be installed - #last and those that have incoming edges that packages are depending on need - #to go first, but those were inserted last), so this reverse fixes that - ordering.reverse() - return ordering +def format_secs_taken(secs): + output = "%.03f seconds" % (secs) + output += " or %.02f minutes" % (secs / 60.0) + return output def joinlinesep(*pieces): @@ -707,28 +638,6 @@ def goodbye(worked): print(msg) -def parse_components(components): - if not components: - return dict() - adjusted_components = dict() - for c in components: - mtch = EXT_COMPONENT.match(c) - if mtch: - component_name = mtch.group(1).lower().strip() - if component_name in settings.COMPONENT_NAMES: - component_opts = mtch.group(2) - components_opts_cleaned = None - if component_opts: - components_opts_cleaned = list() - sp_component_opts = component_opts.split(",") - for co in sp_component_opts: - cleaned_opt = co.strip() - if cleaned_opt: - components_opts_cleaned.append(cleaned_opt) - adjusted_components[component_name] = components_opts_cleaned - return adjusted_components - - def welcome(ident): lower = "| %s %s |" % (ident, version.version_string()) welcome_header = _get_welcome_stack() diff --git a/stack b/stack index 532c1317..612f2d84 100755 --- a/stack +++ b/stack @@ -20,6 +20,7 @@ import sys import time import traceback +from devstack import cfg from devstack import cfg_helpers from devstack import date from devstack import distro @@ -33,7 +34,6 @@ from devstack import shell as sh from devstack import utils from devstack.progs import actions -from devstack.progs import common LOG = logging.getLogger("devstack.stack") @@ -50,7 +50,7 @@ _WELCOME_MAP = { _CFG_GROUPS = { cfg_helpers.make_id('passwords', None): 'Passwords', cfg_helpers.make_id('db', None): 'Database info', - #catch all + # Catch all cfg_helpers.make_id(None, None): 'Misc configs', } @@ -68,12 +68,12 @@ def dump_config(config_cache): value = mp.get(key) LOG.info(item_format(key, value)) - #first partition into our groups + # First partition into our groups partitions = dict() for name in _CFG_ORDERING: partitions[name] = dict() - #now put the config cached values into there partition + # Now put the config cached values into there partitions for (k, v) in config_cache.items(): for name in _CFG_ORDERING: entries = partitions[name] @@ -81,7 +81,7 @@ def dump_config(config_cache): entries[k] = v break - #now print them.. + # Now print them.. for name in _CFG_ORDERING: nice_name = _CFG_GROUPS.get(name) LOG.info(nice_name + ":") @@ -103,49 +103,52 @@ def load_rc_files(): def run(args): - action = args.pop("action").strip().lower() + action = args.pop("action", '').strip().lower() if not (action in settings.ACTIONS): print(utils.color_text("No valid action specified!", "red")) return False loaded_rcs = False - rootdir = args.pop("dir") - if not rootdir: + root_dir = args.pop("dir") + if not root_dir: load_rc_files() loaded_rcs = True - rootdir = env.get_key(env_rc.INSTALL_ROOT) - if not rootdir: + root_dir = env.get_key(env_rc.INSTALL_ROOT) + if not root_dir: print(utils.color_text("No root directory specified!", "red")) return False - #welcome! + persona_fn = args.pop('persona_fn') + if not persona_fn or not sh.isfile(persona_fn): + print(utils.color_text("No valid persona file name specified!", "red")) + return False + + # Welcome! (repeat_string, line_max_len) = utils.welcome(_WELCOME_MAP.get(action)) print(utils.center_text("Action Runner", repeat_string, line_max_len)) - #here on out we should be using the logger (and not print) - start_time = time.time() + # Here on out we should be using the logger (and not print)!! - # if we didn't load them before, load them now + # If we didn't load them before, load them now if not loaded_rcs: load_rc_files() loaded_rcs = True # Stash the dryrun value (if any) into the global configuration - sh.set_dryrun(args['dryrun']) + sh.set_dryrun(args.pop('dryrun')) dist = distro.Distro.get_current() - config = common.get_config() - pw_gen = passwords.PasswordGenerator(config, args['prompt_for_passwords']) - pkg_factory = dist.get_packager_factory() - pkg_manager = pkg_factory(dist, args['keep_old']) - - components = utils.parse_components(args.pop("components")) - runner = actions.ActionRunner(dist, action, rootdir, config, pw_gen, - pkg_manager, components=components, **args) + config = cfg.get_config() + runner = actions.ActionRunner(dist, action, config, **args) LOG.info("Starting action [%s] on %s for distro [%s]" % (action, date.rcf8222date(), dist)) - runner.run() - LOG.info("It took (%s) to complete action [%s]" % (common.format_secs_taken((time.time() - start_time)), action)) + + start_time = time.time() + runner.run(persona_fn, root_dir) + end_time = time.time() + + LOG.info("It took (%s) to complete action [%s]" % + (utils.format_secs_taken((end_time - start_time)), action)) LOG.info("After action [%s] your settings which were created or read are:" % (action)) dump_config(config.configs_fetched) @@ -154,7 +157,7 @@ def run(args): def main(): - #do this first so people can see the help message... + # Do this first so people can see the help message... args = opts.parse() prog_name = sys.argv[0] @@ -163,7 +166,7 @@ def main(): LOG.debug("Command line options %s" % (args)) - #will need root to setup openstack + # Will need root to setup openstack if not sh.got_root(): rest_args = sys.argv[1:] print("This program requires a user with sudo access.") @@ -173,7 +176,7 @@ def main(): return 1 try: - #drop to usermode + # Drop to usermode sh.user_mode(False) started_ok = run(args) if not started_ok: