Pass the settings for a component from the YAML file when creating the instance to manage the component. Use the package list in the YAML file instead of the JSON files.

This commit is contained in:
Doug Hellmann 2012-03-14 20:23:26 -04:00
parent 4c5f992534
commit 9837005900
20 changed files with 81 additions and 219 deletions

View File

@ -56,10 +56,10 @@ components:
# This apparently is a action needed for ubuntu/debian to set the password to something known....
- run_as_root: true
cmd: ["debconf-set-selections"]
stdin: |
mysql-server-5.1 mysql-server/root_password password %PASSWORD%
mysql-server-5.1 mysql-server/root_password_again password %PASSWORD%
mysql-server-5.1 mysql-server/start_on_boot boolean %BOOT_START%
stdin:
- mysql-server-5.1 mysql-server/root_password password %PASSWORD%
- mysql-server-5.1 mysql-server/root_password_again password %PASSWORD%
- mysql-server-5.1 mysql-server/start_on_boot boolean %BOOT_START%
general:
install: devstack.components.pkglist:Installer
@ -116,22 +116,22 @@ components:
removable: false
version: 1.6.4*
- name: python-setuptools
version: 0.6.16*,
version: 0.6.16*
removable: false
- name: python-dev
version: 2.7.2*,
version: 2.7.2*
removable: false
- name: python-nose
version: 1.0.0*,
version: 1.0.0*
removable: false
- name: python-mox
version: 0.5.3*,
version: 0.5.3*
removable: false
- name: screen
removable: false
version: 4.0.3*
- name: sudo
removable: false,
removable: false
version : 1.7.4*
- name: tcpdump
removable: false

View File

@ -63,7 +63,7 @@ class ComponentBase(object):
# avoid breaking garbage collection.
self.runner = weakref.proxy(runner)
self.root = root_dir
self.component_opts = component_options or []
self.component_opts = component_options or {}
self.instances = instances or {}
# Parts of the global runner context that we use
@ -146,29 +146,18 @@ class PkgInstallComponent(ComponentBase):
def _get_param_map(self, config_fn):
return dict()
def _get_pkgs(self):
return list()
def _get_pkgs_expanded(self):
short = self._get_pkgs()
if not short:
return dict()
pkgs = dict()
for fn in short:
full_name = sh.joinpths(settings.STACK_PKG_DIR, fn)
pkgs = utils.extract_pkg_list([full_name], self.distro.name, pkgs)
return pkgs
def install(self):
LOG.debug('Preparing to install packages for %s',
self.component_name)
pkgs = self._get_pkgs_expanded()
pkgs = self.component_opts.get('packages', [])
if pkgs:
pkgnames = sorted(pkgs.keys())
pkgnames = sorted([p['name'] for p in pkgs])
LOG.info("Installing packages (%s).", ", ".join(pkgnames))
# FIXME: We should only record the packages we actually
# install without error.
#do this before install just incase it craps out half way through
for name in pkgnames:
self.tracewriter.package_installed(name, pkgs.get(name))
for pkg in pkgs:
self.tracewriter.package_installed(p['name'], pkg)
#now actually install
self.packager.install_batch(pkgs)
else:
@ -177,13 +166,13 @@ class PkgInstallComponent(ComponentBase):
return self.tracedir
def pre_install(self):
pkgs = self._get_pkgs_expanded()
pkgs = self.component_opts.get('packages', [])
if pkgs:
mp = self._get_param_map(None)
self.packager.pre_install(pkgs, mp)
def post_install(self):
pkgs = self._get_pkgs_expanded()
pkgs = self.component_opts.get('packages', [])
if pkgs:
mp = self._get_param_map(None)
self.packager.post_install(pkgs, mp)

View File

