Added it so that components can describe what they do and what options they have.

This commit is contained in:
Joshua Harlow
2012-01-25 20:05:36 -08:00
parent ec8858174f
commit 15f9e5501c
17 changed files with 380 additions and 105 deletions

View File

@@ -27,6 +27,10 @@ This will typically produce:
Options:
--version show program's version number and exit
-h, --help show this help message and exit
-c COMPONENT, --component=COMPONENT
openstack component, ie (db, glance, horizon, keystone,
keystone-client, nova, nova-client, novnc, openstack-x,
quantum, rabbit, swift)
Install/uninstall/start/stop options:
-a ACTION, --action=ACTION
@@ -34,10 +38,6 @@ This will typically produce:
-d DIR, --directory=DIR
empty root DIR for install or DIR with existing
components for start/stop/uninstall
-c COMPONENT, --component=COMPONENT
openstack component, ie (db, glance, horizon, keystone,
keystone-client, nova, nova-client, openstack-x,
quantum, rabbit, swift)
-i, --ignore-deps ignore dependencies when performing ACTION
-e, --ensure-deps ensure dependencies when performing ACTION (default:
True)
@@ -48,8 +48,10 @@ This will typically produce:
Uninstall/stop options:
-f, --force force ACTION even if no trace file found
Dependency options:
-s, --list-deps show dependencies of COMPONENT (default: False)
Miscellaneous options:
--list-deps show dependencies of COMPONENT (default: False)
--describe-components
describe COMPONENT (default: False)
# Stack prerequisites

View File

@@ -194,3 +194,22 @@ def create_db(cfg, dbname):
else:
msg = BASE_ERROR % ('create', dbtype)
raise NotImplementedError(msg)
def describe(opts=None):
description = """ Module: {module_name}
Description:
Handles actions for the database component.
Component options:
{component_opts}
Provides:
{provides_what}
"""
params = dict()
params['component_opts'] = "N/A"
params['module_name'] = __name__
provides = [DBRuntime.__name__,
DBInstaller.__name__,
DBUninstaller.__name__]
params['provides_what'] = ", ".join(sorted(provides))
return description.format(**params)

View File

@@ -171,3 +171,22 @@ class GlanceInstaller(comp.PythonInstallComponent):
mp['HOST_IP'] = self.cfg.get('host', 'ip')
mp.update(keystone.get_shared_params(self.cfg))
return mp
def describe(opts=None):
description = """ Module: {module_name}
Description:
Handles actions for the glance component.
Component options:
{component_opts}
Provides:
{provides_what}
"""
params = dict()
params['component_opts'] = "TBD"
params['module_name'] = __name__
provides = [GlanceRuntime.__name__,
GlanceInstaller.__name__,
GlanceUninstaller.__name__]
params['provides_what'] = ", ".join(sorted(provides))
return description.format(**params)

View File

@@ -206,3 +206,22 @@ class HorizonRuntime(comp.EmptyRuntime):
return comp.STATUS_STOPPED
else:
return comp.STATUS_UNKNOWN
def describe(opts=None):
description = """ Module: {module_name}
Description:
Handles actions for the horizon component.
Component options:
{component_opts}
Provides:
{provides_what}
"""
params = dict()
params['component_opts'] = "N/A"
params['module_name'] = __name__
provides = [HorizonRuntime.__name__,
HorizonInstaller.__name__,
HorizonUninstaller.__name__]
params['provides_what'] = ", ".join(sorted(provides))
return description.format(**params)

View File

@@ -187,3 +187,22 @@ def get_shared_params(cfg):
mp['KEYSTONE_SERVICE_PROTOCOL'] = cfg.get('keystone', 'keystone_service_protocol')
mp['SERVICE_TOKEN'] = cfg.get("passwords", "service_token")
return mp
def describe(opts=None):
description = """ Module: {module_name}
Description:
Handles actions for the keystone component.
Component options:
{component_opts}
Provides:
{provides_what}
"""
params = dict()
params['component_opts'] = "TBD"
params['module_name'] = __name__
provides = [KeystoneRuntime.__name__,
KeystoneInstaller.__name__,
KeystoneUninstaller.__name__]
params['provides_what'] = ", ".join(sorted(provides))
return description.format(**params)

View File

