Make use of oslo-config-generator

oslo_config provide a utility for generating sample config files,
which provide more detail about opts, like Minimum/Maximum value
and Allowed values.
So drop Ironic's "generate_sample.sh" which was copied from
oslo-incubator long time ago.

Add a new entry point "ironic" under oslo.config.opts namespace to
explore config options to oslo-config-generator.

After this patch, new config options of Ironic code should register
with ironic/conf/opts.py. New external libraries should
register with tools/config/ironic-config-generator.conf

There is a bug #1554657 with oslo-config about deprecated_group.
This bug have impact of some configs from keystonemiddleware
and oslo.messaging in ironic.conf.sample
So currently, deprecated option should always add the deprecated_group
even it didn't alter the group, otherwise the deprecated group value will
be 'DEFAULT'.

Update etc/ironic/ironic.conf.sample via running 'tox -egenconfig'.

Closes-Bug: #1564195
Change-Id: If7721e98e69b6f54f1ee04a07477396b86583371
This commit is contained in:
Lin Tan 2015-11-19 14:50:38 +08:00
parent 28314faae7
commit 773aa20a4a
15 changed files with 231 additions and 677 deletions

View File

@ -1,7 +1,7 @@
[DEFAULT]
#
# Options defined in ironic.api.app
# From ironic
#
# Authentication strategy used by ironic-api. "noauth" should
@ -20,11 +20,6 @@
# value)
#pecan_debug = false
#
# Options defined in ironic.common.driver_factory
#
# Specify the list of drivers to load during service
# initialization. Missing drivers, or drivers which fail to
# initialize, will prevent the conductor service from
@ -35,22 +30,12 @@
# developer documentation online. (list value)
#enabled_drivers = pxe_ipmitool
#
# Options defined in ironic.common.exception
#
# Used if there is a formatting error when generating an
# exception message (a programming error). If True, raise an
# exception; if False, use the unformatted message. (boolean
# value)
#fatal_exception_format_errors = false
#
# Options defined in ironic.common.hash_ring
#
# Exponent to determine number of hash partitions to use when
# distributing load across conductors. Larger values will
# result in more even distribution of load and less load when
@ -76,11 +61,6 @@
# value)
#hash_ring_reset_interval = 180
#
# Options defined in ironic.common.images
#
# If True, convert backing images to "raw" disk image format.
# (boolean value)
#force_raw_images = true
@ -95,11 +75,6 @@
# Template file for grub configuration file. (string value)
#grub_config_template = $pybasedir/common/grub_conf.template
#
# Options defined in ironic.common.paths
#
# Directory where the ironic python module is installed.
# (string value)
#pybasedir = /usr/lib/python/site-packages/ironic/ironic
@ -112,11 +87,6 @@
# value)
#state_path = $pybasedir
#
# Options defined in ironic.common.service
#
# Name of this node. This can be an opaque identifier. It is
# not necessarily a hostname, FQDN, or IP address. However,
# the node name must be valid within an AMQP key, and if using
@ -124,11 +94,6 @@
# value)
#host = localhost
#
# Options defined in ironic.common.utils
#
# Path to the rootwrap configuration file to use for running
# commands as root. (string value)
#rootwrap_config = /etc/ironic/rootwrap.conf
@ -137,32 +102,22 @@
# (string value)
#tempdir = /tmp
#
# Options defined in ironic.drivers.modules.image_cache
#
# Run image downloads and raw format conversions in parallel.
# (boolean value)
#parallel_image_downloads = false
#
# Options defined in ironic.netconf
#
# IP address of this host. If unset, will determine the IP
# programmatically. If unable to do so, will use "127.0.0.1".
# (string value)
#my_ip = 10.0.0.1
#my_ip = 127.0.0.1
#
# Options defined in oslo.log
# From oslo.log
#
# If set to true, the logging level will be set to DEBUG
# instead of the default INFO level. (boolean value)
# Note: This option can be changed without restarting.
#debug = false
# If set to false, the logging level will be set to WARNING
@ -261,9 +216,8 @@
# value)
#fatal_deprecations = false
#
# Options defined in oslo.messaging
# From oslo.messaging
#
# Size of RPC connection pool. (integer value)
@ -357,18 +311,16 @@
# transport_url option. (string value)
#control_exchange = openstack
#
# Options defined in oslo.service.periodic_task
# From oslo.service.periodic_task
#
# Some periodic tasks can be run in a separate process. Should
# we run them here? (boolean value)
#run_external_periodic_tasks = true
#
# Options defined in oslo.service.service
# From oslo.service.service
#
# Enable eventlet backdoor. Acceptable values are 0, <port>,
@ -400,7 +352,7 @@
[agent]
#
# Options defined in ironic.drivers.modules.agent
# From ironic
#
# Whether Ironic will manage booting of the agent ramdisk. If
@ -424,11 +376,6 @@
# be set to True. Defaults to True. (boolean value)
#stream_raw_images = true
#
# Options defined in ironic.drivers.modules.agent_base_vendor
#
# Maximum interval (in seconds) for agent heartbeats. (integer
# value)
#heartbeat_timeout = 300
@ -442,11 +389,6 @@
# state after trigger soft poweroff. (integer value)
#post_deploy_get_power_state_retry_interval = 5
#
# Options defined in ironic.drivers.modules.agent_client
#
# API version to use for communicating with the ramdisk agent.
# (string value)
#agent_api_version = v1
@ -455,7 +397,7 @@
[amt]
#
# Options defined in ironic.drivers.modules.amt.common
# From ironic
#
# Protocol used for AMT endpoint (string value)
@ -471,11 +413,6 @@
# Minimum value: 0
#awake_interval = 60
#
# Options defined in ironic.drivers.modules.amt.power
#
# Maximum number of times to attempt an AMT operation, before
# failing (integer value)
#max_attempts = 3
@ -488,7 +425,7 @@
[api]
#
# Options defined in ironic.api
# From ironic
#
# The IP address on which ironic-api listens. (string value)
@ -529,7 +466,7 @@
[cimc]
#
# Options defined in ironic.drivers.modules.cimc.power
# From ironic
#
# Number of times a power operation needs to be retried
@ -544,7 +481,7 @@
[cisco_ucs]
#
# Options defined in ironic.drivers.modules.ucs.power
# From ironic
#
# Number of times a power operation needs to be retried
@ -559,7 +496,7 @@
[conductor]
#
# Options defined in ironic.conductor.base_manager
# From ironic
#
# The size of the workers greenthread pool. Note that 2
@ -571,11 +508,6 @@
# Seconds between conductor heart beats. (integer value)
#heartbeat_interval = 10
#
# Options defined in ironic.conductor.manager
#
# URL of Ironic API service. If not set ironic can get the
# current value from the keystone service catalog. (string
# value)
@ -677,7 +609,7 @@
[console]
#
# Options defined in ironic.drivers.modules.console_utils
# From ironic
#
# Path to serial console terminal program (string value)
@ -703,7 +635,7 @@
[cors]
#
# Options defined in oslo.middleware.cors
# From oslo.middleware.cors
#
# Indicate whether this resource may be shared with the domain
@ -718,7 +650,7 @@
# Indicate which headers are safe to expose to the API.
# Defaults to HTTP Simple Headers. (list value)
#expose_headers =
#expose_headers =
# Maximum cache age of CORS preflight requests. (integer
# value)
@ -730,13 +662,13 @@
# Indicate which header field names may be used during the
# actual request. (list value)
#allow_headers =
#allow_headers =
[cors.subdomain]
#
# Options defined in oslo.middleware.cors
# From oslo.middleware.cors
#
# Indicate whether this resource may be shared with the domain
@ -751,7 +683,7 @@
# Indicate which headers are safe to expose to the API.
# Defaults to HTTP Simple Headers. (list value)
#expose_headers =
#expose_headers =
# Maximum cache age of CORS preflight requests. (integer
# value)
@ -763,21 +695,20 @@
# Indicate which header field names may be used during the
# actual request. (list value)
#allow_headers =
#allow_headers =
[database]
#
# Options defined in ironic.db.sqlalchemy.models
# From ironic
#
# MySQL engine to use. (string value)
#mysql_engine = InnoDB
#
# Options defined in oslo.db
# From oslo.db
#
# The file name to use with SQLite. (string value)
@ -889,7 +820,7 @@
[deploy]
#
# Options defined in ironic.drivers.modules.deploy_utils
# From ironic
#
# ironic-conductor node's HTTP server URL. Example:
@ -927,7 +858,7 @@
[dhcp]
#
# Options defined in ironic.common.dhcp_factory
# From ironic
#
# DHCP provider to use. "neutron" uses Neutron, and "none"
@ -938,7 +869,7 @@
[disk_partitioner]
#
# Options defined in ironic_lib.disk_partitioner
# From ironic_lib.disk_partitioner
#
# After Ironic has completed creating the partition table, it
@ -957,7 +888,7 @@
[disk_utils]
#
# Options defined in ironic_lib.disk_utils
# From ironic_lib.disk_utils
#
# Size of EFI system partition in MiB when configuring UEFI
@ -979,13 +910,13 @@
[glance]
#
# Options defined in ironic.common.glance_service.v2.image_service
# From ironic
#
# A list of URL schemes that can be downloaded directly via
# the direct_url. Currently supported schemes: [file]. (list
# value)
#allowed_direct_url_schemes =
#allowed_direct_url_schemes =
# The secret token given to Swift to allow temporary URL
# downloads. Required for temporary URLs. (string value)
@ -1065,11 +996,6 @@
# Allowed values: swift, radosgw
#temp_url_endpoint_type = swift
#
# Options defined in ironic.common.image_service
#
# Default glance hostname or IP address. (string value)
#glance_host = $my_ip
@ -1110,7 +1036,7 @@
[iboot]
#
# Options defined in ironic.drivers.modules.iboot
# From ironic
#
# Maximum retries for iBoot operations (integer value)
@ -1129,7 +1055,7 @@
[ilo]
#
# Options defined in ironic.drivers.modules.ilo.common
# From ironic
#
# Timeout (in seconds) for iLO operations (integer value)
@ -1155,21 +1081,11 @@
# (boolean value)
#use_web_server_for_images = false
#
# Options defined in ironic.drivers.modules.ilo.deploy
#
# Priority for erase devices clean step. If unset, it defaults
# to 10. If set to 0, the step will be disabled and will not
# run during cleaning. (integer value)
#clean_priority_erase_devices = <None>
#
# Options defined in ironic.drivers.modules.ilo.management
#
# Priority for reset_ilo clean step. (integer value)
#clean_priority_reset_ilo = 0
@ -1192,11 +1108,6 @@
# nodes's driver_info with the new password. (integer value)
#clean_priority_reset_ilo_credential = 30
#
# Options defined in ironic.drivers.modules.ilo.power
#
# Number of times a power operation needs to be retried
# (integer value)
#power_retry = 6
@ -1209,7 +1120,7 @@
[inspector]
#
# Options defined in ironic.drivers.modules.inspector
# From ironic
#
# whether to enable inspection using ironic-inspector (boolean
@ -1229,7 +1140,7 @@
[ipmi]
#
# Options defined in ironic.drivers.modules.ipminative
# From ironic
#
# Maximum time in seconds to retry IPMI operations. There is a
@ -1250,7 +1161,7 @@
[irmc]
#
# Options defined in ironic.drivers.modules.irmc.boot
# From ironic
#
# Ironic conductor node's "NFS" or "CIFS" root path (string
@ -1276,11 +1187,6 @@
# Domain name of remote_image_user_name (string value)
#remote_image_user_domain =
#
# Options defined in ironic.drivers.modules.irmc.common
#
# Port to be used for iRMC operations (port value)
# Allowed values: 443, 80
#port = 443
@ -1317,7 +1223,7 @@
[ironic_lib]
#
# Options defined in ironic_lib.utils
# From ironic_lib.utils
#
# Command that is prefixed to commands that are run as root.
@ -1329,7 +1235,7 @@
[iscsi]
#
# Options defined in ironic.drivers.modules.iscsi_deploy
# From ironic
#
# The port number on which the iSCSI portal listens for
@ -1342,7 +1248,7 @@
[keystone]
#
# Options defined in ironic.common.keystone
# From ironic
#
# The region used for getting endpoints of OpenStack services.
@ -1353,7 +1259,7 @@
[keystone_authtoken]
#
# Options defined in keystonemiddleware.auth_token
# From keystonemiddleware.auth_token
#
# Complete public Identity API endpoint. (string value)
@ -1405,7 +1311,7 @@
# Optionally specify a list of memcached server(s) to use for
# caching. If left undefined, tokens will instead be cached
# in-process. (list value)
# Deprecated group/name - [keystone_authtoken]/memcache_servers
# Deprecated group/name - [DEFAULT]/memcache_servers
#memcached_servers = <None>
# In order to prevent excessive effort spent validating
@ -1496,7 +1402,7 @@
#hash_algorithms = md5
# Authentication type to load (unknown value)
# Deprecated group/name - [keystone_authtoken]/auth_plugin
# Deprecated group/name - [DEFAULT]/auth_plugin
#auth_type = <None>
# Config Section from which to load plugin specific options
@ -1507,7 +1413,7 @@
[matchmaker_redis]
#
# Options defined in oslo.messaging
# From oslo.messaging
#
# Host to locate redis. (string value)
@ -1523,7 +1429,7 @@
# List of Redis Sentinel hosts (fault tolerance mode) e.g.
# [host:port, host1:port ... ] (list value)
#sentinel_hosts =
#sentinel_hosts =
# Redis replica set name. (string value)
#sentinel_group_name = oslo-messaging-zeromq
@ -1543,7 +1449,7 @@
[neutron]
#
# Options defined in ironic.dhcp.neutron
# From ironic
#
# URL for connecting to neutron. (string value)
@ -1577,7 +1483,7 @@
[oneview]
#
# Options defined in ironic.drivers.modules.oneview.common
# From ironic
#
# URL where OneView is available (string value)
@ -1604,7 +1510,7 @@
[oslo_concurrency]
#
# Options defined in oslo.concurrency
# From oslo.concurrency
#
# Enables or disables inter-process locks. (boolean value)
@ -1623,7 +1529,7 @@
[oslo_messaging_amqp]
#
# Options defined in oslo.messaging
# From oslo.messaging
#
# address prefix used when sending to a specific server
@ -1705,14 +1611,14 @@
[oslo_messaging_notifications]
#
# Options defined in oslo.messaging
# From oslo.messaging
#
# The Drivers(s) to handle sending notifications. Possible
# values are messaging, messagingv2, routing, log, test, noop
# (multi valued)
# Deprecated group/name - [DEFAULT]/notification_driver
#driver =
#driver =
# A URL representing the messaging driver to use for
# notifications. If not set, we fall back to the same
@ -1729,7 +1635,7 @@
[oslo_messaging_rabbit]
#
# Options defined in oslo.messaging
# From oslo.messaging
#
# Use durable queues in AMQP. (boolean value)
@ -1773,7 +1679,7 @@
# How long to wait a missing client beforce abandoning to send
# it its replies. This value should not be longer than
# rpc_response_timeout. (integer value)
# Deprecated group/name - [oslo_messaging_rabbit]/kombu_reconnect_timeout
# Deprecated group/name - [DEFAULT]/kombu_reconnect_timeout
#kombu_missing_consumer_retry_timeout = 60
# Determines how the next RabbitMQ node is chosen in case the
@ -1983,7 +1889,7 @@
[oslo_policy]
#
# Options defined in oslo.policy
# From oslo.policy
#
# The JSON file that defines policies. (string value)
@ -2008,7 +1914,7 @@
[pxe]
#
# Options defined in ironic.drivers.modules.iscsi_deploy
# From ironic
#
# Additional append parameters for baremetal PXE boot. (string
@ -2040,11 +1946,6 @@
# value)
#disk_devices = cciss/c0d0,sda,hda,vda
#
# Options defined in ironic.drivers.modules.pxe
#
# On ironic-conductor node, template file for PXE
# configuration. (string value)
#pxe_config_template = $pybasedir/drivers/modules/pxe_config.template
@ -2092,7 +1993,7 @@
[seamicro]
#
# Options defined in ironic.drivers.modules.seamicro
# From ironic
#
# Maximum retries for SeaMicro operations (integer value)
@ -2106,7 +2007,7 @@
[snmp]
#
# Options defined in ironic.drivers.modules.snmp
# From ironic
#
# Seconds to wait for power action to be completed (integer
@ -2122,7 +2023,7 @@
[ssh]
#
# Options defined in ironic.drivers.modules.ssh
# From ironic
#
# libvirt URI. (string value)
@ -2141,7 +2042,7 @@
[ssl]
#
# Options defined in oslo.service.sslutils
# From oslo.service.sslutils
#
# CA certificate file to use to verify connecting clients.
@ -2172,7 +2073,7 @@
[swift]
#
# Options defined in ironic.common.swift
# From ironic
#
# Maximum number of times to retry a Swift request, before
@ -2183,7 +2084,7 @@
[virtualbox]
#
# Options defined in ironic.drivers.modules.virtualbox
# From ironic
#
# Port on which VirtualBox web service is listening. (port
@ -2191,5 +2092,3 @@
# Minimum value: 0
# Maximum value: 65535
#port = 18083