@ -42,9 +42,6 @@ SQL_RESET_PW_LINKS = [
#used as a generic error message
BASE_ERROR = 'Currently we do not know how to [%s] for database type [%s]'
#the pkg json files db requires for installation
REQ_PKGS = ['db.json']
#config keys we warm up so u won't be prompted later
WARMUP_PWS = ['sql']
@ -126,9 +123,6 @@ class DBInstaller(comp.PkgInstallComponent):
self.distro.name
)
def _get_pkgs(self):
return list(REQ_PKGS)
def post_install(self):
comp.PkgInstallComponent.post_install(self)

View File

@ -78,9 +78,6 @@ SUB_TO_APP = {
CONFIG_DIR = 'etc'
BIN_DIR = 'bin'
#the pkg json files glance requires for installation
REQ_PKGS = ['general.json', 'glance.json']
#pip files that glance requires
REQ_PIPS = ['general.json', 'glance.json']
@ -110,9 +107,6 @@ class GlanceInstaller(comp.PythonInstallComponent):
def _get_pips(self):
return list(REQ_PIPS)
def _get_pkgs(self):
return list(REQ_PKGS)
def post_install(self):
comp.PythonInstallComponent.post_install(self)
self._setup_db()
@ -198,21 +192,11 @@ class GlanceRuntime(comp.PythonRuntime):
self.cfgdir = sh.joinpths(self.appdir, CONFIG_DIR)
def _get_apps_to_start(self):
apps = list()
if not self.component_opts:
for app_name in APP_OPTIONS.keys():
apps.append({
'name': app_name,
'path': sh.joinpths(self.appdir, BIN_DIR, app_name),
})
else:
for short_name in self.component_opts:
full_name = SUB_TO_APP.get(short_name)
if full_name and full_name in APP_OPTIONS:
apps.append({
'name': full_name,
'path': sh.joinpths(self.appdir, BIN_DIR, full_name),
})
apps = [{'name': app_name,
'path': sh.joinpths(self.appdir, BIN_DIR, app_name),
}
for app_name in APP_OPTIONS.keys()
]
return apps
def _get_app_options(self, app):
@ -220,9 +204,8 @@ class GlanceRuntime(comp.PythonRuntime):
def post_start(self):
comp.PythonRuntime.post_start(self)
if NO_IMG_START not in self.component_opts:
#install any images that need activating...
# TODO: make this less cheesy - need to wait till glance goes online
LOG.info("Waiting %s seconds so that glance can start up before image install." % (WAIT_ONLINE_TO))
sh.sleep(WAIT_ONLINE_TO)
creator.ImageCreationService(self.cfg, self.pw_gen).install()
#install any images that need activating...
# TODO: make this less cheesy - need to wait till glance goes online
LOG.info("Waiting %s seconds so that glance can start up before image install." % (WAIT_ONLINE_TO))
sh.sleep(WAIT_ONLINE_TO)
creator.ImageCreationService(self.cfg, self.pw_gen).install()

View File

@ -67,9 +67,6 @@ BAD_APACHE_USERS = ['root']
#apache logs will go here
LOGS_DIR = "logs"
#the pkg json files horizon requires for installation
REQ_PKGS = ['general.json', 'horizon.json']
#pip files that horizon requires
REQ_PIPS = ['general.json', 'horizon.json']
@ -121,9 +118,6 @@ class HorizonInstaller(comp.PythonInstallComponent):
msg = "You may want to adjust your configuration, (user=%s, group=%s) will not work with apache!" % (user, group)
raise excp.ConfigException(msg)
def _get_pkgs(self):
return list(REQ_PKGS)
def _get_pips(self):
return list(REQ_PIPS)

View File

@ -65,8 +65,6 @@ APP_OPTIONS = {
'--log-config=' + sh.joinpths('%ROOT%', CONFIG_DIR, 'logging.cnf')]
}
#the pkg json files keystone requires for installation
REQ_PKGS = ['general.json', 'keystone.json']
#pip files that keystone requires
REQ_PIPS = ['general.json', 'keystone.json']
@ -112,9 +110,6 @@ class KeystoneInstaller(comp.PythonInstallComponent):
def _get_pips(self):
return list(REQ_PIPS)
def _get_pkgs(self):
return list(REQ_PKGS)
def post_install(self):
comp.PythonInstallComponent.post_install(self)
self._setup_db()

