592 lines
23 KiB
Python
Raw Normal View History

2012-01-11 12:47:33 -08:00
# vim: tabstop=4 shiftwidth=4 softtabstop=4
2012-01-26 12:54:36 -08:00
# Copyright (C) 2012 Yahoo! Inc. All Rights Reserved.
2012-01-11 12:47:33 -08:00
#
# 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 component as comp
from devstack import log as logging
from devstack import settings
from devstack import utils
from devstack import exceptions
from devstack import shell as sh
from devstack.components import db
from devstack.components import keystone
2012-01-24 12:53:52 -08:00
LOG = logging.getLogger('devstack.components.nova')
2012-01-20 17:00:23 -08:00
2012-01-24 18:10:38 -08:00
#config files adjusted
2012-01-24 12:53:52 -08:00
API_CONF = 'nova.conf'
2012-01-24 18:10:38 -08:00
PASTE_CONF = 'nova-api-paste.ini'
CONFIGS = [API_CONF, PASTE_CONF]
2012-01-24 18:10:38 -08:00
#this db will be dropped then created
2012-01-24 12:53:52 -08:00
DB_NAME = 'nova'
2012-01-24 18:10:38 -08:00
#id
TYPE = settings.NOVA
2012-01-11 12:47:33 -08:00
2012-01-24 18:10:38 -08:00
#post install cmds that will happen after install
2012-01-24 10:16:51 -08:00
POST_INSTALL_CMDS = [
{'cmd': ['%BINDIR%/nova-manage', '--flagfile', '%CFGFILE%',
2012-01-24 12:53:52 -08:00
'db', 'sync']},
{'cmd': ['%BINDIR%/nova-manage', '--flagfile', '%CFGFILE%',
2012-01-24 12:53:52 -08:00
'floating', 'create', '%FLOATING_RANGE%']},
{'cmd': ['%BINDIR%/nova-manage', '--flagfile', '%CFGFILE%',
2012-01-24 12:53:52 -08:00
'floating', 'create', '--ip_range=%TEST_FLOATING_RANGE%',
'--pool=%TEST_FLOATING_POOL%']}
2012-01-24 10:16:51 -08:00
]
2012-01-25 16:16:09 -08:00
VG_CHECK_CMD = [
{'cmd': ['vgs', '%VOLUME_GROUP%'],
'run_as_root': True}
]
VG_DEV_CMD = [
{'cmd': ['losetup', '-f', '--show', '%VOLUME_BACKING_FILE%'],
'run_as_root': True}
]
VG_CREATE_CMD = [
{'cmd': ['vgcreate', '%VOLUME_GROUP%', '%DEV%'],
'run_as_root': True}
]
VG_LVS_CMD = [
{'cmd': ['lvs', '--noheadings', '-o', 'lv_name', '%VOLUME_GROUP%'],
'run_as_root': True}
]
VG_LVREMOVE_CMD = [
{'cmd': ['lvremove', '-f', '%VOLUME_GROUP%/%LV%'],
'run_as_root': True}
]
RESTART_TGT_CMD = [
{'cmd': ['stop', 'tgt'], 'run_as_root': True},
{'cmd': ['start', 'tgt'], 'run_as_root': True}
2012-01-25 16:16:09 -08:00
]
# NCPU, NVOL, NAPI are here as possible subcomponents of nova
NCPU = "cpu"
NVOL = "vol"
NAPI = "api"
SUBCOMPONENTS = [NCPU, NVOL, NAPI]
# In case we need to map names to the image to run
2012-01-25 16:16:09 -08:00
# This map also controls which subcomponent's packages may need to add
APP_NAME_MAP = {
NAPI: 'nova-api',
NCPU: 'nova-compute',
NVOL: 'nova-volume',
}
# Additional packages for subcomponents
ADD_PKGS = {
NAPI:
[
sh.joinpths(settings.STACK_PKG_DIR, 'n-api.json'),
],
NCPU:
[
sh.joinpths(settings.STACK_PKG_DIR, 'n-cpu.json'),
],
NVOL:
[
sh.joinpths(settings.STACK_PKG_DIR, 'n-vol.json'),
],
}
# What to start
APP_OPTIONS = {
NAPI: ['--flagfile', '%CFGFILE%'],
NCPU: ['--flagfile', '%CFGFILE%'],
NVOL: ['--flagfile', '%CFGFILE%'],
'nova-network': ['--flagfile', '%CFGFILE%'],
'nova-scheduler': ['--flagfile', '%CFGFILE%']
}
2012-01-24 18:10:38 -08:00
#subdirs of the checkout/download
BIN_DIR = 'bin'
2012-01-24 12:53:52 -08:00
#These are used by NovaConf
QUANTUM_MANAGER = 'nova.network.quantum.manager.QuantumManager'
NET_MANAGER_TEMPLATE = 'nova.network.manager.%s'
DEF_IMAGE_SERVICE = 'nova.image.glance.GlanceImageService'
DEF_SCHEDULER = 'nova.scheduler.simple.SimpleScheduler'
DEF_GLANCE_PORT = 9292
#only turned on if vswitch enabled
QUANTUM_OPENSWITCH_OPS = {
'libvirt_vif_type': 'ethernet',
'libvirt_vif_driver': 'nova.virt.libvirt.vif.LibvirtOpenVswitchDriver',
'linuxnet_interface_driver': 'nova.network.linux_net.LinuxOVSInterfaceDriver',
'quantum_use_dhcp': None,
}
2012-01-11 12:47:33 -08:00
class NovaUninstaller(comp.PythonUninstallComponent):
2012-01-11 12:47:33 -08:00
def __init__(self, *args, **kargs):
comp.PythonUninstallComponent.__init__(self, TYPE, *args, **kargs)
2012-01-11 12:47:33 -08:00
2012-01-20 17:11:50 -08:00
class NovaInstaller(comp.PythonInstallComponent):
2012-01-11 12:47:33 -08:00
def __init__(self, *args, **kargs):
comp.PythonInstallComponent.__init__(self, TYPE, *args, **kargs)
2012-01-20 17:00:23 -08:00
self.git_repo = self.cfg.get("git", "nova_repo")
self.git_branch = self.cfg.get("git", "nova_branch")
self.bindir = sh.joinpths(self.appdir, BIN_DIR)
self.paste_conf_fn = self._get_target_config_name(PASTE_CONF)
2012-01-19 14:04:37 -08:00
def _get_pkglist(self):
pkgs = comp.PkgInstallComponent._get_pkglist(self)
# Walk through the subcomponents (like 'vol' and 'cpu') and add those
# those packages as well. Let utils.get_pkglist handle any missing
# entries
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)
return pkgs
def _get_download_locations(self):
places = comp.PythonInstallComponent._get_download_locations(self)
places.append({
2012-01-20 17:00:23 -08:00
'uri': self.git_repo,
'branch': self.git_branch,
})
return places
2012-01-20 17:11:50 -08:00
2012-01-24 12:53:52 -08:00
def _get_config_files(self):
return list(CONFIGS)
def post_install(self):
parent_result = comp.PkgInstallComponent.post_install(self)
#extra actions to do nova setup
self._setup_db()
2012-01-24 10:16:51 -08:00
# Need to do db sync and other post install commands
2012-01-24 12:53:52 -08:00
# set up replacement map for CFGFILE, BINDIR, FLOATING_RANGE,
2012-01-24 10:16:51 -08:00
# TEST_FLOATING_RANGE, TEST_FLOATING_POOL
mp = dict()
mp['BINDIR'] = self.bindir
mp['CFGFILE'] = sh.joinpths(self.cfgdir, API_CONF)
2012-01-24 10:16:51 -08:00
mp['FLOATING_RANGE'] = self.cfg.get('nova', 'floating_range')
mp['TEST_FLOATING_RANGE'] = self.cfg.get('nova', 'test_floating_range')
mp['TEST_FLOATING_POOL'] = self.cfg.get('nova', 'test_floating_pool')
2012-01-24 13:48:13 -08:00
utils.execute_template(*POST_INSTALL_CMDS, params=mp, tracewriter=self.tracewriter)
2012-01-25 16:16:09 -08:00
# check if we need to do the vol subcomponent
if not self.component_opts or NVOL in self.component_opts:
2012-01-25 16:16:09 -08:00
# yes, either no subcomponents were specifically requested or it's
# in the set that was requested
self._setup_vol_groups()
2012-01-24 12:53:52 -08:00
return parent_result
def _setup_db(self):
LOG.info("Fixing up database named %s", DB_NAME)
db.drop_db(self.cfg, DB_NAME)
db.create_db(self.cfg, DB_NAME)
2012-01-25 16:16:09 -08:00
def _setup_vol_groups(self):
LOG.debug("Attempt to setup vol groups")
mp = dict()
backing_file = self.cfg.get('nova', 'volume_backing_file')
# check if we need to have a default backing file
if not backing_file:
backing_file = sh.joinpths(self.appdir, 'nova-volumes-backing-file')
2012-01-26 15:53:12 -08:00
vol_group = self.cfg.get('nova', 'volume_group')
backing_file_size = utils.to_bytes(self.cfg.get('nova', 'volume_backing_file_size'))
2012-01-26 15:53:12 -08:00
mp['VOLUME_GROUP'] = vol_group
mp['VOLUME_BACKING_FILE'] = backing_file
mp['VOLUME_BACKING_FILE_SIZE'] = backing_file_size
try:
utils.execute_template(*VG_CHECK_CMD, params=mp)
2012-01-26 15:53:12 -08:00
LOG.info("Vol group already exists:%s" % (vol_group))
except exceptions.ProcessExecutionError as err:
# Check that the error from VG_CHECK is an expected error
if err.exit_code != 5:
raise
2012-01-26 15:53:12 -08:00
LOG.info("Need to create vol group:%s" % (vol_group))
sh.touch_file(backing_file, die_if_there=False, file_size=backing_file_size)
vg_dev_result = utils.execute_template(*VG_DEV_CMD, params=mp)
LOG.debug("vg dev result:%s" % (vg_dev_result))
2012-01-26 15:53:12 -08:00
# Strip the newlines out of the stdout (which is in the first
# element of the first (and only) tuple in the response
mp['DEV'] = vg_dev_result[0][0].replace('\n', '')
utils.execute_template(*VG_CREATE_CMD, params=mp, tracewriter=self.tracewriter)
2012-01-26 15:53:12 -08:00
# One way or another, we should have the volume group, Now check the
# logical volumes
self._process_lvs(mp)
# Finish off by restarting tgt, and ignore any errors
utils.execute_template(*RESTART_TGT_CMD, check_exit_code=False, tracewriter=self.tracewriter)
2012-01-25 16:16:09 -08:00
def _process_lvs(self, mp):
lvs_result = utils.execute_template(*VG_LVS_CMD, params=mp, tracewriter=self.tracewriter)
LOG.debug("lvs result:%s" % (lvs_result))
vol_name_prefix = self.cfg.get('nova', 'volume_name_prefix')
2012-01-26 15:53:12 -08:00
LOG.debug("Using volume name prefix:%s" % (vol_name_prefix))
for stdout_line in lvs_result[0][0].split('\n'):
if stdout_line:
# Ignore blank lines
LOG.debug("lvs output line:%s" % (stdout_line))
if stdout_line.startswith(vol_name_prefix):
# TODO still need to implement the following:
# tid=`egrep "^tid.+$lv" /proc/net/iet/volume | cut -f1 -d' ' | tr ':' '='`
# if [[ -n "$tid" ]]; then
# lun=`egrep "lun.+$lv" /proc/net/iet/volume | cut -f1 -d' ' | tr ':' '=' | tr -d '\t'`
# sudo ietadm --op delete --$tid --$lun
# fi
# sudo lvremove -f $VOLUME_GROUP/$lv
raise exceptions.StackException("lvs magic not yet implemented")
mp['LV'] = stdout_line
utils.execute_template(*VG_LVREMOVE_CMD, params=mp, tracewriter=self.tracewriter)
2012-01-20 17:00:23 -08:00
def _generate_nova_conf(self):
LOG.debug("Generating dynamic content for nova configuration")
2012-01-20 17:00:23 -08:00
dirs = dict()
dirs['app'] = self.appdir
dirs['cfg'] = self.cfgdir
dirs['bin'] = self.bindir
conf_gen = NovaConfigurator(self)
2012-01-20 17:00:23 -08:00
nova_conf = conf_gen.configure(dirs)
tgtfn = self._get_target_config_name(API_CONF)
2012-01-24 12:53:52 -08:00
LOG.info("Writing conf to %s" % (tgtfn))
LOG.info(nova_conf)
2012-01-20 17:00:23 -08:00
sh.write_file(tgtfn, nova_conf)
self.tracewriter.cfg_write(tgtfn)
def _get_source_config(self, config_fn):
if config_fn == PASTE_CONF:
2012-01-27 15:27:44 -08:00
#this is named differently than what it will be stored as...
srcfn = sh.joinpths(self.appdir, "etc", "nova", 'api-paste.ini')
2012-01-27 15:20:16 -08:00
contents = sh.load_file(srcfn)
return (srcfn, contents)
else:
return comp.PythonInstallComponent._get_source_config(self, config_fn)
def _get_target_config_name(self, config_fn):
if config_fn == PASTE_CONF:
#TODO this should not be here... (in bin??)
2012-01-27 15:27:44 -08:00
return sh.joinpths(self.appdir, "bin", 'nova-api-paste.ini')
else:
return comp.PythonInstallComponent._get_target_config_name(self, config_fn)
def _generate_paste_api_conf(self):
2012-01-27 15:14:33 -08:00
name = PASTE_CONF
LOG.info("Setting up %s" % (name))
mp = keystone.get_shared_params(self.cfg)
2012-01-27 15:14:33 -08:00
(src_fn, contents) = self._get_source_config(name)
LOG.info("Replacing parameters in file %s" % (src_fn))
contents = utils.param_replace(contents, mp, True)
2012-01-27 15:14:33 -08:00
tgt_fn = self._get_target_config_name(name)
LOG.info("Writing to file %s" % (tgt_fn))
sh.write_file(tgt_fn, contents)
self.tracewriter.cfg_write(tgt_fn)
2012-01-20 17:00:23 -08:00
def _configure_files(self):
self._generate_nova_conf()
self._generate_paste_api_conf()
return len(CONFIGS)
2012-01-20 17:00:23 -08:00
class NovaRuntime(comp.PythonRuntime):
2012-01-11 12:47:33 -08:00
def __init__(self, *args, **kargs):
comp.PythonRuntime.__init__(self, TYPE, *args, **kargs)
2012-01-24 15:19:21 -08:00
self.run_tokens = dict()
self.run_tokens['CFGFILE'] = sh.joinpths(self.cfgdir, API_CONF)
2012-01-24 15:19:21 -08:00
LOG.debug("Setting CFGFILE run_token to:%s" % (self.run_tokens['CFGFILE']))
def _get_apps_to_start(self):
# Check if component_opts was set to a subset of apps to be started
LOG.debug("getting list of apps to start")
apps = list()
2012-01-24 12:53:52 -08:00
if not self.component_opts and len(self.component_opts) > 0:
LOG.debug("Attempt to use subset of components:%s" % (self.component_opts))
# check if the specified sub components exist
delta = set(self.component_opts) - set(APP_OPTIONS.keys())
2012-01-24 12:53:52 -08:00
if delta:
LOG.error("sub items that we don't know about:%s" % delta)
raise exceptions.BadParamException("Unknown subcomponent specified:%s" % delta)
else:
apps = self.component_opts
2012-01-24 15:19:21 -08:00
LOG.debug("Using specified subcomponents:%s" % (apps))
else:
apps = APP_OPTIONS.keys()
2012-01-24 15:19:21 -08:00
LOG.debug("Using the keys from APP_OPTIONS:%s" % (apps))
result = list()
for app_name in apps:
2012-01-24 12:53:52 -08:00
if app_name in APP_NAME_MAP:
image_name = APP_NAME_MAP.get(app_name)
2012-01-24 15:19:21 -08:00
LOG.debug("Renamed app_name to:" + app_name)
else:
image_name = app_name
result.append({
'name': app_name,
'path': sh.joinpths(self.appdir, BIN_DIR, image_name),
})
2012-01-24 15:19:21 -08:00
LOG.debug("exiting _get_aps_to_start with:%s" % (result))
return result
def _get_app_options(self, app):
LOG.debug("Getting options for %s" % (app))
2012-01-24 15:19:21 -08:00
result = list()
for opt_str in APP_OPTIONS.get(app):
LOG.debug("Checking opt_str for tokens: %s" % (opt_str))
result.append(utils.param_replace(opt_str, self.run_tokens))
LOG.debug("_get_app_options returning with:%s" % (result))
return result
2012-01-24 12:53:52 -08:00
# This class has the smarts to build the configuration file based on
# various runtime values
2012-01-24 13:48:13 -08:00
class NovaConfigurator(object):
def __init__(self, nc):
self.cfg = nc.cfg
self.instances = nc.instances
2012-01-26 15:53:12 -08:00
self.component_root = nc.component_root
self.appdir = nc.appdir
self.tracewriter = nc.tracewriter
self.paste_conf_fn = nc.paste_conf_fn
self.nvol = not nc.component_opts or NVOL in nc.component_opts
2012-01-24 12:53:52 -08:00
def _getbool(self, name):
return self.cfg.getboolean('nova', name)
def _getstr(self, name):
return self.cfg.get('nova', name)
def configure(self, dirs):
#TODO split up into sections??
nova_conf = NovaConf()
hostip = self.cfg.get('host', 'ip')
#verbose on?
if self._getbool('verbose'):
nova_conf.add_simple('verbose')
#allow the admin api?
if self._getbool('allow_admin_api'):
nova_conf.add_simple('allow_admin_api')
#which scheduler do u want?
scheduler = self._getstr('scheduler')
if not scheduler:
scheduler = DEF_SCHEDULER
nova_conf.add('scheduler_driver', scheduler)
flag_conf_fn = sh.joinpths(dirs.get('bin'), API_CONF)
nova_conf.add('dhcpbridge_flagfile', flag_conf_fn)
#whats the network fixed range?
nova_conf.add('fixed_range', self._getstr('fixed_range'))
if settings.QUANTUM in self.instances:
#setup quantum config
nova_conf.add('network_manager', QUANTUM_MANAGER)
nova_conf.add('quantum_connection_host', self.cfg.get('quantum', 'q_host'))
nova_conf.add('quantum_connection_port', self.cfg.get('quantum', 'q_port'))
if self.cfg.get('quantum', 'q_plugin') == 'openvswitch':
for (key, value) in QUANTUM_OPENSWITCH_OPS.items():
if value is None:
nova_conf.add_simple(key)
else:
nova_conf.add(key, value)
2012-01-24 12:53:52 -08:00
else:
nova_conf.add('network_manager', NET_MANAGER_TEMPLATE % (self._getstr('network_manager')))
2012-01-25 16:16:09 -08:00
if self.nvol:
nova_conf.add('volume_group', self._getstr('volume_group'))
volume_name_template = self._getstr('volume_name_prefix') + self._getstr('volume_name_postfix')
nova_conf.add('volume_name_template', volume_name_template)
nova_conf.add('iscsi_help', 'tgtadm')
2012-01-24 12:53:52 -08:00
nova_conf.add('my_ip', hostip)
# The value for vlan_interface may default to the the current value
# of public_interface. We'll grab the value and keep it handy.
public_interface = self._getstr('public_interface')
vlan_interface = self._getstr('vlan_interface')
if not vlan_interface:
vlan_interface = public_interface
nova_conf.add('public_interface', public_interface)
nova_conf.add('vlan_interface', vlan_interface)
#setup your sql connection and what type of virt u will be doing
nova_conf.add('sql_connection', self.cfg.get_dbdsn('nova'))
#configure anything libvirt releated?
self._configure_libvirt(self._getstr('libvirt_type'), nova_conf)
#how instances will be presented
2012-01-25 16:16:09 -08:00
instance_template = self._getstr('instance_name_prefix') + self._getstr('instance_name_postfix')
2012-01-24 12:53:52 -08:00
nova_conf.add('instance_name_template', instance_template)
if settings.OPENSTACK_X in self.instances:
nova_conf.add('osapi_compute_extension', 'nova.api.openstack.compute.contrib.standard_extensions')
nova_conf.add('osapi_compute_extension', 'extensions.admin.Admin')
if settings.NOVNC in self.instances:
vncproxy_url = self._getstr('vncproxy_url')
if not vncproxy_url:
vncproxy_url = 'http://' + hostip + ':6080/vnc_auto.html'
nova_conf.add('vncproxy_url', vncproxy_url)
nova_conf.add('api_paste_config', self.paste_conf_fn)
2012-01-24 12:53:52 -08:00
img_service = self._getstr('img_service')
if not img_service:
img_service = DEF_IMAGE_SERVICE
nova_conf.add('image_service', img_service)
ec2_dmz_host = self._getstr('ec2_dmz_host')
if not ec2_dmz_host:
ec2_dmz_host = hostip
nova_conf.add('ec2_dmz_host', ec2_dmz_host)
#how is your rabbit setup?
nova_conf.add('rabbit_host', self.cfg.get('default', 'rabbit_host'))
nova_conf.add('rabbit_password', self.cfg.get("passwords", "rabbit"))
#where is glance located?
glance_api_server = self._getstr('glance_server')
if not glance_api_server:
glance_api_server = "%s:%d" % (hostip, DEF_GLANCE_PORT)
nova_conf.add('glance_api_servers', glance_api_server)
nova_conf.add_simple('force_dhcp_release')
#where instances will be stored
instances_path = self._getstr('instances_path')
if not instances_path:
# If there's no instances path, specify a default
2012-01-26 15:53:12 -08:00
instances_path = sh.joinpths(self.component_root, 'instances')
nova_conf.add('instances_path', instances_path)
LOG.debug("Attempting to create instance directory:%s" % (instances_path))
# Create the directory for instances
self.tracewriter.make_dir(instances_path)
2012-01-24 12:53:52 -08:00
#is this a multihost setup?
if self._getbool('multi_host'):
nova_conf.add_simple('multi_host')
nova_conf.add_simple('send_arp_for_ha')
#enable syslog??
if self.cfg.getboolean('default', 'syslog'):
nova_conf.add_simple('use_syslog')
#handle any virt driver specifics
virt_driver = self._getstr('virt_driver')
self._configure_virt_driver(virt_driver, nova_conf)
#now make it
conf_lines = sorted(nova_conf.generate())
complete_file = utils.joinlinesep(*conf_lines)
#add any extra flags in?
extra_flags = self._getstr('extra_flags')
if extra_flags and len(extra_flags):
full_file = [complete_file, extra_flags]
complete_file = utils.joinlinesep(*full_file)
return complete_file
def _configure_libvirt(self, virt_type, nova_conf):
if not virt_type:
return
nova_conf.add('libvirt_type', virt_type)
#configures any virt driver settings
def _configure_virt_driver(self, driver, nova_conf):
if not driver:
return
drive_canon = driver.lower().strip()
if drive_canon == 'xenserver':
nova_conf.add('connection_type', 'xenapi')
nova_conf.add('xenapi_connection_url', 'http://169.254.0.1')
nova_conf.add('xenapi_connection_username', 'root')
nova_conf.add('xenapi_connection_password', self.cfg.get("passwords", "xenapi_connection"))
nova_conf.add_simple('noflat_injected')
nova_conf.add('flat_interface', 'eth1')
nova_conf.add('flat_network_bridge', 'xapi1')
else:
nova_conf.add('connection_type', self._getstr('connection_type'))
nova_conf.add('flat_network_bridge', self._getstr('flat_network_bridge'))
nova_conf.add('flat_interface', self._getstr('flat_interface'))
# This class represents the data in the nova config file
2012-01-24 13:48:13 -08:00
class NovaConf(object):
2012-01-24 12:53:52 -08:00
def __init__(self):
self.lines = list()
def add_list(self, key, *params):
self.lines.append({'key': key, 'options': params})
LOG.debug("Added nova conf key %s with values [%s]" % (key, ",".join(params)))
def add_simple(self, key):
self.lines.append({'key': key, 'options': None})
LOG.debug("Added nova conf key %s" % (key))
def add(self, key, value):
self.lines.append({'key': key, 'options': [value]})
LOG.debug("Added nova conf key %s with value [%s]" % (key, value))
def _form_key(self, key, has_opts):
key_str = "--" + str(key)
if has_opts:
key_str += "="
return key_str
def generate(self, param_dict=None):
gen_lines = list()
for line_entry in self.lines:
key = line_entry.get('key')
opts = line_entry.get('options')
2012-01-25 14:58:45 -08:00
if not key:
2012-01-24 12:53:52 -08:00
continue
2012-01-25 13:30:43 -08:00
if opts is None:
2012-01-24 12:53:52 -08:00
key_str = self._form_key(key, False)
full_line = key_str
else:
key_str = self._form_key(key, True)
2012-01-24 12:53:52 -08:00
filled_opts = list()
for opt in opts:
filled_opts.append(utils.param_replace(str(opt), param_dict))
full_line = key_str + ",".join(filled_opts)
gen_lines.append(full_line)
return gen_lines
def describe(opts=None):
description = """
Module: {module_name}
Description:
{description}
Component options:
{component_opts}
"""
params = dict()
params['component_opts'] = "TBD"
params['module_name'] = __name__
params['description'] = __doc__ or "Handles actions for the nova component."
out = description.format(**params)
return out.strip("\n")