Large update to re juggle how dependencies are resolved.
This time not using priorities but a true topo sort. Also removed pkg listings and pip listings from settings and moved them to there individual components. Split up the 2 programs, one for listing deps and one for describing components into 2 programs.
This commit is contained in:
parent
b6c22ea16e
commit
8fd53948df
@ -43,15 +43,20 @@ class ComponentBase(object):
|
||||
self.cfg = kargs.get("config")
|
||||
self.packager = kargs.get("packager")
|
||||
self.distro = kargs.get("distro")
|
||||
self.component_name = component_name
|
||||
self.instances = kargs.get("instances", set())
|
||||
self.component_opts = kargs.get('opts', list())
|
||||
self.root = kargs.get("root")
|
||||
self.instances = kargs.get("instances")
|
||||
self.component_opts = kargs.get('opts')
|
||||
self.component_root = sh.joinpths(self.root, component_name)
|
||||
self.tracedir = sh.joinpths(self.component_root, settings.COMPONENT_TRACE_DIR)
|
||||
self.appdir = sh.joinpths(self.component_root, settings.COMPONENT_APP_DIR)
|
||||
self.cfgdir = sh.joinpths(self.component_root, settings.COMPONENT_CONFIG_DIR)
|
||||
self.component_name = component_name
|
||||
|
||||
def get_dependencies(self):
|
||||
deps = settings.COMPONENT_DEPENDENCIES.get(self.component_name)
|
||||
if not deps:
|
||||
return list()
|
||||
return list(deps)
|
||||
|
||||
class PkgInstallComponent(ComponentBase):
|
||||
def __init__(self, component_name, *args, **kargs):
|
||||
@ -85,11 +90,11 @@ class PkgInstallComponent(ComponentBase):
|
||||
def _get_param_map(self, config_fn):
|
||||
return None
|
||||
|
||||
def _get_pkglist(self):
|
||||
return utils.get_pkg_list(self.distro, self.component_name)
|
||||
def _get_pkgs(self):
|
||||
return dict()
|
||||
|
||||
def install(self):
|
||||
pkgs = self._get_pkglist()
|
||||
pkgs = self._get_pkgs()
|
||||
if pkgs:
|
||||
pkgnames = sorted(pkgs.keys())
|
||||
LOG.info("Installing packages (%s)." % (", ".join(pkgnames)))
|
||||
@ -100,14 +105,14 @@ class PkgInstallComponent(ComponentBase):
|
||||
return self.tracedir
|
||||
|
||||
def pre_install(self):
|
||||
pkgs = utils.get_pkg_list(self.distro, self.component_name)
|
||||
pkgs = self._get_pkgs()
|
||||
if pkgs:
|
||||
mp = self._get_param_map(None)
|
||||
self.packager.pre_install(pkgs, mp)
|
||||
return self.tracedir
|
||||
|
||||
def post_install(self):
|
||||
pkgs = utils.get_pkg_list(self.distro, self.component_name)
|
||||
pkgs = self._get_pkgs()
|
||||
if pkgs:
|
||||
mp = self._get_param_map(None)
|
||||
self.packager.post_install(pkgs, mp)
|
||||
@ -167,12 +172,12 @@ class PythonInstallComponent(PkgInstallComponent):
|
||||
})
|
||||
return py_dirs
|
||||
|
||||
def _get_pip_list(self):
|
||||
return utils.get_pip_list(self.distro, self.component_name)
|
||||
def _get_pips(self):
|
||||
return dict()
|
||||
|
||||
def _install_pips(self):
|
||||
#install any need pip items
|
||||
pips = self._get_pip_list()
|
||||
pips = self._get_pips()
|
||||
if pips:
|
||||
LOG.info("Setting up %s pips (%s)" % (len(pips), ", ".join(pips.keys())))
|
||||
pip.install(pips)
|
||||
|
@ -15,14 +15,13 @@
|
||||
# under the License.
|
||||
|
||||
from devstack import component as comp
|
||||
from devstack import settings
|
||||
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 trace as tr
|
||||
from devstack import utils
|
||||
|
||||
|
||||
LOG = logging.getLogger("devstack.components.db")
|
||||
|
||||
#id
|
||||
@ -57,6 +56,9 @@ BASE_ERROR = 'Currently we do not know how to %s for database type [%s]'
|
||||
#used to make params for booting when started (not always take advantage of...)
|
||||
BOOLEAN_OUTPUT = {True: 'true', False: 'false'}
|
||||
|
||||
#the pkg json files db requires for installation
|
||||
REQ_PKGS = ['db.json']
|
||||
|
||||
|
||||
class DBUninstaller(comp.PkgUninstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
@ -80,6 +82,13 @@ class DBInstaller(comp.PkgInstallComponent):
|
||||
out['HOST_IP'] = host_ip
|
||||
return out
|
||||
|
||||
def _get_pkgs(self):
|
||||
pkgs = comp.PkgInstallComponent._get_pkgs(self)
|
||||
for fn in REQ_PKGS:
|
||||
full_name = sh.joinpths(settings.STACK_PKG_DIR, fn)
|
||||
pkgs = utils.extract_pkg_list([full_name], self.distro, pkgs)
|
||||
return pkgs
|
||||
|
||||
def post_install(self):
|
||||
parent_result = comp.PkgInstallComponent.post_install(self)
|
||||
#extra actions to ensure we are granted access
|
||||
|
@ -21,8 +21,11 @@ from devstack import component as comp
|
||||
from devstack import log as logging
|
||||
from devstack import settings
|
||||
from devstack import shell as sh
|
||||
from devstack import utils
|
||||
|
||||
from devstack.components import db
|
||||
from devstack.components import keystone
|
||||
|
||||
from devstack.image import creator
|
||||
|
||||
LOG = logging.getLogger("devstack.components.glance")
|
||||
@ -64,6 +67,9 @@ SUB_TO_APP = {
|
||||
CONFIG_DIR = 'etc'
|
||||
BIN_DIR = 'bin'
|
||||
|
||||
#the pkg json files glance requires for installation
|
||||
REQ_PKGS = ['general.json', 'glance.json']
|
||||
|
||||
|
||||
class GlanceUninstaller(comp.PythonUninstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
@ -71,39 +77,6 @@ class GlanceUninstaller(comp.PythonUninstallComponent):
|
||||
self.cfgdir = sh.joinpths(self.appdir, CONFIG_DIR)
|
||||
|
||||
|
||||
class GlanceRuntime(comp.PythonRuntime):
|
||||
def __init__(self, *args, **kargs):
|
||||
comp.PythonRuntime.__init__(self, TYPE, *args, **kargs)
|
||||
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),
|
||||
})
|
||||
return apps
|
||||
|
||||
def _get_app_options(self, app):
|
||||
return APP_OPTIONS.get(app)
|
||||
|
||||
def post_start(self):
|
||||
comp.PythonRuntime.post_start(self)
|
||||
if NO_IMG_START not in self.component_opts:
|
||||
#install any images that need activating...
|
||||
creator.ImageCreationService(self.cfg).install()
|
||||
|
||||
|
||||
class GlanceInstaller(comp.PythonInstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
comp.PythonInstallComponent.__init__(self, TYPE, *args, **kargs)
|
||||
@ -123,6 +96,13 @@ class GlanceInstaller(comp.PythonInstallComponent):
|
||||
#these are the config files we will be adjusting
|
||||
return list(CONFIGS)
|
||||
|
||||
def _get_pkgs(self):
|
||||
pkgs = comp.PythonInstallComponent._get_pkgs(self)
|
||||
for fn in REQ_PKGS:
|
||||
full_name = sh.joinpths(settings.STACK_PKG_DIR, fn)
|
||||
pkgs = utils.extract_pkg_list([full_name], self.distro, pkgs)
|
||||
return pkgs
|
||||
|
||||
def post_install(self):
|
||||
parent_result = comp.PythonInstallComponent.post_install(self)
|
||||
self._setup_db()
|
||||
@ -193,6 +173,39 @@ class GlanceInstaller(comp.PythonInstallComponent):
|
||||
return mp
|
||||
|
||||
|
||||
class GlanceRuntime(comp.PythonRuntime):
|
||||
def __init__(self, *args, **kargs):
|
||||
comp.PythonRuntime.__init__(self, TYPE, *args, **kargs)
|
||||
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),
|
||||
})
|
||||
return apps
|
||||
|
||||
def _get_app_options(self, app):
|
||||
return APP_OPTIONS.get(app)
|
||||
|
||||
def post_start(self):
|
||||
comp.PythonRuntime.post_start(self)
|
||||
if NO_IMG_START not in self.component_opts:
|
||||
#install any images that need activating...
|
||||
creator.ImageCreationService(self.cfg).install()
|
||||
|
||||
|
||||
def describe(opts=None):
|
||||
description = """
|
||||
Module: {module_name}
|
||||
@ -203,9 +216,12 @@ def describe(opts=None):
|
||||
"""
|
||||
copts = """
|
||||
{no_img_upload} - disables upload of test images to glance.
|
||||
{glance_api} - only enable the glance api subcomponent.
|
||||
{glance_reg} - only enable the glance registry subcomponent.
|
||||
"""
|
||||
params = dict()
|
||||
params['component_opts'] = copts.strip("\n").format(no_img_upload=NO_IMG_START)
|
||||
params['component_opts'] = copts.strip("\n").format(no_img_upload=NO_IMG_START,
|
||||
glance_api=GAPI, glance_reg=GREG)
|
||||
params['module_name'] = __name__
|
||||
params['description'] = __doc__ or "Handles actions for the glance component."
|
||||
out = description.format(**params)
|
||||
|
@ -20,6 +20,7 @@ from devstack import component as comp
|
||||
from devstack import log as logging
|
||||
from devstack import settings
|
||||
from devstack import shell as sh
|
||||
from devstack import utils
|
||||
|
||||
#id
|
||||
TYPE = settings.HORIZON
|
||||
@ -54,6 +55,12 @@ BAD_APACHE_USERS = ['root']
|
||||
|
||||
LOG = logging.getLogger("devstack.components.horizon")
|
||||
|
||||
#the pkg json files horizon requires for installation
|
||||
REQ_PKGS = ['general.json', 'horizon.json']
|
||||
|
||||
#pip files that horizon requires
|
||||
REQ_PIPS = ['horizon.json']
|
||||
|
||||
|
||||
class HorizonUninstaller(comp.PythonUninstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
@ -76,6 +83,20 @@ class HorizonInstaller(comp.PythonInstallComponent):
|
||||
})
|
||||
return places
|
||||
|
||||
def _get_pkgs(self):
|
||||
pkgs = comp.PythonInstallComponent._get_pkgs(self)
|
||||
for fn in REQ_PKGS:
|
||||
full_name = sh.joinpths(settings.STACK_PKG_DIR, fn)
|
||||
pkgs = utils.extract_pkg_list([full_name], self.distro, pkgs)
|
||||
return pkgs
|
||||
|
||||
def _get_pips(self):
|
||||
pips = comp.PythonInstallComponent._get_pips(self)
|
||||
for fn in REQ_PIPS:
|
||||
full_name = sh.joinpths(settings.STACK_PIP_DIR, fn)
|
||||
pips = utils.extract_pip_list([full_name], self.distro, pips)
|
||||
return pips
|
||||
|
||||
def _get_target_config_name(self, config_name):
|
||||
if config_name == HORIZON_PY_CONF:
|
||||
return sh.joinpths(self.dash_dir, *HORIZON_PY_CONF_TGT)
|
||||
|
@ -22,6 +22,7 @@ from devstack import log as logging
|
||||
from devstack import settings
|
||||
from devstack import shell as sh
|
||||
from devstack import utils
|
||||
|
||||
from devstack.components import db
|
||||
|
||||
LOG = logging.getLogger("devstack.components.keystone")
|
||||
@ -55,6 +56,12 @@ 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 horizon requires
|
||||
REQ_PIPS = ['keystone.json']
|
||||
|
||||
|
||||
class KeystoneUninstaller(comp.PythonUninstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
@ -79,6 +86,20 @@ class KeystoneInstaller(comp.PythonInstallComponent):
|
||||
})
|
||||
return places
|
||||
|
||||
def _get_pips(self):
|
||||
pips = comp.PythonInstallComponent._get_pips(self)
|
||||
for fn in REQ_PIPS:
|
||||
full_name = sh.joinpths(settings.STACK_PIP_DIR, fn)
|
||||
pips = utils.extract_pip_list([full_name], self.distro, pips)
|
||||
return pips
|
||||
|
||||
def _get_pkgs(self):
|
||||
pkgs = comp.PythonInstallComponent._get_pkgs(self)
|
||||
for fn in REQ_PKGS:
|
||||
full_name = sh.joinpths(settings.STACK_PKG_DIR, fn)
|
||||
pkgs = utils.extract_pkg_list([full_name], self.distro, pkgs)
|
||||
return pkgs
|
||||
|
||||
def post_install(self):
|
||||
parent_result = comp.PythonInstallComponent.post_install(self)
|
||||
self._setup_db()
|
||||
@ -184,22 +205,22 @@ class KeystoneRuntime(comp.PythonRuntime):
|
||||
return APP_OPTIONS.get(app)
|
||||
|
||||
|
||||
def get_shared_params(cfg):
|
||||
def get_shared_params(config):
|
||||
mp = dict()
|
||||
host_ip = cfg.get('host', 'ip')
|
||||
keystone_auth_host = cfg.get('keystone', 'keystone_auth_host')
|
||||
host_ip = config.get('host', 'ip')
|
||||
keystone_auth_host = config.get('keystone', 'keystone_auth_host')
|
||||
if not keystone_auth_host:
|
||||
keystone_auth_host = host_ip
|
||||
mp['KEYSTONE_AUTH_HOST'] = keystone_auth_host
|
||||
mp['KEYSTONE_AUTH_PORT'] = cfg.get('keystone', 'keystone_auth_port')
|
||||
mp['KEYSTONE_AUTH_PROTOCOL'] = cfg.get('keystone', 'keystone_auth_protocol')
|
||||
keystone_service_host = cfg.get('keystone', 'keystone_service_host')
|
||||
mp['KEYSTONE_AUTH_PORT'] = config.get('keystone', 'keystone_auth_port')
|
||||
mp['KEYSTONE_AUTH_PROTOCOL'] = config.get('keystone', 'keystone_auth_protocol')
|
||||
keystone_service_host = config.get('keystone', 'keystone_service_host')
|
||||
if not keystone_service_host:
|
||||
keystone_service_host = host_ip
|
||||
mp['KEYSTONE_SERVICE_HOST'] = keystone_service_host
|
||||
mp['KEYSTONE_SERVICE_PORT'] = cfg.get('keystone', 'keystone_service_port')
|
||||
mp['KEYSTONE_SERVICE_PROTOCOL'] = cfg.get('keystone', 'keystone_service_protocol')
|
||||
mp['SERVICE_TOKEN'] = cfg.get("passwords", "service_token")
|
||||
mp['KEYSTONE_SERVICE_PORT'] = config.get('keystone', 'keystone_service_port')
|
||||
mp['KEYSTONE_SERVICE_PROTOCOL'] = config.get('keystone', 'keystone_service_protocol')
|
||||
mp['SERVICE_TOKEN'] = config.get("passwords", "service_token")
|
||||
return mp
|
||||
|
||||
|
||||
|
@ -17,12 +17,17 @@
|
||||
from devstack import component as comp
|
||||
from devstack import log as logging
|
||||
from devstack import settings
|
||||
from devstack import shell as sh
|
||||
from devstack import utils
|
||||
|
||||
LOG = logging.getLogger("devstack.components.keystone_client")
|
||||
|
||||
#id
|
||||
TYPE = settings.KEYSTONE_CLIENT
|
||||
|
||||
#the pkg json files keystone client requires for installation
|
||||
REQ_PKGS = ['general.json', 'keystone-client.json']
|
||||
|
||||
|
||||
class KeyStoneClientUninstaller(comp.PythonUninstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
@ -43,6 +48,13 @@ class KeyStoneClientInstaller(comp.PythonInstallComponent):
|
||||
})
|
||||
return places
|
||||
|
||||
def _get_pkgs(self):
|
||||
pkgs = comp.PythonInstallComponent._get_pkgs(self)
|
||||
for fn in REQ_PKGS:
|
||||
full_name = sh.joinpths(settings.STACK_PKG_DIR, fn)
|
||||
pkgs = utils.extract_pkg_list([full_name], self.distro, pkgs)
|
||||
return pkgs
|
||||
|
||||
|
||||
class KeyStoneClientRuntime(comp.EmptyRuntime):
|
||||
def __init__(self, *args, **kargs):
|
||||
|
@ -23,6 +23,7 @@ from devstack import log as logging
|
||||
from devstack import settings
|
||||
from devstack import shell as sh
|
||||
from devstack import utils
|
||||
|
||||
from devstack.components import db
|
||||
from devstack.components import keystone
|
||||
|
||||
@ -98,19 +99,23 @@ NCAUTH = "cauth"
|
||||
SUBCOMPONENTS = [NCPU, NVOL, NAPI,
|
||||
NOBJ, NNET, NCERT, NSCHED, NCAUTH]
|
||||
|
||||
|
||||
#the pkg json files nova requires for installation
|
||||
REQ_PKGS = ['general.json', 'nova.json']
|
||||
|
||||
# Additional packages for subcomponents
|
||||
ADD_PKGS = {
|
||||
NAPI:
|
||||
[
|
||||
sh.joinpths(settings.STACK_PKG_DIR, 'n-api.json'),
|
||||
'n-api.json',
|
||||
],
|
||||
NCPU:
|
||||
[
|
||||
sh.joinpths(settings.STACK_PKG_DIR, 'n-cpu.json'),
|
||||
'n-cpu.json',
|
||||
],
|
||||
NVOL:
|
||||
[
|
||||
sh.joinpths(settings.STACK_PKG_DIR, 'n-vol.json'),
|
||||
'n-vol.json',
|
||||
],
|
||||
}
|
||||
|
||||
@ -181,22 +186,26 @@ class NovaInstaller(comp.PythonInstallComponent):
|
||||
self.bindir = sh.joinpths(self.appdir, BIN_DIR)
|
||||
self.paste_conf_fn = self._get_target_config_name(PASTE_CONF)
|
||||
|
||||
def _get_pkglist(self):
|
||||
pkgs = comp.PythonInstallComponent._get_pkglist(self)
|
||||
def _get_pkgs(self):
|
||||
pkgs = comp.PythonInstallComponent._get_pkgs(self)
|
||||
# Get the core pkgs
|
||||
for fn in REQ_PKGS:
|
||||
full_name = sh.joinpths(settings.STACK_PKG_DIR, fn)
|
||||
pkgs = utils.extract_pkg_list([full_name], self.distro, pkgs)
|
||||
# Walk through the subcomponents (like 'vol' and 'cpu') and add those
|
||||
# those packages as well. Let utils.get_pkglist handle any missing
|
||||
# entries
|
||||
# those packages as well.
|
||||
sub_components = []
|
||||
if self.component_opts:
|
||||
sub_components = self.component_opts
|
||||
else:
|
||||
# No subcomponents where explicitly specified, so get all
|
||||
sub_components = SUBCOMPONENTS
|
||||
LOG.debug("Explicit extras: %s" % (sub_components))
|
||||
# Add the extra dependencies
|
||||
for cname in sub_components:
|
||||
subpkgsfns = ADD_PKGS.get(cname)
|
||||
if subpkgsfns:
|
||||
pkgs = utils.extract_pkg_list(subpkgsfns, self.distro, pkgs)
|
||||
for c in sub_components:
|
||||
fns = ADD_PKGS.get(c)
|
||||
if fns:
|
||||
for fn in fns:
|
||||
full_name = sh.joinpths(settings.STACK_PKG_DIR, fn)
|
||||
pkgs = utils.extract_pkg_list([full_name], self.distro, pkgs)
|
||||
return pkgs
|
||||
|
||||
def _get_download_locations(self):
|
||||
|
@ -17,12 +17,17 @@
|
||||
from devstack import component as comp
|
||||
from devstack import log as logging
|
||||
from devstack import settings
|
||||
from devstack import shell as sh
|
||||
from devstack import utils
|
||||
|
||||
LOG = logging.getLogger("devstack.components.nova_client")
|
||||
|
||||
#id
|
||||
TYPE = settings.NOVA_CLIENT
|
||||
|
||||
#the pkg json files nova client requires for installation
|
||||
REQ_PKGS = ['general.json', 'nova-client.json']
|
||||
|
||||
|
||||
class NovaClientUninstaller(comp.PythonUninstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
@ -43,6 +48,13 @@ class NovaClientInstaller(comp.PythonInstallComponent):
|
||||
})
|
||||
return places
|
||||
|
||||
def _get_pkgs(self):
|
||||
pkgs = comp.PythonInstallComponent._get_pkgs(self)
|
||||
for fn in REQ_PKGS:
|
||||
full_name = sh.joinpths(settings.STACK_PKG_DIR, fn)
|
||||
pkgs = utils.extract_pkg_list([full_name], self.distro, pkgs)
|
||||
return pkgs
|
||||
|
||||
|
||||
class NovaClientRuntime(comp.EmptyRuntime):
|
||||
def __init__(self, *args, **kargs):
|
||||
|
@ -18,6 +18,7 @@ from devstack import component as comp
|
||||
from devstack import log as logging
|
||||
from devstack import settings
|
||||
from devstack import shell as sh
|
||||
|
||||
from devstack.components import nova
|
||||
|
||||
LOG = logging.getLogger("devstack.components.novnc")
|
||||
@ -35,6 +36,9 @@ APP_OPTIONS = {
|
||||
VNC_PROXY_APP: ['--flagfile-file', '%NOVA_CONF%', '--web'],
|
||||
}
|
||||
|
||||
#the pkg json files novnc requires for installation
|
||||
REQ_PKGS = ['n-vnc.json']
|
||||
|
||||
|
||||
class NoVNCUninstaller(comp.PkgUninstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
@ -55,6 +59,13 @@ class NoVNCInstaller(comp.PkgInstallComponent):
|
||||
})
|
||||
return places
|
||||
|
||||
def _get_pkgs(self):
|
||||
pkgs = comp.PkgInstallComponent._get_pkgs(self)
|
||||
for fn in REQ_PKGS:
|
||||
full_name = sh.joinpths(settings.STACK_PKG_DIR, fn)
|
||||
pkgs = utils.extract_pkg_list([full_name], self.distro, pkgs)
|
||||
return pkgs
|
||||
|
||||
|
||||
class NoVNCRuntime(comp.ProgramRuntime):
|
||||
def __init__(self, *args, **kargs):
|
||||
|
@ -17,12 +17,17 @@
|
||||
from devstack import component as comp
|
||||
from devstack import log as logging
|
||||
from devstack import settings
|
||||
from devstack import shell as sh
|
||||
from devstack import utils
|
||||
|
||||
LOG = logging.getLogger("devstack.components.openstackx")
|
||||
|
||||
#id
|
||||
TYPE = settings.OPENSTACK_X
|
||||
|
||||
#the pkg json files novnc requires for installation
|
||||
REQ_PKGS = ['general.json', 'openstackx.json']
|
||||
|
||||
|
||||
class OpenstackXUninstaller(comp.PythonUninstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
@ -43,6 +48,13 @@ class OpenstackXInstaller(comp.PythonInstallComponent):
|
||||
})
|
||||
return places
|
||||
|
||||
def _get_pkgs(self):
|
||||
pkgs = comp.PythonInstallComponent._get_pkgs(self)
|
||||
for fn in REQ_PKGS:
|
||||
full_name = sh.joinpths(settings.STACK_PKG_DIR, fn)
|
||||
pkgs = utils.extract_pkg_list([full_name], self.distro, pkgs)
|
||||
return pkgs
|
||||
|
||||
|
||||
class OpenstackXRuntime(comp.EmptyRuntime):
|
||||
def __init__(self, *args, **kargs):
|
||||
|
@ -22,6 +22,7 @@ from devstack import log as logging
|
||||
from devstack import settings
|
||||
from devstack import shell as sh
|
||||
from devstack import utils
|
||||
|
||||
from devstack.components import db
|
||||
|
||||
LOG = logging.getLogger("devstack.components.quantum")
|
||||
@ -67,6 +68,9 @@ APP_OPTIONS = {
|
||||
APP_Q_AGENT: ["%OVS_CONFIG_FILE%", "-v"],
|
||||
}
|
||||
|
||||
#the pkg json files quantum requires for installation
|
||||
REQ_PKGS = ['general.json', 'quantum.json']
|
||||
|
||||
|
||||
class QuantumUninstaller(comp.PkgUninstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
@ -101,8 +105,11 @@ class QuantumInstaller(comp.PkgInstallComponent):
|
||||
})
|
||||
return places
|
||||
|
||||
def _get_pkglist(self):
|
||||
pkglist = comp.PkgInstallComponent._get_pkglist(self)
|
||||
def _get_pkgs(self):
|
||||
pkglist = comp.PkgInstallComponent._get_pkgs(self)
|
||||
for fn in REQ_PKGS:
|
||||
full_name = sh.joinpths(settings.STACK_PKG_DIR, fn)
|
||||
pkglist = utils.extract_pkg_list([full_name], self.distro, pkglist)
|
||||
if self.q_vswitch_service:
|
||||
listing_fn = sh.joinpths(settings.STACK_PKG_DIR, PKG_VSWITCH)
|
||||
pkglist = utils.extract_pkg_list([listing_fn], self.distro, pkglist)
|
||||
|
@ -17,12 +17,17 @@
|
||||
from devstack import component as comp
|
||||
from devstack import log as logging
|
||||
from devstack import settings
|
||||
from devstack import shell as sh
|
||||
from devstack import utils
|
||||
|
||||
LOG = logging.getLogger("devstack.components.quantum_client")
|
||||
|
||||
#id
|
||||
TYPE = settings.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,6 +48,13 @@ class QuantumClientInstaller(comp.PythonInstallComponent):
|
||||
})
|
||||
return places
|
||||
|
||||
def _get_pkgs(self):
|
||||
pkgs = comp.PythonInstallComponent._get_pkgs(self)
|
||||
for fn in REQ_PKGS:
|
||||
full_name = sh.joinpths(settings.STACK_PKG_DIR, fn)
|
||||
pkgs = utils.extract_pkg_list([full_name], self.distro, pkgs)
|
||||
return pkgs
|
||||
|
||||
|
||||
class QuantumClientRuntime(comp.EmptyRuntime):
|
||||
def __init__(self, *args, **kargs):
|
||||
|
@ -22,6 +22,7 @@ from devstack import log as logging
|
||||
from devstack import settings
|
||||
from devstack import shell as sh
|
||||
from devstack import trace as tr
|
||||
from devstack import utils
|
||||
|
||||
LOG = logging.getLogger("devstack.components.rabbit")
|
||||
|
||||
@ -35,6 +36,9 @@ 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']
|
||||
|
||||
|
||||
class RabbitUninstaller(comp.PkgUninstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
@ -57,6 +61,13 @@ class RabbitInstaller(comp.PkgInstallComponent):
|
||||
self.runtime.restart()
|
||||
return parent_result
|
||||
|
||||
def _get_pkgs(self):
|
||||
pkgs = comp.PkgInstallComponent._get_pkgs(self)
|
||||
for fn in REQ_PKGS:
|
||||
full_name = sh.joinpths(settings.STACK_PKG_DIR, fn)
|
||||
pkgs = utils.extract_pkg_list([full_name], self.distro, pkgs)
|
||||
return pkgs
|
||||
|
||||
|
||||
class RabbitRuntime(comp.EmptyRuntime):
|
||||
def __init__(self, *args, **kargs):
|
||||
|
@ -26,9 +26,9 @@ LOG = logging.getLogger("devstack.components.swift")
|
||||
TYPE = settings.SWIFT
|
||||
|
||||
|
||||
class SwiftUninstaller(object):
|
||||
class SwiftUninstaller(comp.ComponentBase):
|
||||
def __init__(self, *args, **kargs):
|
||||
pass
|
||||
comp.ComponentBase.__init__(self, TYPE, *args, **kargs)
|
||||
|
||||
def unconfigure(self):
|
||||
raise NotImplementedError()
|
||||
@ -37,9 +37,9 @@ class SwiftUninstaller(object):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class SwiftInstaller(object):
|
||||
class SwiftInstaller(comp.ComponentBase):
|
||||
def __init__(self, *args, **kargs):
|
||||
pass
|
||||
comp.ComponentBase.__init__(self, TYPE, *args, **kargs)
|
||||
|
||||
def download(self):
|
||||
raise NotImplementedError()
|
||||
|
@ -27,6 +27,10 @@ class BadRegexException(StackException):
|
||||
pass
|
||||
|
||||
|
||||
class DependencyException(StackException):
|
||||
pass
|
||||
|
||||
|
||||
class BadParamException(StackException):
|
||||
pass
|
||||
|
||||
|
@ -26,23 +26,11 @@ from devstack import settings
|
||||
from devstack import shell as sh
|
||||
from devstack import utils
|
||||
|
||||
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 nova
|
||||
from devstack.components import nova_client
|
||||
from devstack.components import novnc
|
||||
from devstack.components import openstack_x
|
||||
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
|
||||
|
||||
from devstack.progs import common
|
||||
|
||||
LOG = logging.getLogger("devstack.progs.actions")
|
||||
|
||||
#this map controls which distro has
|
||||
@ -64,71 +52,6 @@ _WELCOME_MAP = {
|
||||
# For actions in this list we will reverse the component order
|
||||
_REVERSE_ACTIONS = [settings.UNINSTALL, settings.STOP]
|
||||
|
||||
# This determines what classes to use to install/uninstall/...
|
||||
_ACTION_CLASSES = {
|
||||
settings.INSTALL: {
|
||||
settings.NOVA: nova.NovaInstaller,
|
||||
settings.GLANCE: glance.GlanceInstaller,
|
||||
settings.QUANTUM: quantum.QuantumInstaller,
|
||||
settings.SWIFT: swift.SwiftInstaller,
|
||||
settings.HORIZON: horizon.HorizonInstaller,
|
||||
settings.KEYSTONE: keystone.KeystoneInstaller,
|
||||
settings.DB: db.DBInstaller,
|
||||
settings.RABBIT: rabbit.RabbitInstaller,
|
||||
settings.KEYSTONE_CLIENT: keystone_client.KeyStoneClientInstaller,
|
||||
settings.NOVA_CLIENT: nova_client.NovaClientInstaller,
|
||||
settings.OPENSTACK_X: openstack_x.OpenstackXInstaller,
|
||||
settings.NOVNC: novnc.NoVNCInstaller,
|
||||
settings.QUANTUM_CLIENT: quantum_client.QuantumClientInstaller,
|
||||
},
|
||||
settings.UNINSTALL: {
|
||||
settings.NOVA: nova.NovaUninstaller,
|
||||
settings.GLANCE: glance.GlanceUninstaller,
|
||||
settings.QUANTUM: quantum.QuantumUninstaller,
|
||||
settings.SWIFT: swift.SwiftUninstaller,
|
||||
settings.HORIZON: horizon.HorizonUninstaller,
|
||||
settings.KEYSTONE: keystone.KeystoneUninstaller,
|
||||
settings.DB: db.DBUninstaller,
|
||||
settings.RABBIT: rabbit.RabbitUninstaller,
|
||||
settings.KEYSTONE_CLIENT: keystone_client.KeyStoneClientUninstaller,
|
||||
settings.NOVA_CLIENT: nova_client.NovaClientUninstaller,
|
||||
settings.OPENSTACK_X: openstack_x.OpenstackXUninstaller,
|
||||
settings.NOVNC: novnc.NoVNCUninstaller,
|
||||
settings.QUANTUM_CLIENT: quantum_client.QuantumClientUninstaller,
|
||||
},
|
||||
settings.START: {
|
||||
settings.NOVA: nova.NovaRuntime,
|
||||
settings.GLANCE: glance.GlanceRuntime,
|
||||
settings.QUANTUM: quantum.QuantumRuntime,
|
||||
settings.SWIFT: swift.SwiftRuntime,
|
||||
settings.HORIZON: horizon.HorizonRuntime,
|
||||
settings.KEYSTONE: keystone.KeystoneRuntime,
|
||||
settings.DB: db.DBRuntime,
|
||||
settings.RABBIT: rabbit.RabbitRuntime,
|
||||
settings.KEYSTONE_CLIENT: keystone_client.KeyStoneClientRuntime,
|
||||
settings.NOVA_CLIENT: nova_client.NovaClientRuntime,
|
||||
settings.OPENSTACK_X: openstack_x.OpenstackXRuntime,
|
||||
settings.NOVNC: novnc.NoVNCRuntime,
|
||||
settings.QUANTUM_CLIENT: quantum_client.QuantumClientRuntime,
|
||||
},
|
||||
settings.STOP: {
|
||||
settings.NOVA: nova.NovaRuntime,
|
||||
settings.GLANCE: glance.GlanceRuntime,
|
||||
settings.QUANTUM: quantum.QuantumRuntime,
|
||||
settings.SWIFT: swift.SwiftRuntime,
|
||||
settings.HORIZON: horizon.HorizonRuntime,
|
||||
settings.KEYSTONE: keystone.KeystoneRuntime,
|
||||
settings.DB: db.DBRuntime,
|
||||
settings.RABBIT: rabbit.RabbitRuntime,
|
||||
settings.KEYSTONE_CLIENT: keystone_client.KeyStoneClientRuntime,
|
||||
settings.NOVA_CLIENT: nova_client.NovaClientRuntime,
|
||||
settings.OPENSTACK_X: openstack_x.OpenstackXRuntime,
|
||||
settings.NOVNC: novnc.NoVNCRuntime,
|
||||
settings.QUANTUM_CLIENT: quantum_client.QuantumClientRuntime,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _clean_action(action):
|
||||
if action is None:
|
||||
return None
|
||||
@ -143,14 +66,8 @@ def _get_pkg_manager(distro):
|
||||
return cls(distro)
|
||||
|
||||
|
||||
def _get_action_cls(action_name, component_name):
|
||||
action_cls_map = _ACTION_CLASSES.get(action_name)
|
||||
if not action_cls_map:
|
||||
return None
|
||||
return action_cls_map.get(component_name)
|
||||
|
||||
|
||||
def _check_roots(action, rootdir, components):
|
||||
#TODO the check is really pretty basic so should not be depended on...
|
||||
to_skip = list()
|
||||
if action == settings.INSTALL:
|
||||
if sh.isdir(rootdir):
|
||||
@ -276,25 +193,17 @@ def _uninstall(component_name, instance, skip_notrace):
|
||||
raise
|
||||
|
||||
|
||||
def _get_config():
|
||||
cfg_fn = sh.canon_path(settings.STACK_CONFIG_LOCATION)
|
||||
LOG.info("Loading config from [%s]" % (cfg_fn))
|
||||
config_instance = cfg.EnvConfigParser()
|
||||
config_instance.read(cfg_fn)
|
||||
return config_instance
|
||||
|
||||
|
||||
def _run_components(action_name, component_order, components, distro, root_dir, program_args):
|
||||
LOG.info("Will %s [%s] (in that order) using root directory \"%s\"" % (action_name, ", ".join(component_order), root_dir))
|
||||
non_components = set(components.keys()).difference(set(component_order))
|
||||
if non_components:
|
||||
LOG.info("Using reference components [%s]" % (", ".join(sorted(non_components))))
|
||||
pkg_manager = _get_pkg_manager(distro)
|
||||
config = _get_config()
|
||||
config = common.get_config()
|
||||
#form the active instances (this includes ones we won't use)
|
||||
all_instances = dict()
|
||||
for component in components.keys():
|
||||
action_cls = _get_action_cls(action_name, component)
|
||||
action_cls = common.get_action_cls(action_name, component)
|
||||
instance = action_cls(instances=all_instances,
|
||||
distro=distro,
|
||||
packager=pkg_manager,
|
||||
@ -334,40 +243,12 @@ def _run_components(action_name, component_order, components, distro, root_dir,
|
||||
return results
|
||||
|
||||
|
||||
def _get_def_components():
|
||||
#this seems to be the default list of what to install by default
|
||||
#ENABLED_SERVICES=${ENABLED_SERVICES:-g-api,g-reg,key,n-api,
|
||||
#n-crt,n-obj,n-cpu,n-net,n-sch,n-novnc,n-xvnc,n-cauth,horizon,mysql,rabbit}
|
||||
def_components = dict()
|
||||
def_components[settings.GLANCE] = [
|
||||
glance.GAPI,
|
||||
glance.GREG,
|
||||
]
|
||||
def_components[settings.KEYSTONE] = []
|
||||
#TODO add in xvnc?
|
||||
def_components[settings.NOVA] = [
|
||||
nova.NAPI,
|
||||
nova.NCAUTH,
|
||||
nova.NCERT,
|
||||
nova.NCPU,
|
||||
nova.NNET,
|
||||
nova.NOBJ,
|
||||
nova.NSCHED,
|
||||
nova.NVOL,
|
||||
]
|
||||
def_components[settings.NOVNC] = []
|
||||
def_components[settings.HORIZON] = []
|
||||
def_components[settings.DB] = []
|
||||
def_components[settings.RABBIT] = []
|
||||
return def_components
|
||||
|
||||
|
||||
def _run_action(args):
|
||||
defaulted_components = False
|
||||
components = settings.parse_components(args.pop("components"))
|
||||
components = utils.parse_components(args.pop("components"))
|
||||
if not components:
|
||||
defaulted_components = True
|
||||
components = _get_def_components()
|
||||
components = common.get_default_components()
|
||||
action = _clean_action(args.pop("action"))
|
||||
if not action:
|
||||
cprint("No valid action specified!", "red")
|
||||
@ -391,29 +272,28 @@ def _run_action(args):
|
||||
LOG.info("Activating default components [%s]" % (", ".join(sorted(components.keys()))))
|
||||
#need to figure out dependencies for components (if any)
|
||||
ignore_deps = args.pop('ignore_deps', False)
|
||||
component_order = None
|
||||
if not ignore_deps:
|
||||
new_components = settings.resolve_dependencies(components.keys())
|
||||
component_diff = new_components.difference(components.keys())
|
||||
all_components_deps = common.get_components_deps(action, components)
|
||||
component_diff = set(all_components_deps.keys()).difference(components.keys())
|
||||
if component_diff:
|
||||
LOG.info("Having to activate dependent components: [%s]" % (", ".join(sorted(component_diff))))
|
||||
for new_component in component_diff:
|
||||
components[new_component] = list()
|
||||
component_order = utils.get_components_order(all_components_deps)
|
||||
else:
|
||||
component_order = components.keys()
|
||||
#see if we have previously already done the components
|
||||
#TODO the check is really pretty basic so should not be depended on...
|
||||
component_skips = _check_roots(action, rootdir, components.keys())
|
||||
component_skips = _check_roots(action, rootdir, component_order)
|
||||
for c in component_skips:
|
||||
components.pop(c)
|
||||
if not components:
|
||||
LOG.error("After checking the various components roots, no components ended up being specified!")
|
||||
return False
|
||||
#get the right component order (by priority)
|
||||
component_order = settings.prioritize_components(components.keys())
|
||||
component_order.remove(c)
|
||||
#reverse them so that we stop in the reverse order
|
||||
#and that we uninstall in the reverse order which seems to make sense
|
||||
if action in _REVERSE_ACTIONS:
|
||||
#reverse them so that we stop in the reverse order
|
||||
#and that we uninstall in the reverse order which seems to make sense
|
||||
component_order.reverse()
|
||||
#add in any that will just be referenced but which will not actually do anything (ie the action will not be applied to these)
|
||||
ref_components = settings.parse_components(args.pop("ref_components"))
|
||||
ref_components = utils.parse_components(args.pop("ref_components"))
|
||||
for c in ref_components.keys():
|
||||
if c not in components:
|
||||
components[c] = ref_components.get(c)
|
||||
|
159
devstack/progs/common.py
Normal file
159
devstack/progs/common.py
Normal file
@ -0,0 +1,159 @@
|
||||
# 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 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 nova
|
||||
from devstack.components import nova_client
|
||||
from devstack.components import novnc
|
||||
from devstack.components import openstack_x
|
||||
from devstack.components import quantum
|
||||
from devstack.components import quantum_client
|
||||
from devstack.components import rabbit
|
||||
from devstack.components import swift
|
||||
|
||||
# This determines what classes to use to install/uninstall/...
|
||||
ACTION_CLASSES = {
|
||||
settings.INSTALL: {
|
||||
settings.NOVA: nova.NovaInstaller,
|
||||
settings.GLANCE: glance.GlanceInstaller,
|
||||
settings.QUANTUM: quantum.QuantumInstaller,
|
||||
settings.SWIFT: swift.SwiftInstaller,
|
||||
settings.HORIZON: horizon.HorizonInstaller,
|
||||
settings.KEYSTONE: keystone.KeystoneInstaller,
|
||||
settings.DB: db.DBInstaller,
|
||||
settings.RABBIT: rabbit.RabbitInstaller,
|
||||
settings.KEYSTONE_CLIENT: keystone_client.KeyStoneClientInstaller,
|
||||
settings.NOVA_CLIENT: nova_client.NovaClientInstaller,
|
||||
settings.OPENSTACK_X: openstack_x.OpenstackXInstaller,
|
||||
settings.NOVNC: novnc.NoVNCInstaller,
|
||||
settings.QUANTUM_CLIENT: quantum_client.QuantumClientInstaller,
|
||||
},
|
||||
settings.UNINSTALL: {
|
||||
settings.NOVA: nova.NovaUninstaller,
|
||||
settings.GLANCE: glance.GlanceUninstaller,
|
||||
settings.QUANTUM: quantum.QuantumUninstaller,
|
||||
settings.SWIFT: swift.SwiftUninstaller,
|
||||
settings.HORIZON: horizon.HorizonUninstaller,
|
||||
settings.KEYSTONE: keystone.KeystoneUninstaller,
|
||||
settings.DB: db.DBUninstaller,
|
||||
settings.RABBIT: rabbit.RabbitUninstaller,
|
||||
settings.KEYSTONE_CLIENT: keystone_client.KeyStoneClientUninstaller,
|
||||
settings.NOVA_CLIENT: nova_client.NovaClientUninstaller,
|
||||
settings.OPENSTACK_X: openstack_x.OpenstackXUninstaller,
|
||||
settings.NOVNC: novnc.NoVNCUninstaller,
|
||||
settings.QUANTUM_CLIENT: quantum_client.QuantumClientUninstaller,
|
||||
},
|
||||
settings.START: {
|
||||
settings.NOVA: nova.NovaRuntime,
|
||||
settings.GLANCE: glance.GlanceRuntime,
|
||||
settings.QUANTUM: quantum.QuantumRuntime,
|
||||
settings.SWIFT: swift.SwiftRuntime,
|
||||
settings.HORIZON: horizon.HorizonRuntime,
|
||||
settings.KEYSTONE: keystone.KeystoneRuntime,
|
||||
settings.DB: db.DBRuntime,
|
||||
settings.RABBIT: rabbit.RabbitRuntime,
|
||||
settings.KEYSTONE_CLIENT: keystone_client.KeyStoneClientRuntime,
|
||||
settings.NOVA_CLIENT: nova_client.NovaClientRuntime,
|
||||
settings.OPENSTACK_X: openstack_x.OpenstackXRuntime,
|
||||
settings.NOVNC: novnc.NoVNCRuntime,
|
||||
settings.QUANTUM_CLIENT: quantum_client.QuantumClientRuntime,
|
||||
},
|
||||
settings.STOP: {
|
||||
settings.NOVA: nova.NovaRuntime,
|
||||
settings.GLANCE: glance.GlanceRuntime,
|
||||
settings.QUANTUM: quantum.QuantumRuntime,
|
||||
settings.SWIFT: swift.SwiftRuntime,
|
||||
settings.HORIZON: horizon.HorizonRuntime,
|
||||
settings.KEYSTONE: keystone.KeystoneRuntime,
|
||||
settings.DB: db.DBRuntime,
|
||||
settings.RABBIT: rabbit.RabbitRuntime,
|
||||
settings.KEYSTONE_CLIENT: keystone_client.KeyStoneClientRuntime,
|
||||
settings.NOVA_CLIENT: nova_client.NovaClientRuntime,
|
||||
settings.OPENSTACK_X: openstack_x.OpenstackXRuntime,
|
||||
settings.NOVNC: novnc.NoVNCRuntime,
|
||||
settings.QUANTUM_CLIENT: quantum_client.QuantumClientRuntime,
|
||||
},
|
||||
}
|
||||
|
||||
_FAKE_ROOT_DIR = tempfile.gettempdir()
|
||||
|
||||
def get_default_components():
|
||||
#this seems to be the default list of what to install by default
|
||||
#ENABLED_SERVICES=${ENABLED_SERVICES:-g-api,g-reg,key,n-api,
|
||||
#n-crt,n-obj,n-cpu,n-net,n-sch,n-novnc,n-xvnc,n-cauth,horizon,mysql,rabbit}
|
||||
def_components = dict()
|
||||
def_components[settings.GLANCE] = [
|
||||
glance.GAPI,
|
||||
glance.GREG,
|
||||
]
|
||||
def_components[settings.KEYSTONE] = []
|
||||
#TODO add in xvnc?
|
||||
def_components[settings.NOVA] = [
|
||||
nova.NAPI,
|
||||
nova.NCAUTH,
|
||||
nova.NCERT,
|
||||
nova.NCPU,
|
||||
nova.NNET,
|
||||
nova.NOBJ,
|
||||
nova.NSCHED,
|
||||
nova.NVOL,
|
||||
]
|
||||
def_components[settings.NOVNC] = []
|
||||
def_components[settings.HORIZON] = []
|
||||
def_components[settings.DB] = []
|
||||
def_components[settings.RABBIT] = []
|
||||
return def_components
|
||||
|
||||
|
||||
def get_action_cls(action_name, component_name):
|
||||
action_cls_map = ACTION_CLASSES.get(action_name)
|
||||
return action_cls_map.get(component_name)
|
||||
|
||||
|
||||
def get_config():
|
||||
cfg_fn = sh.canon_path(settings.STACK_CONFIG_LOCATION)
|
||||
config_instance = cfg.EnvConfigParser()
|
||||
config_instance.read(cfg_fn)
|
||||
return config_instance
|
||||
|
||||
|
||||
def get_components_deps(action_name, base_components):
|
||||
all_components = dict()
|
||||
active_names = list(base_components)
|
||||
while len(active_names):
|
||||
component = active_names.pop()
|
||||
component_opts = base_components.get(component) or list()
|
||||
cls = get_action_cls(action_name, component)
|
||||
instance = cls(root=_FAKE_ROOT_DIR, opts=component_opts,
|
||||
config=get_config())
|
||||
deps = instance.get_dependencies()
|
||||
if deps is None:
|
||||
deps = 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
|
68
devstack/progs/deps.py
Normal file
68
devstack/progs/deps.py
Normal file
@ -0,0 +1,68 @@
|
||||
# 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.
|
||||
|
||||
#requires http://pypi.python.org/pypi/termcolor
|
||||
#but the colors make it worth it :-)
|
||||
from termcolor import colored
|
||||
|
||||
from devstack import settings
|
||||
from devstack import utils
|
||||
|
||||
from devstack.progs import common
|
||||
|
||||
PROG_NAME = "Dep. Lister"
|
||||
DEF_ACTION = settings.INSTALL
|
||||
|
||||
|
||||
def _print_deps(component, deps):
|
||||
print(" + " + colored(component, "blue", attrs=['bold']))
|
||||
if deps:
|
||||
for d in sorted(deps):
|
||||
print(" |")
|
||||
print(" ------> %s" % (d))
|
||||
|
||||
|
||||
def _clean_action(action):
|
||||
if not action:
|
||||
return DEF_ACTION
|
||||
action = action.strip.lower()
|
||||
if action not in settings.ACTIONS:
|
||||
return DEF_ACTION
|
||||
return action
|
||||
|
||||
|
||||
def _run_dep_comps(args, rep, maxlen):
|
||||
components = utils.parse_components(args.get("components"))
|
||||
if not components:
|
||||
components = dict()
|
||||
for c in settings.COMPONENT_NAMES:
|
||||
components[c] = list()
|
||||
header = utils.center_text("Dependencies (defaulted)", rep, maxlen)
|
||||
else:
|
||||
header = utils.center_text("Dependencies", rep, maxlen)
|
||||
print(header)
|
||||
action = _clean_action(args.pop("action"))
|
||||
msg = "For action %s" % (action)
|
||||
print(utils.center_text(msg, rep, maxlen))
|
||||
all_deps = common.get_components_deps(action, components)
|
||||
for c in sorted(all_deps.keys()):
|
||||
_print_deps(c, all_deps.get(c))
|
||||
|
||||
|
||||
def run(args):
|
||||
(rep, maxlen) = utils.welcome(PROG_NAME)
|
||||
_run_dep_comps(args, rep, maxlen)
|
||||
return True
|
@ -37,7 +37,7 @@ from devstack.components import quantum_client
|
||||
from devstack.components import rabbit
|
||||
from devstack.components import swift
|
||||
|
||||
PROG_NAME = "MISC"
|
||||
PROG_NAME = "Describer"
|
||||
|
||||
#this determines how descriptions for components are found
|
||||
_DESCR_MAP = {
|
||||
@ -57,46 +57,24 @@ _DESCR_MAP = {
|
||||
}
|
||||
|
||||
|
||||
def log_deps(components):
|
||||
shown = set()
|
||||
left_show = list(components)
|
||||
while left_show:
|
||||
c = left_show.pop()
|
||||
deps = settings.get_dependencies(c)
|
||||
dep_str = "depends on:"
|
||||
print(colored(c, "green", attrs=['bold']) + " depends on " + dep_str)
|
||||
for d in deps:
|
||||
print(" " + colored(d, "blue", attrs=['bold']))
|
||||
shown.add(c)
|
||||
for d in deps:
|
||||
if d not in shown and d not in left_show:
|
||||
left_show.append(d)
|
||||
|
||||
|
||||
def _run_list_deps(args):
|
||||
components = settings.parse_components(args.get("components"), True).keys()
|
||||
components = sorted(components)
|
||||
components.reverse()
|
||||
return log_deps(components)
|
||||
|
||||
|
||||
def _run_describe_comps(args):
|
||||
components = settings.parse_components(args.get("components"), True)
|
||||
def _run_describe_comps(args, rep, maxlen):
|
||||
components = utils.parse_components(args.get("components"))
|
||||
if not components:
|
||||
components = dict()
|
||||
for c in settings.COMPONENT_NAMES:
|
||||
components[c] = list()
|
||||
header = utils.center_text("Descriptions (defaulted)", rep, maxlen)
|
||||
else:
|
||||
header = utils.center_text("Descriptions", rep, maxlen)
|
||||
print(header)
|
||||
c_keys = sorted(components.keys())
|
||||
for c in c_keys:
|
||||
print("Name: " + colored(c, "green", attrs=['bold']) + "")
|
||||
print("Name: " + colored(c, "blue", attrs=['bold']))
|
||||
describer = _DESCR_MAP.get(c)
|
||||
print(describer(components.get(c)))
|
||||
|
||||
|
||||
def run(args):
|
||||
(rep, maxlen) = utils.welcome(PROG_NAME)
|
||||
if args.get('list_deps'):
|
||||
header = utils.center_text("Dependencies", rep, maxlen)
|
||||
print(header)
|
||||
_run_list_deps(args)
|
||||
if args.get('describe_comp'):
|
||||
header = utils.center_text("Descriptions", rep, maxlen)
|
||||
print(header)
|
||||
_run_describe_comps(args)
|
||||
_run_describe_comps(args, rep, maxlen)
|
||||
return True
|
@ -53,7 +53,6 @@ DB = "db"
|
||||
RABBIT = "rabbit"
|
||||
OPENSTACK_X = 'openstack-x'
|
||||
NOVNC = 'novnc'
|
||||
|
||||
COMPONENT_NAMES = [
|
||||
NOVA, NOVA_CLIENT,
|
||||
GLANCE,
|
||||
@ -67,23 +66,6 @@ COMPONENT_NAMES = [
|
||||
NOVNC,
|
||||
]
|
||||
|
||||
# Ordering of install (lower priority means earlier)
|
||||
COMPONENT_NAMES_PRIORITY = {
|
||||
DB: 1,
|
||||
RABBIT: 2,
|
||||
KEYSTONE: 3,
|
||||
GLANCE: 4,
|
||||
QUANTUM: 4,
|
||||
SWIFT: 4,
|
||||
NOVA_CLIENT: 4,
|
||||
NOVA: 5,
|
||||
KEYSTONE_CLIENT: 6,
|
||||
OPENSTACK_X: 6,
|
||||
NOVNC: 6,
|
||||
HORIZON: 10,
|
||||
QUANTUM_CLIENT: 11,
|
||||
}
|
||||
|
||||
# When a component is asked for it may
|
||||
# need another component, that dependency
|
||||
# mapping is listed here
|
||||
@ -110,9 +92,6 @@ COMPONENT_TRACE_DIR = "traces"
|
||||
COMPONENT_APP_DIR = "app"
|
||||
COMPONENT_CONFIG_DIR = "config"
|
||||
|
||||
# This regex is used to extract a components options (if any) and its name
|
||||
EXT_COMPONENT = re.compile(r"^\s*([\w-]+)(?:\((.*)\))?\s*$")
|
||||
|
||||
# Program
|
||||
# actions
|
||||
INSTALL = "install"
|
||||
@ -135,162 +114,4 @@ KNOWN_DISTROS = {
|
||||
}
|
||||
|
||||
|
||||
# The pip files that each component needs
|
||||
PIP_MAP = {
|
||||
NOVA:
|
||||
[],
|
||||
GLANCE:
|
||||
[],
|
||||
KEYSTONE:
|
||||
[
|
||||
os.path.join(STACK_PIP_DIR, 'keystone.json'),
|
||||
],
|
||||
HORIZON:
|
||||
[
|
||||
os.path.join(STACK_PIP_DIR, 'horizon.json'),
|
||||
],
|
||||
SWIFT:
|
||||
[],
|
||||
KEYSTONE_CLIENT:
|
||||
[],
|
||||
DB:
|
||||
[],
|
||||
RABBIT:
|
||||
[],
|
||||
QUANTUM:
|
||||
[],
|
||||
QUANTUM_CLIENT:
|
||||
[],
|
||||
}
|
||||
|
||||
# The pkg files that each component needs
|
||||
PKG_MAP = {
|
||||
NOVA:
|
||||
[
|
||||
os.path.join(STACK_PKG_DIR, "general.json"),
|
||||
os.path.join(STACK_PKG_DIR, "nova.json"),
|
||||
#nova may add others in if it finds that u are asking for a additional components
|
||||
],
|
||||
NOVA_CLIENT:
|
||||
[
|
||||
os.path.join(STACK_PKG_DIR, "general.json"),
|
||||
os.path.join(STACK_PKG_DIR, "nova-client.json"),
|
||||
],
|
||||
GLANCE:
|
||||
[
|
||||
os.path.join(STACK_PKG_DIR, "general.json"),
|
||||
os.path.join(STACK_PKG_DIR, 'glance.json'),
|
||||
],
|
||||
KEYSTONE:
|
||||
[
|
||||
os.path.join(STACK_PKG_DIR, "general.json"),
|
||||
os.path.join(STACK_PKG_DIR, 'keystone.json'),
|
||||
],
|
||||
HORIZON:
|
||||
[
|
||||
os.path.join(STACK_PKG_DIR, "general.json"),
|
||||
os.path.join(STACK_PKG_DIR, 'horizon.json'),
|
||||
],
|
||||
SWIFT:
|
||||
[
|
||||
os.path.join(STACK_PKG_DIR, "general.json"),
|
||||
os.path.join(STACK_PKG_DIR, 'swift.json'),
|
||||
],
|
||||
KEYSTONE_CLIENT:
|
||||
[
|
||||
os.path.join(STACK_PKG_DIR, "general.json"),
|
||||
os.path.join(STACK_PKG_DIR, "keystone-client.json"),
|
||||
],
|
||||
QUANTUM:
|
||||
[
|
||||
os.path.join(STACK_PKG_DIR, "general.json"),
|
||||
os.path.join(STACK_PKG_DIR, "quantum.json"),
|
||||
#quantum may add others in if it finds that u are asking for a openvswitch
|
||||
],
|
||||
QUANTUM_CLIENT:
|
||||
[
|
||||
os.path.join(STACK_PKG_DIR, "general.json"),
|
||||
os.path.join(STACK_PKG_DIR, "quantum-client.json"),
|
||||
],
|
||||
DB:
|
||||
[
|
||||
os.path.join(STACK_PKG_DIR, 'db.json'),
|
||||
],
|
||||
RABBIT:
|
||||
[
|
||||
os.path.join(STACK_PKG_DIR, 'rabbitmq.json'),
|
||||
],
|
||||
OPENSTACK_X:
|
||||
[
|
||||
os.path.join(STACK_PKG_DIR, "general.json"),
|
||||
os.path.join(STACK_PKG_DIR, 'openstackx.json'),
|
||||
],
|
||||
NOVNC:
|
||||
[
|
||||
os.path.join(STACK_PKG_DIR, 'n-vnc.json'),
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def get_dependencies(component):
|
||||
return sorted(COMPONENT_DEPENDENCIES.get(component, list()))
|
||||
|
||||
|
||||
def resolve_dependencies(components):
|
||||
active_components = list(components)
|
||||
new_components = set()
|
||||
while active_components:
|
||||
curr_comp = active_components.pop()
|
||||
component_deps = get_dependencies(curr_comp)
|
||||
new_components.add(curr_comp)
|
||||
for c in component_deps:
|
||||
if c in new_components or c in active_components:
|
||||
pass
|
||||
else:
|
||||
active_components.append(c)
|
||||
return new_components
|
||||
|
||||
|
||||
def prioritize_components(components):
|
||||
#get the right component order (by priority)
|
||||
mporder = dict()
|
||||
for c in components:
|
||||
priority = COMPONENT_NAMES_PRIORITY.get(c)
|
||||
if priority is None:
|
||||
priority = sys.maxint
|
||||
mporder[c] = priority
|
||||
#sort by priority value
|
||||
priority_order = sorted(mporder.iteritems(), key=operator.itemgetter(1))
|
||||
#extract the final list ordering
|
||||
component_order = [x[0] for x in priority_order]
|
||||
return component_order
|
||||
|
||||
|
||||
def parse_components(components, assume_all=False):
|
||||
#none provided, init it
|
||||
if not components:
|
||||
components = list()
|
||||
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 COMPONENT_NAMES:
|
||||
component_opts = mtch.group(2)
|
||||
components_opts_cleaned = list()
|
||||
if not component_opts:
|
||||
pass
|
||||
else:
|
||||
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
|
||||
#should we adjust them to be all the components?
|
||||
if not adjusted_components and assume_all:
|
||||
all_components = dict()
|
||||
for c in COMPONENT_NAMES:
|
||||
all_components[c] = list()
|
||||
adjusted_components = all_components
|
||||
return adjusted_components
|
||||
|
@ -37,6 +37,7 @@ from devstack import version
|
||||
|
||||
|
||||
PARAM_SUB_REGEX = re.compile(r"%([\w\d]+?)%")
|
||||
EXT_COMPONENT = re.compile(r"^\s*([\w-]+)(?:\((.*)\))?\s*$")
|
||||
LOG = logging.getLogger("devstack.util")
|
||||
TEMPLATE_EXT = ".tpl"
|
||||
|
||||
@ -157,27 +158,85 @@ def determine_distro():
|
||||
return (found_os, plt)
|
||||
|
||||
|
||||
def extract_pip_list(fns, distro):
|
||||
all_pkgs = dict()
|
||||
def extract_pip_list(fns, distro, all_pips=None):
|
||||
if not all_pips:
|
||||
all_pips = dict()
|
||||
for fn in fns:
|
||||
js = load_json(fn)
|
||||
distro_pkgs = js.get(distro)
|
||||
if distro_pkgs:
|
||||
combined = dict(all_pkgs)
|
||||
for (pkgname, pkginfo) in distro_pkgs.items():
|
||||
#we currently just overwrite
|
||||
combined[pkgname] = pkginfo
|
||||
all_pkgs = combined
|
||||
return all_pkgs
|
||||
distro_pips = js.get(distro)
|
||||
if distro_pips:
|
||||
all_pips.update(distro_pips)
|
||||
return all_pips
|
||||
|
||||
|
||||
def get_pip_list(distro, component):
|
||||
LOG.info("Getting pip packages for distro %s and component %s." % (distro, component))
|
||||
fns = settings.PIP_MAP.get(component)
|
||||
if fns is None:
|
||||
return dict()
|
||||
else:
|
||||
return extract_pip_list(fns, distro)
|
||||
def get_components_order(components):
|
||||
#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
|
||||
ordering.reverse()
|
||||
return ordering
|
||||
|
||||
|
||||
def extract_pkg_list(fns, distro, all_pkgs=None):
|
||||
@ -187,35 +246,10 @@ def extract_pkg_list(fns, distro, all_pkgs=None):
|
||||
js = load_json(fn)
|
||||
distro_pkgs = js.get(distro)
|
||||
if distro_pkgs:
|
||||
combined = dict(all_pkgs)
|
||||
for (pkgname, pkginfo) in distro_pkgs.items():
|
||||
if pkgname in all_pkgs.keys():
|
||||
oldpkginfo = all_pkgs.get(pkgname) or dict()
|
||||
newpkginfo = dict(oldpkginfo)
|
||||
for (infokey, infovalue) in pkginfo.items():
|
||||
#this is expected to be a list of cmd actions
|
||||
#so merge that accordingly
|
||||
if(infokey == settings.PRE_INSTALL or
|
||||
infokey == settings.POST_INSTALL):
|
||||
oldinstalllist = oldpkginfo.get(infokey) or []
|
||||
infovalue = oldinstalllist + infovalue
|
||||
newpkginfo[infokey] = infovalue
|
||||
combined[pkgname] = newpkginfo
|
||||
else:
|
||||
combined[pkgname] = pkginfo
|
||||
all_pkgs = combined
|
||||
all_pkgs.update(distro_pkgs)
|
||||
return all_pkgs
|
||||
|
||||
|
||||
def get_pkg_list(distro, component):
|
||||
LOG.info("Getting packages for distro %s and component %s." % (distro, component))
|
||||
fns = settings.PKG_MAP.get(component)
|
||||
if fns is None:
|
||||
return dict()
|
||||
else:
|
||||
return extract_pkg_list(fns, distro)
|
||||
|
||||
|
||||
def joinlinesep(*pieces):
|
||||
return os.linesep.join(pieces)
|
||||
|
||||
@ -341,6 +375,30 @@ def goodbye(worked):
|
||||
print(msg)
|
||||
|
||||
|
||||
def parse_components(components):
|
||||
#none provided, init it
|
||||
if not components:
|
||||
components = list()
|
||||
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 = list()
|
||||
if not component_opts:
|
||||
pass
|
||||
else:
|
||||
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):
|
||||
ver_str = version.version_string()
|
||||
lower = "|"
|
||||
|
10
stack
10
stack
@ -39,16 +39,18 @@ from devstack import utils
|
||||
|
||||
#these are the program runtimes that actually do the running
|
||||
from devstack.progs import actions
|
||||
from devstack.progs import misc
|
||||
|
||||
from devstack.progs import describe
|
||||
from devstack.progs import deps
|
||||
|
||||
def main():
|
||||
#parse and get it done!
|
||||
args = opts.parse()
|
||||
#figure out what to do
|
||||
module = None
|
||||
if args.get('list_deps') or args.get('describe_comp'):
|
||||
module = misc
|
||||
if args.get('describe_comp'):
|
||||
module = describe
|
||||
elif args.get('list_deps'):
|
||||
module = deps
|
||||
else:
|
||||
module = actions
|
||||
try:
|
||||
|
Loading…
x
Reference in New Issue
Block a user