View File

@ -23,7 +23,6 @@ TYPE = settings.KEYSTONE_CLIENT
LOG = logging.getLogger("devstack.components.keystone_client")
#the pkg json files keystone client requires for installation
REQ_PKGS = ['general.json', 'keystone-client.json']
REQ_PIPS = ['general.json']
@ -44,9 +43,6 @@ class KeyStoneClientInstaller(comp.PythonInstallComponent):
})
return places
def _get_pkgs(self):
return list(REQ_PKGS)
def _get_pips(self):
return list(REQ_PIPS)

View File

@ -30,9 +30,6 @@ from devstack.components import db
TYPE = settings.MELANGE
LOG = logging.getLogger("devstack.components.melange")
#the pkg json files melange requires for installation
REQ_PKGS = ['general.json', 'melange.json']
#this db will be dropped then created
DB_NAME = 'melange'
@ -92,9 +89,6 @@ class MelangeInstaller(comp.PythonInstallComponent):
db.drop_db(self.cfg, self.pw_gen, self.distro, DB_NAME)
db.create_db(self.cfg, self.pw_gen, self.distro, DB_NAME)
def _get_pkgs(self):
return list(REQ_PKGS)
def post_install(self):
comp.PythonInstallComponent.post_install(self)
self._setup_db()
@ -167,7 +161,9 @@ class MelangeRuntime(comp.PythonRuntime):
def post_start(self):
comp.PythonRuntime.post_start(self)
if CREATE_CIDR in self.component_opts or not self.component_opts:
# FIXME: This is a bit of a hack. How do we document "flags" like this?
flags = self.component_opts.get('flags', [])
if CREATE_CIDR in flags or not flags:
LOG.info("Waiting %s seconds so that the melange server can start up before cidr range creation." % (WAIT_ONLINE_TO))
sh.sleep(WAIT_ONLINE_TO)
mp = dict()

View File

@ -22,9 +22,6 @@ from devstack import settings
TYPE = settings.MELANGE_CLIENT
LOG = logging.getLogger("devstack.components.melange_client")
#the pkg json files melange client requires for installation
REQ_PKGS = ['general.json']
class MelangeClientUninstaller(comp.PythonUninstallComponent):
def __init__(self, *args, **kargs):
@ -43,9 +40,6 @@ class MelangeClientInstaller(comp.PythonInstallComponent):
})
return places
def _get_pkgs(self):
return list(REQ_PKGS)
class MelangeClientRuntime(comp.EmptyRuntime):
def __init__(self, *args, **kargs):

View File

