single point of entry for sample config generation

To create a "nova.conf.sample" file, we use "tox -e genconfig".
This command triggers the generator from "oslo.config" which needs
entry points in "setup.cfg". Right now we have multiple entry points
to "opts.py" files which are going to be consolidated to one single
point of entry "nova/conf/opts.py". Until all config options are
moved to that central place, we would often face merge conflicts
when multiple contributors commit patches to that one "opts.py".

To prevent that, and to make it easier for future config option
moduls in "nova/conf/", the new "nova/conf/opts.py" module collects
the config options in a dynamic way.

Co-Author: EdLeafe <ed@leafe.com>

bp centralize-config-options

Change-Id: I4e5d643cd93bb2822ff59c71669cedf3de7f86fc
This commit is contained in:
Markus Zoeller 2015-12-21 14:37:15 +01:00 committed by EdLeafe
parent ce34000c85
commit 627fde8832
12 changed files with 103 additions and 36 deletions

View File

@ -2,12 +2,12 @@
output_file = etc/nova/nova.conf.sample
wrap_width = 79
namespace = nova
namespace = nova.conf
namespace = nova.api
namespace = nova.cells
namespace = nova.compute
namespace = nova.network
namespace = nova.network.neutronv2
namespace = nova.scheduler
namespace = nova.virt
namespace = nova.openstack.common.memorycache
namespace = oslo.log

View File

@ -24,7 +24,6 @@ def list_opts():
return [
('DEFAULT',
itertools.chain(
nova.conf.compute.compute_opts,
nova.compute.flavors.flavor_opts,
nova.compute.manager.compute_opts,
nova.compute.manager.instance_cleaning_opts,
@ -36,8 +35,6 @@ def list_opts():
nova.compute.resource_tracker.allocation_ratio_opts,
nova.compute.rpcapi.rpcapi_opts,
)),
('ephemeral_storage_encryption',
nova.conf.ephemeral_storage.ephemeral_storage_encryption_opts),
('upgrade_levels',
itertools.chain(
[nova.compute.rpcapi.rpcapi_cap_opt],

View File

@ -63,4 +63,4 @@ def register_opts(conf):
def list_opts():
return compute_opts
return {'DEFAULT': compute_opts}

View File

@ -45,4 +45,4 @@ def register_opts(conf):
def list_opts():
return ephemeral_storage_encryption_opts
return {'ephemeral_storage_encryption': ephemeral_storage_encryption_opts}

View File

@ -95,4 +95,4 @@ def list_opts():
# As soon as this bug is fixed is oslo.config and Nova uses the
# version which contains this fix, we can pass in the OptGroup instead
# of its name. This allows the generation of the group help too.
return (ironic_group.name, ALL_OPTS)
return {ironic_group.name: ALL_OPTS}

89
nova/conf/opts.py Normal file
View File

@ -0,0 +1,89 @@
# Copyright 2015 OpenStack Foundation
# 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.
"""
This is the single point of entry to generate the sample configuration
file for Nova. It collects all the necessary info from the other modules
in this package. It is assumed that:
* every other module in this package has a 'list_opts' function which
return a dict where
* the keys are strings which are the group names
* the value of each key is a list of config options for that group
* the nova.conf package doesn't have further packages with config options
* this module is only used in the context of sample file generation
"""
import collections
import importlib
import os
import pkgutil
LIST_OPTS_FUNC_NAME = "list_opts"
def _tupleize(dct):
"""Take the dict of options and convert to the 2-tuple format."""
return [(key, val) for key, val in dct.items()]
def list_opts():
opts = collections.defaultdict(list)
module_names = _list_module_names()
imported_modules = _import_modules(module_names)
_append_config_options(imported_modules, opts)
return _tupleize(opts)
def _list_module_names():
module_names = []
package_path = os.path.dirname(os.path.abspath(__file__))
for _, modname, ispkg in pkgutil.iter_modules(path=[package_path]):
if modname == "opts" or ispkg:
continue
else:
module_names.append(modname)
return module_names
def _import_modules(module_names):
imported_modules = []
for modname in module_names:
mod = importlib.import_module("nova.conf." + modname)
if not hasattr(mod, LIST_OPTS_FUNC_NAME):
msg = "The module 'nova.conf.%s' should have a '%s' "\
"function which returns the config options." % \
(LIST_OPTS_FUNC_NAME, modname)
raise Exception(msg)
else:
imported_modules.append(mod)
return imported_modules
def _process_old_opts(configs):
"""Convert old-style 2-tuple configs to dicts."""
if isinstance(configs, tuple):
configs = [configs]
return {label: options for label, options in configs}
def _append_config_options(imported_modules, config_options):
for mod in imported_modules:
configs = mod.list_opts()
# TODO(markus_z): Remove this compatibility shim once all list_opts()
# functions have been updated to return dicts.
if not isinstance(configs, dict):
configs = _process_old_opts(configs)
for key, val in configs.items():
config_options[key].extend(val)

View File

@ -250,3 +250,11 @@ def register_opts(conf):
conf.register_group(trust_group)
conf.register_opts(trusted_opts, group=trust_group)
conf.register_opts(metrics_weight_opts, group="metrics")
def list_opts():
return {"DEFAULT": SIMPLE_OPTS,
"upgrade_levels": [rpcapi_cap_opt],
"trusted_computing": trusted_opts,
"metrics": metrics_weight_opts,
}

View File

@ -200,4 +200,4 @@ def list_opts():
# As soon as this bug is fixed is oslo.config and Nova uses the
# version which contains this fix, we can pass in the OptGroup instead
# of its name. This allows the generation of the group help too.
return (serial_opt_group.name, ALL_OPTS)
return {serial_opt_group.name: ALL_OPTS}

View File

@ -116,7 +116,6 @@ def list_opts():
nova.keymgr.keymgr_opts,
)),
('rdp', nova.rdp.rdp_opts),
nova.conf.serial_console.list_opts(),
('spice',
itertools.chain(
nova.cmd.spicehtml5proxy.opts,

View File

@ -1,25 +0,0 @@
# 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 nova.conf.scheduler
def list_opts():
return [
('DEFAULT',
nova.conf.scheduler.SIMPLE_OPTS),
('metrics', nova.conf.scheduler.metrics_weight_opts),
('trusted_computing',
nova.conf.scheduler.trusted_opts),
('upgrade_levels',
[nova.conf.scheduler.rpcapi_cap_opt]),
]

View File

@ -72,7 +72,6 @@ def list_opts():
nova.virt.hyperv.vmops.hyperv_opts,
nova.virt.hyperv.volumeops.hyper_volumeops_opts,
)),
nova.conf.ironic.list_opts(),
('libvirt',
itertools.chain(
nova.virt.libvirt.driver.libvirt_opts,

View File

@ -27,12 +27,12 @@ packages =
[entry_points]
oslo.config.opts =
nova = nova.opts:list_opts
nova.conf = nova.conf.opts:list_opts
nova.api = nova.api.opts:list_opts
nova.cells = nova.cells.opts:list_opts
nova.compute = nova.compute.opts:list_opts
nova.network = nova.network.opts:list_opts
nova.network.neutronv2 = nova.network.neutronv2.api:list_opts
nova.scheduler = nova.scheduler.opts:list_opts
nova.virt = nova.virt.opts:list_opts
nova.openstack.common.memorycache = nova.openstack.common.memorycache:list_opts