View File

@ -1,375 +0,0 @@
# Copyright 2012 SINA Corporation
# Copyright 2014 Cisco Systems, 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.
#
"""Extracts OpenStack config option info from module(s)."""
# NOTE(GheRivero): Copied from oslo_incubator before getting removed in
# Change-Id: If15b77d31a8c615aad8fca30f6dd9928da2d08bb
from __future__ import print_function
import argparse
import imp
import os
import re
import socket
import sys
import tempfile
import textwrap
import mock
from oslo_config import cfg
import oslo_i18n
from oslo_utils import importutils
import six
import stevedore.named
oslo_i18n.install('ironic')
OPT = "Opt"
STROPT = "StrOpt"
BOOLOPT = "BoolOpt"
INTOPT = "IntOpt"
FLOATOPT = "FloatOpt"
LISTOPT = "ListOpt"
DICTOPT = "DictOpt"
MULTISTROPT = "MultiStrOpt"
PORTOPT = "PortOpt"
OPT_TYPES = {
OPT: 'unknown value',
STROPT: 'string value',
BOOLOPT: 'boolean value',
INTOPT: 'integer value',
FLOATOPT: 'floating point value',
LISTOPT: 'list value',
DICTOPT: 'dict value',
MULTISTROPT: 'multi valued',
PORTOPT: 'port value',
}
OPTION_REGEX = re.compile(r"(%s)" % "|".join(OPT_TYPES))
PY_EXT = ".py"
BASEDIR = os.path.abspath(os.path.join(os.path.dirname(__file__),
"../../../../"))
WORDWRAP_WIDTH = 60
def raise_extension_exception(extmanager, ep, err):
raise
# Don't let the system hostname or FQDN affect config file values. Certain 3rd
# party libraries use either 'gethostbyname' or 'getfqdn' to set the default
# value.
@mock.patch.object(socket, 'gethostname', lambda: 'localhost')
@mock.patch.object(socket, 'getfqdn', lambda: 'localhost')
@mock.patch.object(tempfile, 'gettempdir', lambda: '/tmp')
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 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 = 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': []}
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,
on_load_failure_callback=raise_extension_exception
)
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)
mods.sort()
for mod_str in mods:
if mod_str.endswith('.__init__'):
mod_str = mod_str[:mod_str.rfind(".")]
mod_obj = _import_module(mod_str)
if not mod_obj:
raise RuntimeError("Unable to import module %s" % mod_str)
for group, opts in _list_opts(mod_obj):
opts_by_group.setdefault(group, []).append((mod_str, opts))
print_group_opts('DEFAULT', opts_by_group.pop('DEFAULT', []))
for group in sorted(opts_by_group.keys()):
print_group_opts(group, opts_by_group[group])
def _import_module(mod_str):
try:
if mod_str.startswith('bin.'):
imp.load_source(mod_str[4:], os.path.join('bin', mod_str[4:]))
return sys.modules[mod_str[4:]]
else:
return importutils.import_module(mod_str)
except Exception as e:
sys.stderr.write("Error importing module %s: %s\n" % (mod_str, e))
return None
def _is_in_group(opt, group):
"""Check if opt is in group."""
for value in group._opts.values():
if value['opt'] is opt:
return True
return False
def _guess_groups(opt):
# is it in the DEFAULT group?
if _is_in_group(opt, cfg.CONF):
return 'DEFAULT'
# what other groups is it in?
for value in cfg.CONF.values():
if isinstance(value, cfg.CONF.GroupAttr):
if _is_in_group(opt, value._group):
return value._group.name
raise RuntimeError(
"Unable to find group for option %s, "
"maybe it's defined twice in the same group?"
% opt.name
)
def _list_opts(obj):
def is_opt(o):
return (isinstance(o, cfg.Opt) and
not isinstance(o, cfg.SubCommandOpt))
opts = list()
if 'list_opts' in dir(obj):
group_opts = getattr(obj, 'list_opts')()
# NOTE(GheRivero): Options without a defined group,
# must be registered to the DEFAULT section
fixed_list = []
for section, opts in group_opts:
if not section:
section = 'DEFAULT'
fixed_list.append((section, opts))
return fixed_list
for attr_str in dir(obj):
attr_obj = getattr(obj, attr_str)
if is_opt(attr_obj):
opts.append(attr_obj)
elif (isinstance(attr_obj, list) and
all(map(lambda x: is_opt(x), attr_obj))):
opts.extend(attr_obj)
ret = {}
for opt in opts:
ret.setdefault(_guess_groups(opt), []).append(opt)
return ret.items()
def print_group_opts(group, opts_by_module):
print("[%s]" % group)
print('')
for mod, opts in sorted(opts_by_module, key=lambda x: x[0]):
print('#')
print('# Options defined in %s' % mod)
print('#')
print('')
for opt in opts:
_print_opt(opt, group)
print('')
def _get_choice_text(choice):
if choice is None:
return '<None>'
elif choice == '':
return "''"
return six.text_type(choice)
def _get_my_ip():
try:
csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
csock.connect(('8.8.8.8', 80))
(addr, port) = csock.getsockname()
csock.close()
return addr
except socket.error:
return None
def _sanitize_default(name, value):
"""Set up a reasonably sensible default for pybasedir, my_ip and host."""
if value.startswith(sys.prefix):
# NOTE(jd) Don't use os.path.join, because it is likely to think the
# second part is an absolute pathname and therefore drop the first
# part.
value = os.path.normpath("/usr/" + value[len(sys.prefix):])
elif value.startswith(BASEDIR):
return value.replace(BASEDIR, '/usr/lib/python/site-packages')
elif BASEDIR in value:
return value.replace(BASEDIR, '')
elif value == _get_my_ip():
return '10.0.0.1'
elif value.strip() != value:
return '"%s"' % value
return value
def _print_opt(opt, group):
opt_name, opt_default, opt_help = opt.dest, opt.default, opt.help
if not opt_help:
sys.stderr.write('WARNING: "%s" is missing help string.\n' % opt_name)
opt_help = ""
result = OPTION_REGEX.search(str(type(opt)))
if not result:
raise ValueError(
"Config option: {!r} Unknown option type: {}\n".format(
opt_name, type(opt)))
opt_type = result.group(0)
opt_help = u'%s (%s)' % (opt_help,
OPT_TYPES[opt_type])
print('#', "\n# ".join(textwrap.wrap(opt_help, WORDWRAP_WIDTH)))
min_value = getattr(opt.type, 'min', None)
max_value = getattr(opt.type, 'max', None)
choices = getattr(opt.type, 'choices', None)
# NOTE(lintan): choices are mutually exclusive with 'min/max',
# see oslo.config for more details.
if min_value is not None:
print('# Minimum value: %d' % min_value)
if max_value is not None:
print('# Maximum value: %d' % max_value)
if choices is not None:
if choices == []:
print('# No possible values.')
else:
choices_text = ', '.join([_get_choice_text(choice)
for choice in choices])
print('# Allowed values: %s' % choices_text)
if opt.deprecated_opts:
for deprecated_opt in opt.deprecated_opts:
deprecated_name = (deprecated_opt.name if
deprecated_opt.name else opt_name)
deprecated_group = (deprecated_opt.group if
deprecated_opt.group else group)
print('# Deprecated group/name - [%s]/%s' %
(deprecated_group,
deprecated_name))
if opt.deprecated_for_removal:
print('# This option is deprecated for removal.')
print('# Its value may be silently ignored in the future.')
try:
if opt_default is None:
print('#%s = <None>' % opt_name)
else:
_print_type(opt_type, opt_name, opt_default)
print('')
except Exception as e:
sys.stderr.write('Error in option "%s": %s\n' % (opt_name, e))
sys.exit(1)
def _print_type(opt_type, opt_name, opt_default):
if opt_type == OPT:
print('#%s = %s' % (opt_name, opt_default))
elif opt_type == STROPT:
assert(isinstance(opt_default, six.string_types))
value = _sanitize_default(opt_name, opt_default)
if value:
print('#%s = %s' % (opt_name, value))
else:
print('#%s =' % (opt_name))
elif opt_type == BOOLOPT:
assert(isinstance(opt_default, bool))
print('#%s = %s' % (opt_name, str(opt_default).lower()))
elif opt_type == INTOPT:
assert(isinstance(opt_default, int) and
not isinstance(opt_default, bool))
print('#%s = %s' % (opt_name, opt_default))
elif opt_type == PORTOPT:
assert(isinstance(opt_default, int) and
not isinstance(opt_default, bool))
print('#%s = %s' % (opt_name, opt_default))
elif opt_type == FLOATOPT:
assert(isinstance(opt_default, float))
print('#%s = %s' % (opt_name, opt_default))
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:
opt_default = ['']
for default in opt_default:
print('#%s = %s' % (opt_name, default))
else:
raise ValueError("unknown oslo_config type %s" % opt_type)
def main():
generate(sys.argv[1:])
if __name__ == '__main__':
main()