@ -111,25 +111,6 @@ NXVNC = "xvnc"
SUBCOMPONENTS = [NCPU, NVOL, NAPI,
NOBJ, NNET, NCERT, NSCHED, NCAUTH, NXVNC]
#the pkg json files nova requires for installation
REQ_PKGS = ['general.json', 'nova.json']
# Additional packages for subcomponents
ADD_PKGS = {
NAPI:
[
'n-api.json',
],
NCPU:
[
'n-cpu.json',
],
NVOL:
[
'n-vol.json',
],
}
# What to start
APP_OPTIONS = {
#these are currently the core components/applications
@ -277,9 +258,8 @@ class NovaUninstaller(comp.PythonUninstallComponent):
def _clean_it(self):
#these environment additions are important
#in that they eventually affect how this script runs
sub_components = self.component_opts or SUBCOMPONENTS
env = dict()
env['ENABLED_SERVICES'] = ",".join(sub_components)
env['ENABLED_SERVICES'] = ",".join(SUBCOMPONENTS)
env['BIN_DIR'] = self.bindir
env['VOLUME_NAME_PREFIX'] = self.cfg.getdefaulted('nova', 'volume_name_prefix', DEF_VOL_PREFIX)
cleaner_fn = sh.joinpths(self.bindir, CLEANER_DATA_CONF)
@ -303,20 +283,15 @@ class NovaInstaller(comp.PythonInstallComponent):
self.cfgdir = sh.joinpths(self.appdir, CONFIG_DIR)
self.paste_conf_fn = self._get_target_config_name(PASTE_CONF)
self.volumes_enabled = False
if not self.component_opts or NVOL in self.component_opts:
package_names = [p['name']
for p in self.component_opts.get('packages', [])
]
if NVOL in package_names:
self.volumes_enabled = True
self.xvnc_enabled = False
if not self.component_opts or NXVNC in self.component_opts:
if NXVNC in package_names:
self.xvnc_enabled = True
def _get_pkgs(self):
pkgs = list(REQ_PKGS)
sub_components = self.component_opts or SUBCOMPONENTS
for c in sub_components:
fns = ADD_PKGS.get(c, [])
pkgs.extend(fns)
return pkgs
def _get_symlinks(self):
links = comp.PythonInstallComponent._get_symlinks(self)
source_fn = sh.joinpths(self.cfgdir, API_CONF)
@ -473,22 +448,11 @@ class NovaRuntime(comp.PythonRuntime):
return deps
def _get_apps_to_start(self):
result = list()
if not self.component_opts:
apps = sorted(APP_OPTIONS.keys())
for app_name in apps:
result.append({
'name': app_name,
'path': sh.joinpths(self.bindir, app_name),
})
else:
for short_name in self.component_opts:
full_name = SUB_COMPONENT_NAME_MAP.get(short_name)
if full_name and full_name in APP_OPTIONS:
result.append({
'name': full_name,
'path': sh.joinpths(self.bindir, full_name),
})
result = [{'name': app_name,
'path': sh.joinpths(self.bindir, app_name),
}
for app_name in sorted(APP_OPTIONS.keys())
]
return result
def pre_start(self):

View File

@ -23,7 +23,6 @@ TYPE = settings.NOVA_CLIENT
LOG = logging.getLogger("devstack.components.nova_client")
#the pkg json files nova client requires for installation
REQ_PKGS = ['general.json', 'nova-client.json']
REQ_PIPS = ['general.json']
@ -44,9 +43,6 @@ class NovaClientInstaller(comp.PythonInstallComponent):
})
return places
def _get_pkgs(self):
return list(REQ_PKGS)
def _get_pips(self):
return list(REQ_PIPS)

View File

@ -36,9 +36,6 @@ APP_OPTIONS = {
VNC_PROXY_APP: ['--flagfile', '%NOVA_CONF%', '--web', '.'],
}
#the pkg json files no-vnc requires for installation
REQ_PKGS = ['general.json', 'n-vnc.json']
#pip files that no-vnc requires
REQ_PIPS = ['general.json', 'n-vnc.json']
@ -63,9 +60,6 @@ class NoVNCInstaller(comp.PythonInstallComponent):
})
return places
def _get_pkgs(self):
return list(REQ_PKGS)
def _get_pips(self):
return list(REQ_PIPS)

View File