@@ -47,3 +47,22 @@ class KeyStoneClientInstaller(comp.PythonInstallComponent):
class KeyStoneClientRuntime(comp.EmptyRuntime):
def __init__(self, *args, **kargs):
comp.EmptyRuntime.__init__(self, TYPE, *args, **kargs)
def describe(opts=None):
description = """ Module: {module_name}
Description:
Handles actions for the keystone client component.
Component options:
{component_opts}
Provides:
{provides_what}
"""
params = dict()
params['component_opts'] = "TBD"
params['module_name'] = __name__
provides = [KeyStoneClientRuntime.__name__,
KeyStoneClientInstaller.__name__,
KeyStoneClientUninstaller.__name__]
params['provides_what'] = ", ".join(sorted(provides))
return description.format(**params)

View File

@@ -441,3 +441,22 @@ class NovaConf(object):
full_line = key_str + ",".join(filled_opts)
gen_lines.append(full_line)
return gen_lines
def describe(opts=None):
description = """ Module: {module_name}
Description:
Handles actions for the nova component.
Component options:
{component_opts}
Provides:
{provides_what}
"""
params = dict()
params['component_opts'] = "TBD"
params['module_name'] = __name__
provides = [NovaRuntime.__name__,
NovaInstaller.__name__,
NovaUninstaller.__name__]
params['provides_what'] = ", ".join(sorted(provides))
return description.format(**params)

View File

@@ -54,3 +54,22 @@ class NovaClientInstaller(comp.PythonInstallComponent):
class NovaClientRuntime(comp.EmptyRuntime):
def __init__(self, *args, **kargs):
comp.EmptyRuntime.__init__(self, TYPE, *args, **kargs)
def describe(opts=None):
description = """ Module: {module_name}
Description:
Handles actions for the nova client component.
Component options:
{component_opts}
Provides:
{provides_what}
"""
params = dict()
params['component_opts'] = "TBD"
params['module_name'] = __name__
provides = [NovaClientRuntime.__name__,
NovaClientUninstaller.__name__,
NovaClientInstaller.__name__]
params['provides_what'] = ", ".join(sorted(provides))
return description.format(**params)

View File

@@ -77,3 +77,22 @@ class NoVNCRuntime(comp.ProgramRuntime):
def _get_app_options(self, app):
return APP_OPTIONS.get(app)
def describe(opts=None):
description = """ Module: {module_name}
Description:
Handles actions for the nova no-vnc component.
Component options:
{component_opts}
Provides:
{provides_what}
"""
params = dict()
params['component_opts'] = "TBD"
params['module_name'] = __name__
provides = [NoVNCRuntime.__name__,
NoVNCUninstaller.__name__,
NoVNCInstaller.__name__]
params['provides_what'] = ", ".join(sorted(provides))
return description.format(**params)

View File

@@ -46,3 +46,22 @@ class OpenstackXInstaller(comp.PythonInstallComponent):
class OpenstackXRuntime(comp.EmptyRuntime):
def __init__(self, *args, **kargs):
comp.EmptyRuntime.__init__(self, TYPE, *args, **kargs)
def describe(opts=None):
description = """ Module: {module_name}
Description:
Handles actions for the openstack x component.
Component options:
{component_opts}
Provides:
{provides_what}
"""
params = dict()
params['component_opts'] = "TBD"
params['module_name'] = __name__
provides = [OpenstackXRuntime.__name__,
OpenstackXInstaller.__name__,
OpenstackXUninstaller.__name__]
params['provides_what'] = ", ".join(sorted(provides))
return description.format(**params)

View File

@@ -198,3 +198,22 @@ class QuantumInstaller(comp.PkgInstallComponent):
class QuantumRuntime(comp.EmptyRuntime):
def __init__(self, *args, **kargs):
comp.EmptyRuntime.__init__(self, TYPE, *args, **kargs)
def describe(opts=None):
description = """ Module: {module_name}
Description:
Handles actions for the quantum component.
Component options:
{component_opts}
Provides:
{provides_what}
"""
params = dict()
params['component_opts'] = "TBD"
params['module_name'] = __name__
provides = [QuantumRuntime.__name__,
QuantumInstaller.__name__,
QuantumUninstaller.__name__]
params['provides_what'] = ", ".join(sorted(provides))
return description.format(**params)

View File