View File

@ -25,6 +25,7 @@ path_opts = [
cfg.StrOpt('pybasedir',
default=os.path.abspath(os.path.join(os.path.dirname(__file__),
'../')),
sample_default='/usr/lib/python/site-packages/ironic/ironic',
help=_('Directory where the ironic python module is '
'installed.')),
cfg.StrOpt('bindir',

View File

@ -40,6 +40,7 @@ from ironic.objects import base as objects_base
service_opts = [
cfg.StrOpt('host',
default=socket.getfqdn(),
sample_default='localhost',
help=_('Name of this node. This can be an opaque identifier. '
'It is not necessarily a hostname, FQDN, or IP address. '
'However, the node name must be valid within '

View File

@ -49,6 +49,7 @@ utils_opts = [
'running commands as root.')),
cfg.StrOpt('tempdir',
default=tempfile.gettempdir(),
sample_default='/tmp',
help=_('Temporary working directory, default is Python temp '
'dir.')),
]

137
ironic/conf/opts.py Normal file
View File

@ -0,0 +1,137 @@
# 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 itertools
import ironic.api
import ironic.api.app
import ironic.common.dhcp_factory
import ironic.common.driver_factory
import ironic.common.exception
import ironic.common.glance_service.v2.image_service
import ironic.common.hash_ring
import ironic.common.image_service
import ironic.common.images
import ironic.common.keystone
import ironic.common.paths
import ironic.common.service
import ironic.common.swift
import ironic.common.utils
import ironic.conductor.base_manager
import ironic.conductor.manager
import ironic.db.sqlalchemy.models
import ironic.dhcp.neutron
import ironic.drivers.modules.agent
import ironic.drivers.modules.agent_base_vendor
import ironic.drivers.modules.agent_client
import ironic.drivers.modules.amt.common
import ironic.drivers.modules.amt.power
import ironic.drivers.modules.cimc.power
import ironic.drivers.modules.console_utils
import ironic.drivers.modules.deploy_utils
import ironic.drivers.modules.iboot
import ironic.drivers.modules.ilo.common
import ironic.drivers.modules.ilo.deploy
import ironic.drivers.modules.ilo.management
import ironic.drivers.modules.ilo.power
import ironic.drivers.modules.image_cache
import ironic.drivers.modules.inspector
import ironic.drivers.modules.ipminative
import ironic.drivers.modules.irmc.boot
import ironic.drivers.modules.irmc.common
import ironic.drivers.modules.iscsi_deploy
import ironic.drivers.modules.oneview.common
import ironic.drivers.modules.pxe
import ironic.drivers.modules.seamicro
import ironic.drivers.modules.snmp
import ironic.drivers.modules.ssh
import ironic.drivers.modules.ucs.power
import ironic.drivers.modules.virtualbox
import ironic.netconf
_default_opt_lists = [
ironic.api.app.api_opts,
ironic.common.driver_factory.driver_opts,
ironic.common.exception.exc_log_opts,
ironic.common.hash_ring.hash_opts,
ironic.common.images.image_opts,
ironic.common.paths.path_opts,
ironic.common.service.service_opts,
ironic.common.utils.utils_opts,
ironic.drivers.modules.image_cache.img_cache_opts,
ironic.netconf.netconf_opts,
]
_opts = [
('DEFAULT', itertools.chain(*_default_opt_lists)),
('agent', itertools.chain(
ironic.drivers.modules.agent.agent_opts,
ironic.drivers.modules.agent_base_vendor.agent_opts,
ironic.drivers.modules.agent_client.agent_opts)),
('amt', itertools.chain(
ironic.drivers.modules.amt.common.opts,
ironic.drivers.modules.amt.power.opts)),
('api', ironic.api.API_SERVICE_OPTS),
('cimc', ironic.drivers.modules.cimc.power.opts),
('cisco_ucs', ironic.drivers.modules.ucs.power.opts),
('conductor', itertools.chain(
ironic.conductor.base_manager.conductor_opts,
ironic.conductor.manager.conductor_opts)),
('console', ironic.drivers.modules.console_utils.opts),
('database', ironic.db.sqlalchemy.models.sql_opts),
('deploy', ironic.drivers.modules.deploy_utils.deploy_opts),
('dhcp', ironic.common.dhcp_factory.dhcp_provider_opts),
('glance', itertools.chain(
ironic.common.glance_service.v2.image_service.glance_opts,
ironic.common.image_service.glance_opts)),
('iboot', ironic.drivers.modules.iboot.opts),
('ilo', itertools.chain(
ironic.drivers.modules.ilo.common.opts,
ironic.drivers.modules.ilo.deploy.clean_opts,
ironic.drivers.modules.ilo.management.clean_step_opts,
ironic.drivers.modules.ilo.power.opts)),
('inspector', ironic.drivers.modules.inspector.inspector_opts),
('ipmi', ironic.drivers.modules.ipminative.opts),
('irmc', itertools.chain(
ironic.drivers.modules.irmc.boot.opts,
ironic.drivers.modules.irmc.common.opts)),
('iscsi', ironic.drivers.modules.iscsi_deploy.iscsi_opts),
('keystone', ironic.common.keystone.keystone_opts),
('neutron', ironic.dhcp.neutron.neutron_opts),
('oneview', ironic.drivers.modules.oneview.common.opts),
('pxe', itertools.chain(
ironic.drivers.modules.iscsi_deploy.pxe_opts,
ironic.drivers.modules.pxe.pxe_opts)),
('seamicro', ironic.drivers.modules.seamicro.opts),
('snmp', ironic.drivers.modules.snmp.opts),
('ssh', ironic.drivers.modules.ssh.libvirt_opts),
('swift', ironic.common.swift.swift_opts),
('virtualbox', ironic.drivers.modules.virtualbox.opts),
]
def list_opts():
"""Return a list of oslo.config options available in Ironic code.
The returned list includes all oslo.config options. Each element of
the list is a tuple. The first element is the name of the group, the
second element is the options.
The function is discoverable via the 'ironic' entry point under the
'oslo.config.opts' namespace.
The function is used by Oslo sample config file generator to discover the
options.
:returns: a list of (group, options) tuples
"""
return _opts

View File

@ -25,6 +25,7 @@ CONF = cfg.CONF
netconf_opts = [
cfg.StrOpt('my_ip',
default=netutils.get_my_ipv4(),
sample_default='127.0.0.1',
help=_('IP address of this host. If unset, will determine the '
'IP programmatically. If unable to do so, will use '
'"127.0.0.1".')),

View File

@ -0,0 +1,9 @@
---
other:
Adopt oslo-config-generator to generate sample config files.
New config options from Ironic code should register with
ironic/conf/opts.py. New external libraries should register
with tools/config/ironic-config-generator.conf.
A deprecated option should add a deprecated group even if it
didn't alter its group, otherwise the deprecated group will
use 'DEFAULT' by default.

View File

@ -22,6 +22,9 @@ packages =
ironic_tempest_plugin
[entry_points]
oslo.config.opts =
ironic = ironic.conf.opts:list_opts
console_scripts =
ironic-api = ironic.cmd.api:main
ironic-dbsync = ironic.cmd.dbsync:main

View File

@ -2,6 +2,7 @@
PROJECT_NAME=${PROJECT_NAME:-ironic}
CFGFILE_NAME=${PROJECT_NAME}.conf.sample
OSLO_CFGFILE_OPTION=${OSLO_CFGFILE_OPTION:-tools/config/ironic-config-generator.conf}
if [ -e etc/${PROJECT_NAME}/${CFGFILE_NAME} ]; then
CFGFILE=etc/${PROJECT_NAME}/${CFGFILE_NAME}
@ -15,7 +16,7 @@ fi
TEMPDIR=`mktemp -d /tmp/${PROJECT_NAME}.XXXXXX`
trap "rm -rf $TEMPDIR" EXIT
tools/config/generate_sample.sh -b ./ -p ${PROJECT_NAME} -o ${TEMPDIR}
oslo-config-generator --config-file=${OSLO_CFGFILE_OPTION} --output-file ${TEMPDIR}/${CFGFILE_NAME}
if [ $? != 0 ]
then
exit 1
@ -24,6 +25,6 @@ fi
if ! diff -u ${TEMPDIR}/${CFGFILE_NAME} ${CFGFILE}
then
echo "${0##*/}: ${PROJECT_NAME}.conf.sample is not up to date."
echo "${0##*/}: Please run ${0%%${0##*/}}generate_sample.sh."
echo "${0##*/}: Please run oslo-config-generator --config-file=${OSLO_CFGFILE_OPTION}"
exit 1
fi

View File

@ -1,138 +0,0 @@
#!/usr/bin/env bash
# Generate sample configuration for your project.
#
# Aside from the command line flags, it also respects a config file which
# should be named oslo.config.generator.rc and be placed in the same directory.
#
# You can then export the following variables:
# IRONIC_CONFIG_GENERATOR_EXTRA_MODULES: list of modules to interrogate for options.
# IRONIC_CONFIG_GENERATOR_EXTRA_LIBRARIES: list of libraries to discover.
# IRONIC_CONFIG_GENERATOR_EXCLUDED_FILES: list of files to remove from automatic listing.
print_hint() {
echo "Try \`${0##*/} --help' for more information." >&2
}
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
eval set -- "$PARSED_OPTIONS"
while true; do
case "$1" in
-h|--help)
echo "${0##*/} [options]"
echo ""
echo "options:"
echo "-h, --help show brief help"
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)
shift
BASEDIR=`echo $1 | sed -e 's/\/*$//g'`
shift
;;
-p|--package-name)
shift
PACKAGENAME=`echo $1`
shift
;;
-o|--output-dir)
shift
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
;;
esac
done
BASEDIR=${BASEDIR:-`pwd`}
if ! [ -d $BASEDIR ]
then
echo "${0##*/}: missing project base directory" >&2 ; print_hint ; exit 1
elif [[ $BASEDIR != /* ]]
then
BASEDIR=$(cd "$BASEDIR" && pwd)
fi
PACKAGENAME=${PACKAGENAME:-$(python setup.py --name)}
TARGETDIR=$BASEDIR/$PACKAGENAME
if ! [ -d $TARGETDIR ]
then
echo "${0##*/}: invalid project package name" >&2 ; print_hint ; exit 1
fi
OUTPUTDIR=${OUTPUTDIR:-$BASEDIR/etc}
# NOTE(bnemec): Some projects put their sample config in etc/,
# some in etc/$PACKAGENAME/
if [ -d $OUTPUTDIR/$PACKAGENAME ]
then
OUTPUTDIR=$OUTPUTDIR/$PACKAGENAME
elif ! [ -d $OUTPUTDIR ]
then
echo "${0##*/}: cannot access \`$OUTPUTDIR': No such file or directory" >&2
exit 1
fi
BASEDIRESC=`echo $BASEDIR | sed -e 's/\//\\\\\//g'`
find $TARGETDIR -type f -name "*.pyc" -delete
FILES=$(find $TARGETDIR -type f -name "*.py" ! -path "*/tests/*" ! -path "*/nova/*" \
-exec grep -l "Opt(" {} + | sed -e "s/^$BASEDIRESC\///g" | sort -u)
RC_FILE="`dirname $0`/oslo.config.generator.rc"
if test -r "$RC_FILE"
then
source "$RC_FILE"
fi
for filename in ${IRONIC_CONFIG_GENERATOR_EXCLUDED_FILES}; do
FILES="${FILES[@]/$filename/}"
done
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)
[ "$OS_VARS" ] && eval "unset \$OS_VARS"
DEFAULT_CONFIG_GENERATOR=ironic.common.config_generator.generator
CONFIG_GENERATOR=${CONFIG_GENERATOR:-$DEFAULT_CONFIG_GENERATOR}
OUTPUTFILE=$OUTPUTDIR/$PACKAGENAME.conf.sample
python -m $CONFIG_GENERATOR $MODULES $LIBRARIES $FILES > $OUTPUTFILE
if [ $? != 0 ]
then
echo "Can not generate $OUTPUTFILE"
exit 1
fi
# Hook to allow projects to append custom config file snippets
CONCAT_FILES=$(ls $BASEDIR/tools/config/*.conf.sample 2>/dev/null)
for CONCAT_FILE in $CONCAT_FILES; do
cat $CONCAT_FILE >> $OUTPUTFILE
done

View File

@ -0,0 +1,17 @@
[DEFAULT]
output_file = etc/ironic/ironic.conf.sample
wrap_width = 62
namespace = ironic
namespace = ironic_lib.disk_utils
namespace = ironic_lib.disk_partitioner
namespace = ironic_lib.utils
namespace = oslo.db
namespace = oslo.messaging
namespace = oslo.middleware.cors
namespace = oslo.concurrency
namespace = oslo.policy
namespace = oslo.log
namespace = oslo.service.service
namespace = oslo.service.periodic_task
namespace = oslo.service.sslutils
namespace = keystonemiddleware.auth_token

View File

@ -1,2 +0,0 @@
export IRONIC_CONFIG_GENERATOR_EXTRA_LIBRARIES='oslo.db oslo.messaging oslo.middleware.cors keystonemiddleware.auth_token oslo.concurrency oslo.policy oslo.log oslo.service.service oslo.service.periodic_task oslo.service.sslutils'
export IRONIC_CONFIG_GENERATOR_EXTRA_MODULES='ironic_lib.disk_utils ironic_lib.disk_partitioner ironic_lib.utils'

View File

@ -53,11 +53,10 @@ commands =
{toxinidir}/tools/config/check_uptodate.sh
[testenv:genconfig]
whitelist_externals = bash
sitepackages = False
envdir = {toxworkdir}/venv
commands =
bash tools/config/generate_sample.sh -b . -p ironic -o etc/ironic
oslo-config-generator --config-file=tools/config/ironic-config-generator.conf
[testenv:docs]
setenv = PYTHONHASHSEED=0