@ -69,9 +69,6 @@ APP_OPTIONS = {
APP_Q_AGENT: ["%OVS_CONFIG_FILE%", "-v"],
}
#the pkg json files quantum requires for installation
REQ_PKGS = ['general.json', 'quantum.json']
#pip files that nova requires
REQ_PIPS = ['quantum.json']
@ -88,16 +85,15 @@ class QuantumInstaller(comp.PkgInstallComponent):
self.q_vswitch_service = False
plugin = self.cfg.getdefaulted("quantum", "q_plugin", VSWITCH_PLUGIN)
if plugin == VSWITCH_PLUGIN:
if len(self.component_opts) == 0:
#default to on if not specified
self.q_vswitch_agent = True
self.q_vswitch_service = True
else:
#only turn on if requested
if QUANTUM_SERVICE in self.component_opts:
self.q_vswitch_service = True
if QUANTUM_AGENT in self.component_opts:
self.q_vswitch_agent = True
#default to on if not specified
self.q_vswitch_agent = True
self.q_vswitch_service = True
# else:
# #only turn on if requested
# if QUANTUM_SERVICE in self.component_opts:
# self.q_vswitch_service = True
# if QUANTUM_AGENT in self.component_opts:
# self.q_vswitch_agent = True
def _get_download_locations(self):
places = list()
@ -122,12 +118,6 @@ class QuantumInstaller(comp.PkgInstallComponent):
add_deps.append(settings.DB)
return common_deps + add_deps
def _get_pkgs(self):
pkglist = list(REQ_PKGS)
if self.q_vswitch_service:
pkglist.append(PKG_VSWITCH)
return pkglist
def _get_config_files(self):
return list(CONFIG_FILES)
@ -226,16 +216,15 @@ class QuantumRuntime(comp.ProgramRuntime):
self.q_vswitch_service = False
plugin = self.cfg.getdefaulted("quantum", "q_plugin", VSWITCH_PLUGIN)
if plugin == VSWITCH_PLUGIN:
if len(self.component_opts) == 0:
#default to on if not specified
self.q_vswitch_agent = True
self.q_vswitch_service = True
else:
#only turn on if requested
if QUANTUM_SERVICE in self.component_opts:
self.q_vswitch_service = True
if QUANTUM_AGENT in self.component_opts:
self.q_vswitch_agent = True
#default to on if not specified
self.q_vswitch_agent = True
self.q_vswitch_service = True
# else:
# #only turn on if requested
# if QUANTUM_SERVICE in self.component_opts:
# self.q_vswitch_service = True
# if QUANTUM_AGENT in self.component_opts:
# self.q_vswitch_agent = True
def _get_apps_to_start(self):
app_list = comp.ProgramRuntime._get_apps_to_start(self)

View File

@ -22,9 +22,6 @@ from devstack import settings
TYPE = settings.QUANTUM_CLIENT
LOG = logging.getLogger("devstack.components.quantum_client")
#the pkg json files quantum client requires for installation
REQ_PKGS = ['general.json', 'quantum-client.json']
class QuantumClientUninstaller(comp.PythonUninstallComponent):
def __init__(self, *args, **kargs):
@ -43,9 +40,6 @@ class QuantumClientInstaller(comp.PythonInstallComponent):
})
return places
def _get_pkgs(self):
return list(REQ_PKGS)
class QuantumClientRuntime(comp.EmptyRuntime):
def __init__(self, *args, **kargs):

View File

@ -32,9 +32,6 @@ STATUS_CMD = ['service', "rabbitmq-server", "status"]
RESTART_CMD = ['service', "rabbitmq-server", "restart"]
PWD_CMD = ['rabbitmqctl', 'change_password', 'guest']
#the pkg json files rabbit mq server requires for installation
REQ_PKGS = ['rabbitmq.json']
#default password
RESET_BASE_PW = ''
@ -86,9 +83,6 @@ class RabbitInstaller(comp.PkgInstallComponent):
comp.PkgInstallComponent.post_install(self)
self._setup_pw()
def _get_pkgs(self):
return list(REQ_PKGS)
class RabbitRuntime(comp.EmptyRuntime):
def __init__(self, *args, **kargs):

View File

@ -64,9 +64,6 @@ BIN_DIR = 'bin'
CONFIG_DIR = 'etc'
LOG_DIR = 'logs'
#the pkg json files swift requires for installation
REQ_PKGS = ['general.json', 'swift.json']
#config keys we warm up so u won't be prompted later
WARMUP_PWS = ['service_token', 'swift_hash']
@ -112,9 +109,6 @@ class SwiftInstaller(comp.PythonInstallComponent):
def _get_config_files(self):
return list(CONFIGS)
def _get_pkgs(self):
return list(REQ_PKGS)
def warm_configs(self):
for pw_key in WARMUP_PWS:
self.cfg.get("passwords", pw_key)