@@ -109,3 +109,22 @@ class RabbitRuntime(comp.EmptyRuntime):
return 1
else:
return 0
def describe(opts=None):
description = """ Module: {module_name}
Description:
Handles actions for the rabbit-mq component.
Component options:
{component_opts}
Provides:
{provides_what}
"""
params = dict()
params['component_opts'] = "TBD"
params['module_name'] = __name__
provides = [RabbitRuntime.__name__,
RabbitUninstaller.__name__,
RabbitInstaller.__name__]
params['provides_what'] = ", ".join(sorted(provides))
return description.format(**params)

View File

@@ -60,3 +60,22 @@ class SwiftInstaller(object):
class SwiftRuntime(comp.EmptyRuntime):
def __init__(self, *args, **kargs):
comp.EmptyRuntime.__init__(self, TYPE, *args, **kargs)
def describe(opts=None):
description = """ Module: {module_name}
Description:
Handles actions for the swift component.
Component options:
{component_opts}
Provides:
{provides_what}
"""
params = dict()
params['component_opts'] = "TBD"
params['module_name'] = __name__
provides = [SwiftRuntime.__name__,
SwiftInstaller.__name__,
SwiftUninstaller.__name__]
params['provides_what'] = ", ".join(sorted(provides))
return description.format(**params)

View File

@@ -31,6 +31,13 @@ def parse():
help_formatter = IndentedHelpFormatter(width=HELP_WIDTH)
parser = OptionParser(version=version_str, formatter=help_formatter)
known_components = sorted(settings.COMPONENT_NAMES)
components = "(" + ", ".join(known_components) + ")"
parser.add_option("-c", "--component",
action="append",
dest="component",
help="openstack component, ie %s" % (components))
base_group = OptionGroup(parser, "Install/uninstall/start/stop options")
known_actions = sorted(settings.ACTIONS)
actions = "(" + ", ".join(known_actions) + ")"
@@ -47,12 +54,6 @@ def parse():
metavar="DIR",
help="empty root DIR for install or "\
"DIR with existing components for start/stop/uninstall")
known_components = sorted(settings.COMPONENT_NAMES)
components = "(" + ", ".join(known_components) + ")"
base_group.add_option("-c", "--component",
action="append",
dest="component",
help="openstack component, ie %s" % (components))
base_group.add_option("-i", "--ignore-deps",
action="store_false",
dest="ensure_deps",
@@ -77,13 +78,18 @@ def parse():
default=False)
parser.add_option_group(stop_un_group)
dep_group = OptionGroup(parser, "Dependency options")
dep_group.add_option("-s", "--list-deps",
misc_group = OptionGroup(parser, "Miscellaneous options")
misc_group.add_option("--list-deps",
action="store_true",
dest="list_deps",
help="show dependencies of COMPONENT (default: %default)",
default=False)
parser.add_option_group(dep_group)
misc_group.add_option("--describe-components",
action="store_true",
dest="describe_comp",
help="describe COMPONENT (default: %default)",
default=False)
parser.add_option_group(misc_group)
(options, args) = parser.parse_args()
@@ -94,6 +100,7 @@ def parse():
output['ref_components'] = options.r_component
output['action'] = options.action
output['list_deps'] = options.list_deps
output['describe_comp'] = options.describe_comp
output['force'] = options.force
if options.ensure_deps:
output['ignore_deps'] = False

View File

@@ -1,59 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# 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.
from devstack import log as logging
from devstack import settings
from devstack import utils
LOG = logging.getLogger("devstack.progs.deps")
PROG_NAME = "DEPENDENCY LIST"
def log_deps(components):
shown = set()
left_show = list(components)
while left_show:
c = left_show.pop()
deps = settings.get_dependencies(c)
dep_str = ""
dep_len = len(deps)
if dep_len >= 1:
dep_str = "component"
if dep_len > 1:
dep_str += "s"
dep_str += ":"
elif dep_len == 0:
dep_str = "no components."
LOG.info("%s depends on %s" % (c, dep_str))
for d in deps:
LOG.info("\t%s" % (d))
shown.add(c)
for d in deps:
if d not in shown and d not in left_show:
left_show.append(d)
return True
def _run_list_deps(args):
components = settings.parse_components(args.pop("components"), True).keys()
components = sorted(components)
components.reverse()
utils.welcome(PROG_NAME)
LOG.info("Showing dependencies of [%s]" % (", ".join(sorted(components))))
return log_deps(components)
def run(args):
return _run_list_deps(args)

118
devstack/progs/misc.py Normal file
View File

@@ -0,0 +1,118 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# 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 re
from devstack import log as logging
from devstack import settings
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 rabbit
from devstack.components import swift
LOG = logging.getLogger("devstack.progs.misc")
PROG_NAME = "MISC"
_DESCR_MAP = {
settings.DB: db.describe,
settings.GLANCE: glance.describe,
settings.HORIZON: horizon.describe,
settings.KEYSTONE: keystone.describe,
settings.KEYSTONE_CLIENT: keystone_client.describe,
settings.NOVA: nova.describe,
settings.NOVA_CLIENT: nova_client.describe,
settings.OPENSTACK_X: openstack_x.describe,
settings.QUANTUM: quantum.describe,
settings.RABBIT: rabbit.describe,
settings.SWIFT: swift.describe,
settings.NOVNC: novnc.describe,
}
def log_deps(components):
shown = set()
left_show = list(components)
while left_show:
c = left_show.pop()
deps = settings.get_dependencies(c)
dep_str = ""
dep_len = len(deps)
if dep_len >= 1:
dep_str = "component"
if dep_len > 1:
dep_str += "s"
dep_str += ":"
elif dep_len == 0:
dep_str = "no components."
LOG.info("%s depends on %s" % (c, dep_str))
for d in deps:
LOG.info("\t%s" % (d))
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)
c_keys = sorted(components.keys())
for c in c_keys:
LOG.info("Component %s {", c)
describer = _DESCR_MAP.get(c)
info = describer(components.get(c))
if info:
lines = info.splitlines()
for line in lines:
if len(line) == 0:
continue
#do some basic formatting
mtch = re.match(r"^(\s*)(.*)$", line)
new_line = line
if mtch:
space_am = len(mtch.group(1)) * 2
new_line = " " * space_am + mtch.group(2)
LOG.info(new_line)
LOG.info("}")
def run(args):
prog_name = PROG_NAME
if args.get('list_deps'):
prog_name += " [DEPS]"
if args.get('describe_comp'):
prog_name += " [DESCRIBE]"
utils.welcome(prog_name)
if args.get('list_deps'):
_run_list_deps(args)
if args.get('describe_comp'):
_run_describe_comps(args)
return True

