Sync common config module from Oslo

List of changes

1a6dfb9 Sanitize FQDN in config generator
e839886 Config generator fails with lazy messages
763eedf Fix DictOpt support in config sample generator
e3dddd7 generator: use EXTRA_* env vars in the bash script
e8e636c generator: add an EXTRA_LIBRARIES env variable
5dce17b Use entry points to discover options in libraries
dd9aa2b Remove unused variables
ad17a69 Fix filter() usage due to python 3 compability
7c18261 Temporary workaround for config generator
4b3e32b Sort the output of config/generator.py by group name
12bcdb7 Remove vim header
806272e Improve error reporting on import failures
6cd1c33 Clean up extra modules code

Updated ironic.conf.sample using new config generator.

Closes-Bug: #1282481
Change-Id: Ice3e527589bbf0e881d21f55229264513ea445d2
This commit is contained in:
Victor Sergeyev 2014-02-18 16:54:55 +02:00
parent 3a4e732985
commit 1fd5b44425
3 changed files with 235 additions and 182 deletions

View File

@ -442,6 +442,23 @@
#matchmaker_heartbeat_ttl=600
[api]
#
# Options defined in ironic.api
#
# The listen IP for the Ironic API server. (string value)
#host_ip=0.0.0.0
# The port for the Ironic API server. (integer value)
#port=6385
# The maximum number of items returned in a single response
# from a collection resource. (integer value)
#max_limit=1000
[conductor]
#
@ -557,6 +574,50 @@
#pool_timeout=<None>
[glance]
#
# Options defined in ironic.common.glance_service.v2.image_service
#
# A list of URL schemes that can be downloaded directly via
# the direct_url. Currently supported schemes: [file]. (list
# value)
#allowed_direct_url_schemes=
#
# Options defined in ironic.common.image_service
#
# Default glance hostname or IP address. (string value)
#glance_host=$my_ip
# Default glance port. (integer value)
#glance_port=9292
# Default protocol to use when connecting to glance. Set to
# https for SSL. (string value)
#glance_protocol=http
# A list of the glance api servers available to nova. Prefix
# with https:// for SSL-based glance API servers. Format is
# [hostname|IP]:port. (string value)
#glance_api_servers=<None>
# Allow to perform insecure SSL (https) requests to glance.
# (boolean value)
#glance_api_insecure=false
# Number of retries when downloading an image from glance.
# (integer value)
#glance_num_retries=0
# Default protocol to use when connecting to glance. Set to
# https for SSL. (string value)
#auth_strategy=keystone
[ipmi]
#
@ -568,98 +629,6 @@
#retry_timeout=10
[ssl]
#
# Options defined in ironic.openstack.common.sslutils
#
# CA certificate file to use to verify connecting clients
# (string value)
#ca_file=<None>
# Certificate file to use when starting the server securely
# (string value)
#cert_file=<None>
# Private key file to use when starting the server securely
# (string value)
#key_file=<None>
[matchmaker_ring]
#
# Options defined in ironic.openstack.common.rpc.matchmaker_ring
#
# Matchmaker ring file (JSON) (string value)
# Deprecated group/name - [DEFAULT]/matchmaker_ringfile
#ringfile=/etc/oslo/matchmaker_ring.json
[rpc_notifier2]
#
# Options defined in ironic.openstack.common.notifier.rpc_notifier2
#
# AMQP topic(s) used for OpenStack notifications (list value)
#topics=notifications
[api]
#
# Options defined in ironic.api
#
# The listen IP for the Ironic API server. (string value)
#host_ip=0.0.0.0
# The port for the Ironic API server. (integer value)
#port=6385
# The maximum number of items returned in a single response
# from a collection resource. (integer value)
#max_limit=1000
[pxe]
#
# Options defined in ironic.drivers.modules.pxe
#
# Additional append parameters for baremetal PXE boot. (string
# value)
#pxe_append_params=nofb nomodeset vga=normal
# Template file for PXE configuration. (string value)
#pxe_config_template=$pybasedir/drivers/modules/pxe_config.template
# IP address of Ironic compute node's tftp server. (string
# value)
#tftp_server=$my_ip
# Ironic compute node's tftp root path. (string value)
#tftp_root=/tftpboot
# Directory where images are stored on disk. (string value)
#images_path=/var/lib/ironic/images/
# Directory where master tftp images are stored on disk.
# (string value)
#tftp_master_path=/tftpboot/master_images
# Directory where master instance images are stored on disk.
# (string value)
#instance_master_path=/var/lib/ironic/master_images
# Neutron bootfile DHCP parameter. (string value)
#pxe_bootfile_name=pxelinux.0
[keystone_authtoken]
#
@ -791,64 +760,6 @@
#enforce_token_bind=permissive
[glance]
#
# Options defined in ironic.common.glance_service.v2.image_service
#
# A list of URL schemes that can be downloaded directly via
# the direct_url. Currently supported schemes: [file]. (list
# value)
#allowed_direct_url_schemes=
#
# Options defined in ironic.common.image_service
#
# Default glance hostname or IP address. (string value)
#glance_host=$my_ip
# Default glance port. (integer value)
#glance_port=9292
# Default protocol to use when connecting to glance. Set to
# https for SSL. (string value)
#glance_protocol=http
# A list of the glance api servers available to nova. Prefix
# with https:// for SSL-based glance API servers. Format is
# [hostname|IP]:port. (string value)
#glance_api_servers=<None>
# Allow to perform insecure SSL (https) requests to glance.
# (boolean value)
#glance_api_insecure=false
# Number of retries when downloading an image from glance.
# (integer value)
#glance_num_retries=0
# Default protocol to use when connecting to glance. Set to
# https for SSL. (string value)
#auth_strategy=keystone
[neutron]
#
# Options defined in ironic.common.neutron
#
# URL for connecting to neutron. (string value)
#url=http://127.0.0.1:9696
# Timeout value for connecting to neutron in seconds. (integer
# value)
#url_timeout=30
[matchmaker_redis]
#
@ -865,3 +776,92 @@
#password=<None>
[matchmaker_ring]
#
# Options defined in ironic.openstack.common.rpc.matchmaker_ring
#
# Matchmaker ring file (JSON) (string value)
# Deprecated group/name - [DEFAULT]/matchmaker_ringfile
#ringfile=/etc/oslo/matchmaker_ring.json
[neutron]
#
# Options defined in ironic.common.neutron
#
# URL for connecting to neutron. (string value)
#url=http://127.0.0.1:9696
# Timeout value for connecting to neutron in seconds. (integer
# value)
#url_timeout=30
[pxe]
#
# Options defined in ironic.drivers.modules.pxe
#
# Additional append parameters for baremetal PXE boot. (string
# value)
#pxe_append_params=nofb nomodeset vga=normal
# Template file for PXE configuration. (string value)
#pxe_config_template=$pybasedir/drivers/modules/pxe_config.template
# IP address of Ironic compute node's tftp server. (string
# value)
#tftp_server=$my_ip
# Ironic compute node's tftp root path. (string value)
#tftp_root=/tftpboot
# Directory where images are stored on disk. (string value)
#images_path=/var/lib/ironic/images/
# Directory where master tftp images are stored on disk.
# (string value)
#tftp_master_path=/tftpboot/master_images
# Directory where master instance images are stored on disk.
# (string value)
#instance_master_path=/var/lib/ironic/master_images
# Neutron bootfile DHCP parameter. (string value)
#pxe_bootfile_name=pxelinux.0
[rpc_notifier2]
#
# Options defined in ironic.openstack.common.notifier.rpc_notifier2
#
# AMQP topic(s) used for OpenStack notifications (list value)
#topics=notifications
[ssl]
#
# Options defined in ironic.openstack.common.sslutils
#
# CA certificate file to use to verify connecting clients
# (string value)
#ca_file=<None>
# Certificate file to use when starting the server securely
# (string value)
#cert_file=<None>
# Private key file to use when starting the server securely
# (string value)
#key_file=<None>