View File

@ -35,21 +35,19 @@ class Packager(object):
return []
def pre_install(self, pkgs, installparams=None):
pkgnames = sorted(pkgs.keys())
for name in pkgnames:
packageinfo = pkgs.get(name)
for packageinfo in pkgs:
preinstallcmds = packageinfo.get(settings.PRE_INSTALL)
if preinstallcmds and len(preinstallcmds):
LOG.info("Running pre-install commands for package %s." % (name))
if preinstallcmds:
LOG.info("Running pre-install commands for package %s.",
packageinfo['name'])
utils.execute_template(*preinstallcmds, params=installparams)
def post_install(self, pkgs, installparams=None):
pkgnames = sorted(pkgs.keys())
for name in pkgnames:
packageinfo = pkgs.get(name)
for packageinfo in pkgs:
postinstallcmds = packageinfo.get(settings.POST_INSTALL)
if postinstallcmds and len(postinstallcmds):
LOG.info("Running post-install commands for package %s." % (name))
LOG.info("Running post-install commands for package %s.",
packageinfo['name'])
utils.execute_template(*postinstallcmds, params=installparams)
def _remove_batch(self, pkgs):

View File

@ -60,12 +60,11 @@ class AptPackager(pack.Packager):
**kargs)
def _remove_batch(self, pkgs):
pkgnames = sorted(pkgs.keys())
#form the needed commands
cmds = []
which_removed = []
for name in pkgnames:
info = pkgs.get(name) or {}
for info in pkgs:
name = info['name']
removable = info.get('removable', True)
if not removable:
continue
@ -86,11 +85,10 @@ class AptPackager(pack.Packager):
return which_removed
def install_batch(self, pkgs):
pkgnames = sorted(pkgs.keys())
#form the needed commands
cmds = []
for name in pkgnames:
info = pkgs.get(name) or {}
for info in pkgs:
name = info['name']
if self._pkg_install_special(name, info):
continue
pkg_full = self._format_pkg(name, info.get("version"))

View File

@ -89,10 +89,9 @@ class YumPackager(pack.Packager):
return False
def install_batch(self, pkgs):
pkg_names = sorted(pkgs.keys())
pkg_full_names = []
for name in pkg_names:
info = pkgs.get(name) or {}
for info in pkgs:
name = info['name']
if self._install_special(name, info):
continue
full_pkg_name = self._format_pkg_name(name, info.get("version"))
@ -102,10 +101,10 @@ class YumPackager(pack.Packager):
self._execute_yum(cmd)
def _remove_batch(self, pkgs):
pkg_names = sorted(pkgs.keys())
pkg_full_names = []
which_removed = []
for name in pkg_names:
for info in pkgs:
name = info['name']
info = pkgs.get(name) or {}
removable = info.get('removable', True)
if not removable:

View File

@ -193,17 +193,18 @@ class ActionRunner(object):
adjusted_components[c] = ref_components.get(c)
return adjusted_components
def _instanciate_components(self, components):
def _instantiate_components(self, components):
all_instances = dict()
for component in components.keys():
cls = self.distro.get_component_action_class(component, self.action)
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=components.get(component),
component_options=self.distro.components[component],
keep_old=self.kargs.get("keep_old")
)
all_instances[component] = instance
@ -213,7 +214,7 @@ class ActionRunner(object):
if not (self.action in PREQ_ACTIONS):
return
(check_functor, preq_action) = PREQ_ACTIONS[self.action]
instances = self._instanciate_components(components)
instances = self._instantiate_components(components)
preq_components = dict()
for c in component_order:
instance = instances[c]
@ -278,7 +279,7 @@ class ActionRunner(object):
def _start(self, components, component_order):
LOG.info("Activating components required to complete action [%s]" % (self.action))
instances = self._instanciate_components(components)
instances = self._instantiate_components(components)
self._pre_run(instances, component_order)
self._run_preqs(components, component_order)
self._run_instances(instances, component_order)