41
stack
View File

@@ -20,14 +20,10 @@ import logging.config
import sys
#this needs to happen immediately (or thats what it seems)
LOG_FN_ENV = 'LOG_FILE'
LOG_FILE_DEF = os.path.join("conf", 'logging.ini')
def setupLogging():
logfn = os.getenv(LOG_FN_ENV)
logfn = os.getenv('LOG_FILE')
if(logfn == None):
logfn = LOG_FILE_DEF
logfn = os.path.join("conf", 'logging.ini')
logging.config.fileConfig(logfn)
setupLogging()
@@ -36,45 +32,28 @@ from devstack import opts
#these are the program runtimes that actually do the running
from devstack.progs import actions
from devstack.progs import deps
from devstack.progs import misc
LOG = logging.getLogger("devstack")
def check_python(prog):
py_version = sys.version_info
major = py_version[0]
minor = py_version[1]
if(major < 2 or (major == 2 and minor < 6)):
LOG.error("Your python version is to old, please upgrade to >= 2.6!")
return False
if(major >= 3):
LOG.warn("%s has not been tested in python %s, use at your own risk!" % (prog, major))
return True
def main():
me = os.path.basename(sys.argv[0])
if(not check_python(me)):
return 1
#parse and get it done!
args = opts.parse()
run_ok = False
#figure out what to do
only_list_deps = args.pop('list_deps', False)
if args.get('list_deps') or args.get('describe_comp'):
run_ok = misc.run(args)
else:
run_ok = actions.run(args)
#now do it
rc_ok = False
if(only_list_deps):
rc_ok = deps.run(args)
else:
rc_ok = actions.run(args)
if(rc_ok):
if run_ok:
return 0
else:
LOG.info("Perhaps you should try %s --help" % (me))
LOG.info("Perhaps you should try %s --help" % (os.path.basename(sys.argv[0])))
return 1