View File

@ -1,6 +1,5 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 SINA Corporation
# Copyright 2014 Cisco Systems, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -20,6 +19,7 @@
from __future__ import print_function
import argparse
import imp
import os
import re
@ -29,6 +29,7 @@ import textwrap
from oslo.config import cfg
import six
import stevedore.named
from ironic.openstack.common import gettextutils
from ironic.openstack.common import importutils
@ -40,6 +41,7 @@ BOOLOPT = "BoolOpt"
INTOPT = "IntOpt"
FLOATOPT = "FloatOpt"
LISTOPT = "ListOpt"
DICTOPT = "DictOpt"
MULTISTROPT = "MultiStrOpt"
OPT_TYPES = {
@ -48,11 +50,12 @@ OPT_TYPES = {
INTOPT: 'integer value',
FLOATOPT: 'floating point value',
LISTOPT: 'list value',
DICTOPT: 'dict value',
MULTISTROPT: 'multi valued',
}
OPTION_REGEX = re.compile(r"(%s)" % "|".join([STROPT, BOOLOPT, INTOPT,
FLOATOPT, LISTOPT,
FLOATOPT, LISTOPT, DICTOPT,
MULTISTROPT]))
PY_EXT = ".py"
@ -61,30 +64,54 @@ BASEDIR = os.path.abspath(os.path.join(os.path.dirname(__file__),
WORDWRAP_WIDTH = 60
def generate(srcfiles):
def generate(argv):
parser = argparse.ArgumentParser(
description='generate sample configuration file',
)
parser.add_argument('-m', dest='modules', action='append')
parser.add_argument('-l', dest='libraries', action='append')
parser.add_argument('srcfiles', nargs='*')
parsed_args = parser.parse_args(argv)
mods_by_pkg = dict()
for filepath in srcfiles:
for filepath in parsed_args.srcfiles:
pkg_name = filepath.split(os.sep)[1]
mod_str = '.'.join(['.'.join(filepath.split(os.sep)[:-1]),
os.path.basename(filepath).split('.')[0]])
mods_by_pkg.setdefault(pkg_name, list()).append(mod_str)
# NOTE(lzyeval): place top level modules before packages
pkg_names = filter(lambda x: x.endswith(PY_EXT), mods_by_pkg.keys())
pkg_names.sort()
ext_names = filter(lambda x: x not in pkg_names, mods_by_pkg.keys())
ext_names.sort()
pkg_names = sorted(pkg for pkg in mods_by_pkg if pkg.endswith(PY_EXT))
ext_names = sorted(pkg for pkg in mods_by_pkg if pkg not in pkg_names)
pkg_names.extend(ext_names)
# opts_by_group is a mapping of group name to an options list
# The options list is a list of (module, options) tuples
opts_by_group = {'DEFAULT': []}
for module_name in os.getenv(
"IRONIC_CONFIG_GENERATOR_EXTRA_MODULES", "").split(','):
module = _import_module(module_name)
if module:
for group, opts in _list_opts(module):
opts_by_group.setdefault(group, []).append((module_name, opts))
if parsed_args.modules:
for module_name in parsed_args.modules:
module = _import_module(module_name)
if module:
for group, opts in _list_opts(module):
opts_by_group.setdefault(group, []).append((module_name,
opts))
# Look for entry points defined in libraries (or applications) for
# option discovery, and include their return values in the output.
#
# Each entry point should be a function returning an iterable
# of pairs with the group name (or None for the default group)
# and the list of Opt instances for that group.
if parsed_args.libraries:
loader = stevedore.named.NamedExtensionManager(
'oslo.config.opts',
names=list(set(parsed_args.libraries)),
invoke_on_load=False,
)
for ext in loader:
for group, opts in ext.plugin():
opt_list = opts_by_group.setdefault(group or 'DEFAULT', [])
opt_list.append((ext.name, opts))
for pkg_name in pkg_names:
mods = mods_by_pkg.get(pkg_name)
@ -101,8 +128,8 @@ def generate(srcfiles):
opts_by_group.setdefault(group, []).append((mod_str, opts))
print_group_opts('DEFAULT', opts_by_group.pop('DEFAULT', []))
for group, opts in opts_by_group.items():
print_group_opts(group, opts)
for group in sorted(opts_by_group.keys()):
print_group_opts(group, opts_by_group[group])
def _import_module(mod_str):
@ -112,17 +139,17 @@ def _import_module(mod_str):
return sys.modules[mod_str[4:]]
else:
return importutils.import_module(mod_str)
except ImportError as ie:
sys.stderr.write("%s\n" % str(ie))
return None
except Exception:
except Exception as e:
sys.stderr.write("Error importing module %s: %s\n" % (mod_str, str(e)))
return None
def _is_in_group(opt, group):
"Check if opt is in group."
for key, value in group._opts.items():
if value['opt'] == opt:
for value in group._opts.values():
# NOTE(llu): Temporary workaround for bug #1262148, wait until
# newly released oslo.config support '==' operator.
if not(value['opt'] != opt):
return True
return False
@ -133,7 +160,7 @@ def _guess_groups(opt, mod_obj):
return 'DEFAULT'
# what other groups is it in?
for key, value in cfg.CONF.items():
for value in cfg.CONF.values():
if isinstance(value, cfg.CONF.GroupAttr):
if _is_in_group(opt, value._group):
return value._group.name
@ -202,7 +229,7 @@ def _sanitize_default(name, value):
return value.replace(BASEDIR, '')
elif value == _get_my_ip():
return '10.0.0.1'
elif value == socket.gethostname() and 'host' in name:
elif value in (socket.gethostname(), socket.getfqdn()) and 'host' in name:
return 'ironic'
elif value.strip() != value:
return '"%s"' % value
@ -220,7 +247,8 @@ def _print_opt(opt):
except (ValueError, AttributeError) as err:
sys.stderr.write("%s\n" % str(err))
sys.exit(1)
opt_help += ' (' + OPT_TYPES[opt_type] + ')'
opt_help = u'%s (%s)' % (opt_help,
OPT_TYPES[opt_type])
print('#', "\n# ".join(textwrap.wrap(opt_help, WORDWRAP_WIDTH)))
if opt.deprecated_opts:
for deprecated_opt in opt.deprecated_opts:
@ -250,6 +278,11 @@ def _print_opt(opt):
elif opt_type == LISTOPT:
assert(isinstance(opt_default, list))
print('#%s=%s' % (opt_name, ','.join(opt_default)))
elif opt_type == DICTOPT:
assert(isinstance(opt_default, dict))
opt_default_strlist = [str(key) + ':' + str(value)
for (key, value) in opt_default.items()]
print('#%s=%s' % (opt_name, ','.join(opt_default_strlist)))
elif opt_type == MULTISTROPT:
assert(isinstance(opt_default, list))
if not opt_default:

View File

@ -4,8 +4,8 @@ print_hint() {
echo "Try \`${0##*/} --help' for more information." >&2
}
PARSED_OPTIONS=$(getopt -n "${0##*/}" -o hb:p:o: \
--long help,base-dir:,package-name:,output-dir: -- "$@")
PARSED_OPTIONS=$(getopt -n "${0##*/}" -o hb:p:m:l:o: \
--long help,base-dir:,package-name:,output-dir:,module:,library: -- "$@")
if [ $? != 0 ] ; then print_hint ; exit 1 ; fi
@ -21,6 +21,8 @@ while true; do
echo "-b, --base-dir=DIR project base directory"
echo "-p, --package-name=NAME project package name"
echo "-o, --output-dir=DIR file output directory"
echo "-m, --module=MOD extra python module to interrogate for options"
echo "-l, --library=LIB extra library that registers options for discovery"
exit 0
;;
-b|--base-dir)
@ -38,6 +40,16 @@ while true; do
OUTPUTDIR=`echo $1 | sed -e 's/\/*$//g'`
shift
;;
-m|--module)
shift
MODULES="$MODULES -m $1"
shift
;;
-l|--library)
shift
LIBRARIES="$LIBRARIES -l $1"
shift
;;
--)
break
;;
@ -77,12 +89,20 @@ find $TARGETDIR -type f -name "*.pyc" -delete
FILES=$(find $TARGETDIR -type f -name "*.py" ! -path "*/tests/*" \
-exec grep -l "Opt(" {} + | sed -e "s/^$BASEDIRESC\///g" | sort -u)
EXTRA_MODULES_FILE="`dirname $0`/oslo.config.generator.rc"
if test -r "$EXTRA_MODULES_FILE"
RC_FILE="`dirname $0`/oslo.config.generator.rc"
if test -r "$RC_FILE"
then
source "$EXTRA_MODULES_FILE"
source "$RC_FILE"
fi
for mod in ${IRONIC_CONFIG_GENERATOR_EXTRA_MODULES}; do
MODULES="$MODULES -m $mod"
done
for lib in ${IRONIC_CONFIG_GENERATOR_EXTRA_LIBRARIES}; do
LIBRARIES="$LIBRARIES -l $lib"
done
export EVENTLET_NO_GREENDNS=yes
OS_VARS=$(set | sed -n '/^OS_/s/=[^=]*$//gp' | xargs)
@ -90,7 +110,7 @@ OS_VARS=$(set | sed -n '/^OS_/s/=[^=]*$//gp' | xargs)
DEFAULT_MODULEPATH=ironic.openstack.common.config.generator
MODULEPATH=${MODULEPATH:-$DEFAULT_MODULEPATH}
OUTPUTFILE=$OUTPUTDIR/$PACKAGENAME.conf.sample
python -m $MODULEPATH $FILES > $OUTPUTFILE
python -m $MODULEPATH $MODULES $LIBRARIES $FILES > $OUTPUTFILE
# Hook to allow projects to append custom config file snippets
CONCAT_FILES=$(ls $BASEDIR/tools/config/*.conf.sample 2>/dev/null)