move some documentation out of the source files
The cfg module is very large, and starts with a huge block of documentation. This patch moves that information into separate files in the reference section of the docs. A few formatting fixes need to be made to have it build cleanly, but the content is not changed in a substantive way. Change-Id: I86aa90bbf180b5dc9acbcedb024e5361d49954c3 Signed-off-by: Doug Hellmann <doug@doughellmann.com>
This commit is contained in:
parent
ce150b1037
commit
bd463ee3b6
16
doc/source/reference/accessing.rst
Normal file
16
doc/source/reference/accessing.rst
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
======================================
|
||||||
|
Accessing Option Values In Your Code
|
||||||
|
======================================
|
||||||
|
|
||||||
|
Option values in the default group are referenced as attributes/properties on
|
||||||
|
the config manager; groups are also attributes on the config manager, with
|
||||||
|
attributes for each of the options associated with the group:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
server.start(app, conf.bind_port, conf.bind_host, conf)
|
||||||
|
|
||||||
|
self.connection = kombu.connection.BrokerConnection(
|
||||||
|
hostname=conf.rabbit.host,
|
||||||
|
port=conf.rabbit.port,
|
||||||
|
...)
|
@ -1,5 +0,0 @@
|
|||||||
--------------
|
|
||||||
The cfg Module
|
|
||||||
--------------
|
|
||||||
|
|
||||||
.. automodule:: oslo_config.cfg
|
|
37
doc/source/reference/command-line.rst
Normal file
37
doc/source/reference/command-line.rst
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
======================
|
||||||
|
Command Line Options
|
||||||
|
======================
|
||||||
|
|
||||||
|
Positional Command Line Arguments
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
Positional command line arguments are supported via a 'positional' Opt
|
||||||
|
constructor argument:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
>>> conf = cfg.ConfigOpts()
|
||||||
|
>>> conf.register_cli_opt(cfg.MultiStrOpt('bar', positional=True))
|
||||||
|
True
|
||||||
|
>>> conf(['a', 'b'])
|
||||||
|
>>> conf.bar
|
||||||
|
['a', 'b']
|
||||||
|
|
||||||
|
Sub-Parsers
|
||||||
|
-----------
|
||||||
|
|
||||||
|
It is also possible to use argparse "sub-parsers" to parse additional
|
||||||
|
command line arguments using the SubCommandOpt class:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
>>> def add_parsers(subparsers):
|
||||||
|
... list_action = subparsers.add_parser('list')
|
||||||
|
... list_action.add_argument('id')
|
||||||
|
...
|
||||||
|
>>> conf = cfg.ConfigOpts()
|
||||||
|
>>> conf.register_cli_opt(cfg.SubCommandOpt('action', handler=add_parsers))
|
||||||
|
True
|
||||||
|
>>> conf(args=['list', '10'])
|
||||||
|
>>> conf.action.name, conf.action.id
|
||||||
|
('list', '10')
|
84
doc/source/reference/configuration-files.rst
Normal file
84
doc/source/reference/configuration-files.rst
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
=============================
|
||||||
|
Loading Configuration Files
|
||||||
|
=============================
|
||||||
|
|
||||||
|
The config manager has two CLI options defined by default, ``--config-file``
|
||||||
|
and ``--config-dir``:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
class ConfigOpts(object):
|
||||||
|
|
||||||
|
def __call__(self, ...):
|
||||||
|
|
||||||
|
opts = [
|
||||||
|
MultiStrOpt('config-file',
|
||||||
|
...),
|
||||||
|
StrOpt('config-dir',
|
||||||
|
...),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.register_cli_opts(opts)
|
||||||
|
|
||||||
|
Option values are parsed from any supplied config files using
|
||||||
|
oslo_config.iniparser. If none are specified, a default set is used
|
||||||
|
for example glance-api.conf and glance-common.conf:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
glance-api.conf:
|
||||||
|
[DEFAULT]
|
||||||
|
bind_port = 9292
|
||||||
|
|
||||||
|
glance-common.conf:
|
||||||
|
[DEFAULT]
|
||||||
|
bind_host = 0.0.0.0
|
||||||
|
|
||||||
|
Lines in a configuration file should not start with whitespace. A
|
||||||
|
configuration file also supports comments, which must start with '#' or ';'.
|
||||||
|
Option values in config files and those on the command line are parsed
|
||||||
|
in order. The same option (includes deprecated option name and current
|
||||||
|
option name) can appear many times, in config files or on the command line.
|
||||||
|
Later values always override earlier ones.
|
||||||
|
|
||||||
|
The order of configuration files inside the same configuration directory is
|
||||||
|
defined by the alphabetic sorting order of their file names.
|
||||||
|
|
||||||
|
The parsing of CLI args and config files is initiated by invoking the config
|
||||||
|
manager for example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
conf = cfg.ConfigOpts()
|
||||||
|
conf.register_opt(cfg.BoolOpt('verbose', ...))
|
||||||
|
conf(sys.argv[1:])
|
||||||
|
if conf.verbose:
|
||||||
|
...
|
||||||
|
|
||||||
|
Option Value Interpolation
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
Option values may reference other values using PEP 292 string substitution:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
opts = [
|
||||||
|
cfg.StrOpt('state_path',
|
||||||
|
default=os.path.join(os.path.dirname(__file__), '../'),
|
||||||
|
help='Top-level directory for maintaining nova state.'),
|
||||||
|
cfg.StrOpt('sqlite_db',
|
||||||
|
default='nova.sqlite',
|
||||||
|
help='File name for SQLite.'),
|
||||||
|
cfg.StrOpt('sql_connection',
|
||||||
|
default='sqlite:///$state_path/$sqlite_db',
|
||||||
|
help='Connection string for SQL database.'),
|
||||||
|
]
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Interpolation can be avoided by using `$$`.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
You can use `.` to delimit option from other groups, e.g.
|
||||||
|
${mygroup.myoption}.
|
314
doc/source/reference/defining.rst
Normal file
314
doc/source/reference/defining.rst
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
==================
|
||||||
|
Defining Options
|
||||||
|
==================
|
||||||
|
|
||||||
|
Configuration options may be set on the command line or in config files.
|
||||||
|
|
||||||
|
The schema for each option is defined using the
|
||||||
|
:class:`Opt` class or its sub-classes, for example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
from oslo_config import types
|
||||||
|
|
||||||
|
PortType = types.Integer(1, 65535)
|
||||||
|
|
||||||
|
common_opts = [
|
||||||
|
cfg.StrOpt('bind_host',
|
||||||
|
default='0.0.0.0',
|
||||||
|
help='IP address to listen on.'),
|
||||||
|
cfg.Opt('bind_port',
|
||||||
|
type=PortType,
|
||||||
|
default=9292,
|
||||||
|
help='Port number to listen on.')
|
||||||
|
]
|
||||||
|
|
||||||
|
Option Types
|
||||||
|
------------
|
||||||
|
|
||||||
|
Options can have arbitrary types via the `type` parameter to the :class:`Opt`
|
||||||
|
constructor. The `type` parameter is a callable object that takes a string and
|
||||||
|
either returns a value of that particular type or raises :class:`ValueError` if
|
||||||
|
the value can not be converted.
|
||||||
|
|
||||||
|
For convenience, there are predefined option subclasses in
|
||||||
|
:mod:`oslo_config.cfg` that set the option `type` as in the following table:
|
||||||
|
|
||||||
|
====================================== ======
|
||||||
|
Type Option
|
||||||
|
====================================== ======
|
||||||
|
:class:`oslo_config.types.String` :class:`oslo_config.cfg.StrOpt`
|
||||||
|
:class:`oslo_config.types.String` :class:`oslo_config.cfg.SubCommandOpt`
|
||||||
|
:class:`oslo_config.types.Boolean` :class:`oslo_config.cfg.BoolOpt`
|
||||||
|
:class:`oslo_config.types.Integer` :class:`oslo_config.cfg.IntOpt`
|
||||||
|
:class:`oslo_config.types.Float` :class:`oslo_config.cfg.FloatOpt`
|
||||||
|
:class:`oslo_config.types.Port` :class:`oslo_config.cfg.PortOpt`
|
||||||
|
:class:`oslo_config.types.List` :class:`oslo_config.cfg.ListOpt`
|
||||||
|
:class:`oslo_config.types.Dict` :class:`oslo_config.cfg.DictOpt`
|
||||||
|
:class:`oslo_config.types.IPAddress` :class:`oslo_config.cfg.IPOpt`
|
||||||
|
:class:`oslo_config.types.Hostname` :class:`oslo_config.cfg.HostnameOpt`
|
||||||
|
:class:`oslo_config.types.HostAddress` :class:`oslo_config.cfg.HostAddressOpt`
|
||||||
|
:class:`oslo_config.types.URI` :class:`oslo_config.cfg.URIOpt`
|
||||||
|
====================================== ======
|
||||||
|
|
||||||
|
For :class:`oslo_config.cfg.MultiOpt` the `item_type` parameter defines
|
||||||
|
the type of the values. For convenience, :class:`oslo_config.cfg.MultiStrOpt`
|
||||||
|
is :class:`~oslo_config.cfg.MultiOpt` with the `item_type` parameter set to
|
||||||
|
:class:`oslo_config.types.MultiString`.
|
||||||
|
|
||||||
|
The following example defines options using the convenience classes:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
enabled_apis_opt = cfg.ListOpt('enabled_apis',
|
||||||
|
default=['ec2', 'osapi_compute'],
|
||||||
|
help='List of APIs to enable by default.')
|
||||||
|
|
||||||
|
DEFAULT_EXTENSIONS = [
|
||||||
|
'nova.api.openstack.compute.contrib.standard_extensions'
|
||||||
|
]
|
||||||
|
osapi_compute_extension_opt = cfg.MultiStrOpt('osapi_compute_extension',
|
||||||
|
default=DEFAULT_EXTENSIONS)
|
||||||
|
|
||||||
|
Registering Options
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Option schemas are registered with the config manager at runtime, but before
|
||||||
|
the option is referenced:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
class ExtensionManager(object):
|
||||||
|
|
||||||
|
enabled_apis_opt = cfg.ListOpt(...)
|
||||||
|
|
||||||
|
def __init__(self, conf):
|
||||||
|
self.conf = conf
|
||||||
|
self.conf.register_opt(enabled_apis_opt)
|
||||||
|
...
|
||||||
|
|
||||||
|
def _load_extensions(self):
|
||||||
|
for ext_factory in self.conf.osapi_compute_extension:
|
||||||
|
....
|
||||||
|
|
||||||
|
A common usage pattern is for each option schema to be defined in the module or
|
||||||
|
class which uses the option:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
opts = ...
|
||||||
|
|
||||||
|
def add_common_opts(conf):
|
||||||
|
conf.register_opts(opts)
|
||||||
|
|
||||||
|
def get_bind_host(conf):
|
||||||
|
return conf.bind_host
|
||||||
|
|
||||||
|
def get_bind_port(conf):
|
||||||
|
return conf.bind_port
|
||||||
|
|
||||||
|
An option may optionally be made available via the command line. Such options
|
||||||
|
must be registered with the config manager before the command line is parsed
|
||||||
|
(for the purposes of --help and CLI arg validation):
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
cli_opts = [
|
||||||
|
cfg.BoolOpt('verbose',
|
||||||
|
short='v',
|
||||||
|
default=False,
|
||||||
|
help='Print more verbose output.'),
|
||||||
|
cfg.BoolOpt('debug',
|
||||||
|
short='d',
|
||||||
|
default=False,
|
||||||
|
help='Print debugging output.'),
|
||||||
|
]
|
||||||
|
|
||||||
|
def add_common_opts(conf):
|
||||||
|
conf.register_cli_opts(cli_opts)
|
||||||
|
|
||||||
|
Option Groups
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Options can be registered as belonging to a group:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
rabbit_group = cfg.OptGroup(name='rabbit',
|
||||||
|
title='RabbitMQ options')
|
||||||
|
|
||||||
|
rabbit_host_opt = cfg.StrOpt('host',
|
||||||
|
default='localhost',
|
||||||
|
help='IP/hostname to listen on.'),
|
||||||
|
rabbit_port_opt = cfg.PortOpt('port',
|
||||||
|
default=5672,
|
||||||
|
help='Port number to listen on.')
|
||||||
|
|
||||||
|
def register_rabbit_opts(conf):
|
||||||
|
conf.register_group(rabbit_group)
|
||||||
|
# options can be registered under a group in either of these ways:
|
||||||
|
conf.register_opt(rabbit_host_opt, group=rabbit_group)
|
||||||
|
conf.register_opt(rabbit_port_opt, group='rabbit')
|
||||||
|
|
||||||
|
If no group attributes are required other than the group name, the group
|
||||||
|
need not be explicitly registered for example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
def register_rabbit_opts(conf):
|
||||||
|
# The group will automatically be created, equivalent calling:
|
||||||
|
# conf.register_group(OptGroup(name='rabbit'))
|
||||||
|
conf.register_opt(rabbit_port_opt, group='rabbit')
|
||||||
|
|
||||||
|
If no group is specified, options belong to the 'DEFAULT' section of config
|
||||||
|
files:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
glance-api.conf:
|
||||||
|
[DEFAULT]
|
||||||
|
bind_port = 9292
|
||||||
|
...
|
||||||
|
|
||||||
|
[rabbit]
|
||||||
|
host = localhost
|
||||||
|
port = 5672
|
||||||
|
use_ssl = False
|
||||||
|
userid = guest
|
||||||
|
password = guest
|
||||||
|
virtual_host = /
|
||||||
|
|
||||||
|
Command-line options in a group are automatically prefixed with the
|
||||||
|
group name:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
--rabbit-host localhost --rabbit-port 9999
|
||||||
|
|
||||||
|
Dynamic Groups
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Groups can be registered dynamically by application code. This
|
||||||
|
introduces a challenge for the sample generator, discovery mechanisms,
|
||||||
|
and validation tools, since they do not know in advance the names of
|
||||||
|
all of the groups. The ``dynamic_group_owner`` parameter to the
|
||||||
|
constructor specifies the full name of an option registered in another
|
||||||
|
group that controls repeated instances of a dynamic group. This option
|
||||||
|
is usually a MultiStrOpt.
|
||||||
|
|
||||||
|
For example, Cinder supports multiple storage backend devices and
|
||||||
|
services. To configure Cinder to communicate with multiple backends,
|
||||||
|
the ``enabled_backends`` option is set to the list of names of
|
||||||
|
backends. Each backend group includes the options for communicating
|
||||||
|
with that device or service.
|
||||||
|
|
||||||
|
Driver Groups
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Groups can have dynamic sets of options, usually based on a driver
|
||||||
|
that has unique requirements. This works at runtime because the code
|
||||||
|
registers options before it uses them, but it introduces a challenge
|
||||||
|
for the sample generator, discovery mechanisms, and validation tools
|
||||||
|
because they do not know in advance the correct options for a group.
|
||||||
|
|
||||||
|
To address this issue, the driver option for a group can be named
|
||||||
|
using the ``driver_option`` parameter. Each driver option should
|
||||||
|
define its own discovery entry point namespace to return the set of
|
||||||
|
options for that driver, named using the prefix
|
||||||
|
``"oslo.config.opts."`` followed by the driver option name.
|
||||||
|
|
||||||
|
In the Cinder case described above, a ``volume_backend_name`` option
|
||||||
|
is part of the static definition of the group, so ``driver_option``
|
||||||
|
should be set to ``"volume_backend_name"``. And plugins should be
|
||||||
|
registered under ``"oslo.config.opts.volume_backend_name"`` using the
|
||||||
|
same names as the main plugin registered with
|
||||||
|
``"oslo.config.opts"``. The drivers residing within the Cinder code
|
||||||
|
base have an entry point named ``"cinder"`` registered.
|
||||||
|
|
||||||
|
Special Handling Instructions
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
Options may be declared as required so that an error is raised if the user
|
||||||
|
does not supply a value for the option:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
opts = [
|
||||||
|
cfg.StrOpt('service_name', required=True),
|
||||||
|
cfg.StrOpt('image_id', required=True),
|
||||||
|
...
|
||||||
|
]
|
||||||
|
|
||||||
|
Options may be declared as secret so that their values are not leaked into
|
||||||
|
log files:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
opts = [
|
||||||
|
cfg.StrOpt('s3_store_access_key', secret=True),
|
||||||
|
cfg.StrOpt('s3_store_secret_key', secret=True),
|
||||||
|
...
|
||||||
|
]
|
||||||
|
|
||||||
|
Dictionary Options
|
||||||
|
------------------
|
||||||
|
|
||||||
|
If you need end users to specify a dictionary of key/value pairs, then you can
|
||||||
|
use the DictOpt:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
opts = [
|
||||||
|
cfg.DictOpt('foo',
|
||||||
|
default={})
|
||||||
|
]
|
||||||
|
|
||||||
|
The end users can then specify the option foo in their configuration file
|
||||||
|
as shown below:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
[DEFAULT]
|
||||||
|
foo = k1:v1,k2:v2
|
||||||
|
|
||||||
|
Advanced Option
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Use if you need to label an option as advanced in sample files, indicating the
|
||||||
|
option is not normally used by the majority of users and might have a
|
||||||
|
significant effect on stability and/or performance:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
|
opts = [
|
||||||
|
cfg.StrOpt('option1', default='default_value',
|
||||||
|
advanced=True, help='This is help '
|
||||||
|
'text.'),
|
||||||
|
cfg.PortOpt('option2', default='default_value',
|
||||||
|
help='This is help text.'),
|
||||||
|
]
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
CONF.register_opts(opts)
|
||||||
|
|
||||||
|
This will result in the option being pushed to the bottom of the
|
||||||
|
namespace and labeled as advanced in the sample files, with a notation
|
||||||
|
about possible effects:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
[DEFAULT]
|
||||||
|
...
|
||||||
|
# This is help text. (string value)
|
||||||
|
# option2 = default_value
|
||||||
|
...
|
||||||
|
<pushed to bottom of section>
|
||||||
|
...
|
||||||
|
# This is help text. (string value)
|
||||||
|
# Advanced Option: intended for advanced users and not used
|
||||||
|
# by the majority of users, and might have a significant
|
||||||
|
# effect on stability and/or performance.
|
||||||
|
# option1 = default_value
|
47
doc/source/reference/deprecating.rst
Normal file
47
doc/source/reference/deprecating.rst
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
====================
|
||||||
|
Option Deprecation
|
||||||
|
====================
|
||||||
|
|
||||||
|
If you want to rename some options, move them to another group or remove
|
||||||
|
completely, you may change their declarations using `deprecated_name`,
|
||||||
|
`deprecated_group` and `deprecated_for_removal` parameters to the :class:`Opt`
|
||||||
|
constructor:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
|
conf = cfg.ConfigOpts()
|
||||||
|
|
||||||
|
opt_1 = cfg.StrOpt('opt_1', default='foo', deprecated_name='opt1')
|
||||||
|
opt_2 = cfg.StrOpt('opt_2', default='spam', deprecated_group='DEFAULT')
|
||||||
|
opt_3 = cfg.BoolOpt('opt_3', default=False, deprecated_for_removal=True)
|
||||||
|
|
||||||
|
conf.register_opt(opt_1, group='group_1')
|
||||||
|
conf.register_opt(opt_2, group='group_2')
|
||||||
|
conf.register_opt(opt_3)
|
||||||
|
|
||||||
|
conf(['--config-file', 'config.conf'])
|
||||||
|
|
||||||
|
assert conf.group_1.opt_1 == 'bar'
|
||||||
|
assert conf.group_2.opt_2 == 'eggs'
|
||||||
|
assert conf.opt_3
|
||||||
|
|
||||||
|
Assuming that the file config.conf has the following content:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
[group_1]
|
||||||
|
opt1 = bar
|
||||||
|
|
||||||
|
[DEFAULT]
|
||||||
|
opt_2 = eggs
|
||||||
|
opt_3 = True
|
||||||
|
|
||||||
|
the script will succeed, but will log three respective warnings about the
|
||||||
|
given deprecated options.
|
||||||
|
|
||||||
|
There are also `deprecated_reason` and `deprecated_since` parameters for
|
||||||
|
specifying some additional information about a deprecation.
|
||||||
|
|
||||||
|
All the mentioned parameters can be mixed together in any combinations.
|
21
doc/source/reference/globals.rst
Normal file
21
doc/source/reference/globals.rst
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
===================
|
||||||
|
Global ConfigOpts
|
||||||
|
===================
|
||||||
|
|
||||||
|
This module also contains a global instance of the ConfigOpts class
|
||||||
|
in order to support a common usage pattern in OpenStack:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
|
opts = [
|
||||||
|
cfg.StrOpt('bind_host', default='0.0.0.0'),
|
||||||
|
cfg.PortOpt('bind_port', default=9292),
|
||||||
|
]
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
CONF.register_opts(opts)
|
||||||
|
|
||||||
|
def start(server, app):
|
||||||
|
server.start(app, CONF.bind_port, CONF.bind_host)
|
@ -1,11 +1,17 @@
|
|||||||
===================
|
=============================
|
||||||
Using oslo.config
|
oslo.config Reference Guide
|
||||||
===================
|
=============================
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
cfg
|
defining
|
||||||
|
naming
|
||||||
|
accessing
|
||||||
|
configuration-files
|
||||||
|
command-line
|
||||||
|
deprecating
|
||||||
|
globals
|
||||||
opts
|
opts
|
||||||
types
|
types
|
||||||
configopts
|
configopts
|
||||||
@ -14,7 +20,6 @@
|
|||||||
fixture
|
fixture
|
||||||
parser
|
parser
|
||||||
exceptions
|
exceptions
|
||||||
namespaces
|
|
||||||
styleguide
|
styleguide
|
||||||
mutable
|
mutable
|
||||||
locations
|
locations
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
.. _option-definitions:
|
.. _option-definitions:
|
||||||
|
|
||||||
------------------
|
====================
|
||||||
Option Definitions
|
Opt and Subclasses
|
||||||
------------------
|
====================
|
||||||
|
|
||||||
.. currentmodule:: oslo_config.cfg
|
.. currentmodule:: oslo_config.cfg
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---------------------------
|
=============================
|
||||||
Option Types and Validation
|
Option Types and Validation
|
||||||
---------------------------
|
=============================
|
||||||
|
|
||||||
.. automodule:: oslo_config.types
|
.. automodule:: oslo_config.types
|
||||||
:members:
|
:members:
|
||||||
|
@ -12,475 +12,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
r"""
|
"""Primary module in oslo_config.
|
||||||
Configuration options may be set on the command line or in config files.
|
|
||||||
|
|
||||||
The schema for each option is defined using the
|
|
||||||
:class:`Opt` class or its sub-classes, for example:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
|
||||||
from oslo_config import types
|
|
||||||
|
|
||||||
PortType = types.Integer(1, 65535)
|
|
||||||
|
|
||||||
common_opts = [
|
|
||||||
cfg.StrOpt('bind_host',
|
|
||||||
default='0.0.0.0',
|
|
||||||
help='IP address to listen on.'),
|
|
||||||
cfg.Opt('bind_port',
|
|
||||||
type=PortType,
|
|
||||||
default=9292,
|
|
||||||
help='Port number to listen on.')
|
|
||||||
]
|
|
||||||
|
|
||||||
Option Types
|
|
||||||
------------
|
|
||||||
|
|
||||||
Options can have arbitrary types via the `type` parameter to the :class:`Opt`
|
|
||||||
constructor. The `type` parameter is a callable object that takes a string and
|
|
||||||
either returns a value of that particular type or raises :class:`ValueError` if
|
|
||||||
the value can not be converted.
|
|
||||||
|
|
||||||
For convenience, there are predefined option subclasses in
|
|
||||||
:mod:`oslo_config.cfg` that set the option `type` as in the following table:
|
|
||||||
|
|
||||||
====================================== ======
|
|
||||||
Type Option
|
|
||||||
====================================== ======
|
|
||||||
:class:`oslo_config.types.String` :class:`oslo_config.cfg.StrOpt`
|
|
||||||
:class:`oslo_config.types.String` :class:`oslo_config.cfg.SubCommandOpt`
|
|
||||||
:class:`oslo_config.types.Boolean` :class:`oslo_config.cfg.BoolOpt`
|
|
||||||
:class:`oslo_config.types.Integer` :class:`oslo_config.cfg.IntOpt`
|
|
||||||
:class:`oslo_config.types.Float` :class:`oslo_config.cfg.FloatOpt`
|
|
||||||
:class:`oslo_config.types.Port` :class:`oslo_config.cfg.PortOpt`
|
|
||||||
:class:`oslo_config.types.List` :class:`oslo_config.cfg.ListOpt`
|
|
||||||
:class:`oslo_config.types.Dict` :class:`oslo_config.cfg.DictOpt`
|
|
||||||
:class:`oslo_config.types.IPAddress` :class:`oslo_config.cfg.IPOpt`
|
|
||||||
:class:`oslo_config.types.Hostname` :class:`oslo_config.cfg.HostnameOpt`
|
|
||||||
:class:`oslo_config.types.HostAddress` :class:`oslo_config.cfg.HostAddressOpt`
|
|
||||||
:class:`oslo_config.types.URI` :class:`oslo_config.cfg.URIOpt`
|
|
||||||
====================================== ======
|
|
||||||
|
|
||||||
For :class:`oslo_config.cfg.MultiOpt` the `item_type` parameter defines
|
|
||||||
the type of the values. For convenience, :class:`oslo_config.cfg.MultiStrOpt`
|
|
||||||
is :class:`~oslo_config.cfg.MultiOpt` with the `item_type` parameter set to
|
|
||||||
:class:`oslo_config.types.MultiString`.
|
|
||||||
|
|
||||||
The following example defines options using the convenience classes::
|
|
||||||
|
|
||||||
enabled_apis_opt = cfg.ListOpt('enabled_apis',
|
|
||||||
default=['ec2', 'osapi_compute'],
|
|
||||||
help='List of APIs to enable by default.')
|
|
||||||
|
|
||||||
DEFAULT_EXTENSIONS = [
|
|
||||||
'nova.api.openstack.compute.contrib.standard_extensions'
|
|
||||||
]
|
|
||||||
osapi_compute_extension_opt = cfg.MultiStrOpt('osapi_compute_extension',
|
|
||||||
default=DEFAULT_EXTENSIONS)
|
|
||||||
|
|
||||||
Registering Options
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
Option schemas are registered with the config manager at runtime, but before
|
|
||||||
the option is referenced::
|
|
||||||
|
|
||||||
class ExtensionManager(object):
|
|
||||||
|
|
||||||
enabled_apis_opt = cfg.ListOpt(...)
|
|
||||||
|
|
||||||
def __init__(self, conf):
|
|
||||||
self.conf = conf
|
|
||||||
self.conf.register_opt(enabled_apis_opt)
|
|
||||||
...
|
|
||||||
|
|
||||||
def _load_extensions(self):
|
|
||||||
for ext_factory in self.conf.osapi_compute_extension:
|
|
||||||
....
|
|
||||||
|
|
||||||
A common usage pattern is for each option schema to be defined in the module or
|
|
||||||
class which uses the option::
|
|
||||||
|
|
||||||
opts = ...
|
|
||||||
|
|
||||||
def add_common_opts(conf):
|
|
||||||
conf.register_opts(opts)
|
|
||||||
|
|
||||||
def get_bind_host(conf):
|
|
||||||
return conf.bind_host
|
|
||||||
|
|
||||||
def get_bind_port(conf):
|
|
||||||
return conf.bind_port
|
|
||||||
|
|
||||||
An option may optionally be made available via the command line. Such options
|
|
||||||
must be registered with the config manager before the command line is parsed
|
|
||||||
(for the purposes of --help and CLI arg validation)::
|
|
||||||
|
|
||||||
cli_opts = [
|
|
||||||
cfg.BoolOpt('verbose',
|
|
||||||
short='v',
|
|
||||||
default=False,
|
|
||||||
help='Print more verbose output.'),
|
|
||||||
cfg.BoolOpt('debug',
|
|
||||||
short='d',
|
|
||||||
default=False,
|
|
||||||
help='Print debugging output.'),
|
|
||||||
]
|
|
||||||
|
|
||||||
def add_common_opts(conf):
|
|
||||||
conf.register_cli_opts(cli_opts)
|
|
||||||
|
|
||||||
Loading Config Files
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
The config manager has two CLI options defined by default, --config-file
|
|
||||||
and --config-dir::
|
|
||||||
|
|
||||||
class ConfigOpts(object):
|
|
||||||
|
|
||||||
def __call__(self, ...):
|
|
||||||
|
|
||||||
opts = [
|
|
||||||
MultiStrOpt('config-file',
|
|
||||||
...),
|
|
||||||
StrOpt('config-dir',
|
|
||||||
...),
|
|
||||||
]
|
|
||||||
|
|
||||||
self.register_cli_opts(opts)
|
|
||||||
|
|
||||||
Option values are parsed from any supplied config files using
|
|
||||||
oslo_config.iniparser. If none are specified, a default set is used
|
|
||||||
for example glance-api.conf and glance-common.conf::
|
|
||||||
|
|
||||||
glance-api.conf:
|
|
||||||
[DEFAULT]
|
|
||||||
bind_port = 9292
|
|
||||||
|
|
||||||
glance-common.conf:
|
|
||||||
[DEFAULT]
|
|
||||||
bind_host = 0.0.0.0
|
|
||||||
|
|
||||||
Lines in a configuration file should not start with whitespace. A
|
|
||||||
configuration file also supports comments, which must start with '#' or ';'.
|
|
||||||
Option values in config files and those on the command line are parsed
|
|
||||||
in order. The same option (includes deprecated option name and current
|
|
||||||
option name) can appear many times, in config files or on the command line.
|
|
||||||
Later values always override earlier ones.
|
|
||||||
|
|
||||||
The order of configuration files inside the same configuration directory is
|
|
||||||
defined by the alphabetic sorting order of their file names.
|
|
||||||
|
|
||||||
The parsing of CLI args and config files is initiated by invoking the config
|
|
||||||
manager for example::
|
|
||||||
|
|
||||||
conf = cfg.ConfigOpts()
|
|
||||||
conf.register_opt(cfg.BoolOpt('verbose', ...))
|
|
||||||
conf(sys.argv[1:])
|
|
||||||
if conf.verbose:
|
|
||||||
...
|
|
||||||
|
|
||||||
Option Groups
|
|
||||||
-------------
|
|
||||||
|
|
||||||
Options can be registered as belonging to a group::
|
|
||||||
|
|
||||||
rabbit_group = cfg.OptGroup(name='rabbit',
|
|
||||||
title='RabbitMQ options')
|
|
||||||
|
|
||||||
rabbit_host_opt = cfg.StrOpt('host',
|
|
||||||
default='localhost',
|
|
||||||
help='IP/hostname to listen on.'),
|
|
||||||
rabbit_port_opt = cfg.PortOpt('port',
|
|
||||||
default=5672,
|
|
||||||
help='Port number to listen on.')
|
|
||||||
|
|
||||||
def register_rabbit_opts(conf):
|
|
||||||
conf.register_group(rabbit_group)
|
|
||||||
# options can be registered under a group in either of these ways:
|
|
||||||
conf.register_opt(rabbit_host_opt, group=rabbit_group)
|
|
||||||
conf.register_opt(rabbit_port_opt, group='rabbit')
|
|
||||||
|
|
||||||
If no group attributes are required other than the group name, the group
|
|
||||||
need not be explicitly registered for example::
|
|
||||||
|
|
||||||
def register_rabbit_opts(conf):
|
|
||||||
# The group will automatically be created, equivalent calling::
|
|
||||||
# conf.register_group(OptGroup(name='rabbit'))
|
|
||||||
conf.register_opt(rabbit_port_opt, group='rabbit')
|
|
||||||
|
|
||||||
If no group is specified, options belong to the 'DEFAULT' section of config
|
|
||||||
files::
|
|
||||||
|
|
||||||
glance-api.conf:
|
|
||||||
[DEFAULT]
|
|
||||||
bind_port = 9292
|
|
||||||
...
|
|
||||||
|
|
||||||
[rabbit]
|
|
||||||
host = localhost
|
|
||||||
port = 5672
|
|
||||||
use_ssl = False
|
|
||||||
userid = guest
|
|
||||||
password = guest
|
|
||||||
virtual_host = /
|
|
||||||
|
|
||||||
Command-line options in a group are automatically prefixed with the
|
|
||||||
group name::
|
|
||||||
|
|
||||||
--rabbit-host localhost --rabbit-port 9999
|
|
||||||
|
|
||||||
Dynamic Groups
|
|
||||||
--------------
|
|
||||||
|
|
||||||
Groups can be registered dynamically by application code. This
|
|
||||||
introduces a challenge for the sample generator, discovery mechanisms,
|
|
||||||
and validation tools, since they do not know in advance the names of
|
|
||||||
all of the groups. The ``dynamic_group_owner`` parameter to the
|
|
||||||
constructor specifies the full name of an option registered in another
|
|
||||||
group that controls repeated instances of a dynamic group. This option
|
|
||||||
is usually a MultiStrOpt.
|
|
||||||
|
|
||||||
For example, Cinder supports multiple storage backend devices and
|
|
||||||
services. To configure Cinder to communicate with multiple backends,
|
|
||||||
the ``enabled_backends`` option is set to the list of names of
|
|
||||||
backends. Each backend group includes the options for communicating
|
|
||||||
with that device or service.
|
|
||||||
|
|
||||||
Driver Groups
|
|
||||||
-------------
|
|
||||||
|
|
||||||
Groups can have dynamic sets of options, usually based on a driver
|
|
||||||
that has unique requirements. This works at runtime because the code
|
|
||||||
registers options before it uses them, but it introduces a challenge
|
|
||||||
for the sample generator, discovery mechanisms, and validation tools
|
|
||||||
because they do not know in advance the correct options for a group.
|
|
||||||
|
|
||||||
To address this issue, the driver option for a group can be named
|
|
||||||
using the ``driver_option`` parameter. Each driver option should
|
|
||||||
define its own discovery entry point namespace to return the set of
|
|
||||||
options for that driver, named using the prefix
|
|
||||||
``"oslo.config.opts."`` followed by the driver option name.
|
|
||||||
|
|
||||||
In the Cinder case described above, a ``volume_backend_name`` option
|
|
||||||
is part of the static definition of the group, so ``driver_option``
|
|
||||||
should be set to ``"volume_backend_name"``. And plugins should be
|
|
||||||
registered under ``"oslo.config.opts.volume_backend_name"`` using the
|
|
||||||
same names as the main plugin registered with
|
|
||||||
``"oslo.config.opts"``. The drivers residing within the Cinder code
|
|
||||||
base have an entry point named ``"cinder"`` registered.
|
|
||||||
|
|
||||||
Accessing Option Values In Your Code
|
|
||||||
------------------------------------
|
|
||||||
|
|
||||||
Option values in the default group are referenced as attributes/properties on
|
|
||||||
the config manager; groups are also attributes on the config manager, with
|
|
||||||
attributes for each of the options associated with the group::
|
|
||||||
|
|
||||||
server.start(app, conf.bind_port, conf.bind_host, conf)
|
|
||||||
|
|
||||||
self.connection = kombu.connection.BrokerConnection(
|
|
||||||
hostname=conf.rabbit.host,
|
|
||||||
port=conf.rabbit.port,
|
|
||||||
...)
|
|
||||||
|
|
||||||
Option Value Interpolation
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
Option values may reference other values using PEP 292 string substitution::
|
|
||||||
|
|
||||||
opts = [
|
|
||||||
cfg.StrOpt('state_path',
|
|
||||||
default=os.path.join(os.path.dirname(__file__), '../'),
|
|
||||||
help='Top-level directory for maintaining nova state.'),
|
|
||||||
cfg.StrOpt('sqlite_db',
|
|
||||||
default='nova.sqlite',
|
|
||||||
help='File name for SQLite.'),
|
|
||||||
cfg.StrOpt('sql_connection',
|
|
||||||
default='sqlite:///$state_path/$sqlite_db',
|
|
||||||
help='Connection string for SQL database.'),
|
|
||||||
]
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Interpolation can be avoided by using `$$`.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
You can use `.` to delimit option from other groups, e.g.
|
|
||||||
${mygroup.myoption}.
|
|
||||||
|
|
||||||
Special Handling Instructions
|
|
||||||
-----------------------------
|
|
||||||
|
|
||||||
Options may be declared as required so that an error is raised if the user
|
|
||||||
does not supply a value for the option::
|
|
||||||
|
|
||||||
opts = [
|
|
||||||
cfg.StrOpt('service_name', required=True),
|
|
||||||
cfg.StrOpt('image_id', required=True),
|
|
||||||
...
|
|
||||||
]
|
|
||||||
|
|
||||||
Options may be declared as secret so that their values are not leaked into
|
|
||||||
log files::
|
|
||||||
|
|
||||||
opts = [
|
|
||||||
cfg.StrOpt('s3_store_access_key', secret=True),
|
|
||||||
cfg.StrOpt('s3_store_secret_key', secret=True),
|
|
||||||
...
|
|
||||||
]
|
|
||||||
|
|
||||||
Dictionary Options
|
|
||||||
------------------
|
|
||||||
|
|
||||||
If you need end users to specify a dictionary of key/value pairs, then you can
|
|
||||||
use the DictOpt::
|
|
||||||
|
|
||||||
opts = [
|
|
||||||
cfg.DictOpt('foo',
|
|
||||||
default={})
|
|
||||||
]
|
|
||||||
|
|
||||||
The end users can then specify the option foo in their configuration file
|
|
||||||
as shown below:
|
|
||||||
|
|
||||||
.. code-block:: ini
|
|
||||||
|
|
||||||
[DEFAULT]
|
|
||||||
foo = k1:v1,k2:v2
|
|
||||||
|
|
||||||
|
|
||||||
Global ConfigOpts
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
This module also contains a global instance of the ConfigOpts class
|
|
||||||
in order to support a common usage pattern in OpenStack::
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
|
||||||
|
|
||||||
opts = [
|
|
||||||
cfg.StrOpt('bind_host', default='0.0.0.0'),
|
|
||||||
cfg.PortOpt('bind_port', default=9292),
|
|
||||||
]
|
|
||||||
|
|
||||||
CONF = cfg.CONF
|
|
||||||
CONF.register_opts(opts)
|
|
||||||
|
|
||||||
def start(server, app):
|
|
||||||
server.start(app, CONF.bind_port, CONF.bind_host)
|
|
||||||
|
|
||||||
Positional Command Line Arguments
|
|
||||||
---------------------------------
|
|
||||||
|
|
||||||
Positional command line arguments are supported via a 'positional' Opt
|
|
||||||
constructor argument::
|
|
||||||
|
|
||||||
>>> conf = cfg.ConfigOpts()
|
|
||||||
>>> conf.register_cli_opt(cfg.MultiStrOpt('bar', positional=True))
|
|
||||||
True
|
|
||||||
>>> conf(['a', 'b'])
|
|
||||||
>>> conf.bar
|
|
||||||
['a', 'b']
|
|
||||||
|
|
||||||
Sub-Parsers
|
|
||||||
-----------
|
|
||||||
|
|
||||||
It is also possible to use argparse "sub-parsers" to parse additional
|
|
||||||
command line arguments using the SubCommandOpt class:
|
|
||||||
|
|
||||||
>>> def add_parsers(subparsers):
|
|
||||||
... list_action = subparsers.add_parser('list')
|
|
||||||
... list_action.add_argument('id')
|
|
||||||
...
|
|
||||||
>>> conf = cfg.ConfigOpts()
|
|
||||||
>>> conf.register_cli_opt(cfg.SubCommandOpt('action', handler=add_parsers))
|
|
||||||
True
|
|
||||||
>>> conf(args=['list', '10'])
|
|
||||||
>>> conf.action.name, conf.action.id
|
|
||||||
('list', '10')
|
|
||||||
|
|
||||||
Advanced Option
|
|
||||||
---------------
|
|
||||||
|
|
||||||
Use if you need to label an option as advanced in sample files, indicating the
|
|
||||||
option is not normally used by the majority of users and might have a
|
|
||||||
significant effect on stability and/or performance::
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
|
||||||
|
|
||||||
opts = [
|
|
||||||
cfg.StrOpt('option1', default='default_value',
|
|
||||||
advanced=True, help='This is help '
|
|
||||||
'text.'),
|
|
||||||
cfg.PortOpt('option2', default='default_value',
|
|
||||||
help='This is help text.'),
|
|
||||||
]
|
|
||||||
|
|
||||||
CONF = cfg.CONF
|
|
||||||
CONF.register_opts(opts)
|
|
||||||
|
|
||||||
This will result in the option being pushed to the bottom of the
|
|
||||||
namespace and labeled as advanced in the sample files, with a notation
|
|
||||||
about possible effects::
|
|
||||||
|
|
||||||
[DEFAULT]
|
|
||||||
...
|
|
||||||
# This is help text. (string value)
|
|
||||||
# option2 = default_value
|
|
||||||
...
|
|
||||||
<pushed to bottom of section>
|
|
||||||
...
|
|
||||||
# This is help text. (string value)
|
|
||||||
# Advanced Option: intended for advanced users and not used
|
|
||||||
# by the majority of users, and might have a significant
|
|
||||||
# effect on stability and/or performance.
|
|
||||||
# option1 = default_value
|
|
||||||
|
|
||||||
Option Deprecation
|
|
||||||
------------------
|
|
||||||
|
|
||||||
If you want to rename some options, move them to another group or remove
|
|
||||||
completely, you may change their declarations using `deprecated_name`,
|
|
||||||
`deprecated_group` and `deprecated_for_removal` parameters to the :class:`Opt`
|
|
||||||
constructor::
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
|
||||||
|
|
||||||
conf = cfg.ConfigOpts()
|
|
||||||
|
|
||||||
opt_1 = cfg.StrOpt('opt_1', default='foo', deprecated_name='opt1')
|
|
||||||
opt_2 = cfg.StrOpt('opt_2', default='spam', deprecated_group='DEFAULT')
|
|
||||||
opt_3 = cfg.BoolOpt('opt_3', default=False, deprecated_for_removal=True)
|
|
||||||
|
|
||||||
conf.register_opt(opt_1, group='group_1')
|
|
||||||
conf.register_opt(opt_2, group='group_2')
|
|
||||||
conf.register_opt(opt_3)
|
|
||||||
|
|
||||||
conf(['--config-file', 'config.conf'])
|
|
||||||
|
|
||||||
assert conf.group_1.opt_1 == 'bar'
|
|
||||||
assert conf.group_2.opt_2 == 'eggs'
|
|
||||||
assert conf.opt_3
|
|
||||||
|
|
||||||
Assuming that the file config.conf has the following content::
|
|
||||||
|
|
||||||
[group_1]
|
|
||||||
opt1 = bar
|
|
||||||
|
|
||||||
[DEFAULT]
|
|
||||||
opt_2 = eggs
|
|
||||||
opt_3 = True
|
|
||||||
|
|
||||||
the script will succeed, but will log three respective warnings about the
|
|
||||||
given deprecated options.
|
|
||||||
|
|
||||||
There are also `deprecated_reason` and `deprecated_since` parameters for
|
|
||||||
specifying some additional information about a deprecation.
|
|
||||||
|
|
||||||
All the mentioned parameters can be mixed together in any combinations.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@ -1983,7 +1515,7 @@ class ParseError(iniparser.ParseError):
|
|||||||
|
|
||||||
|
|
||||||
class ConfigParser(iniparser.BaseParser):
|
class ConfigParser(iniparser.BaseParser):
|
||||||
"""Parses a single config file, populating 'sections' to look like:
|
"""Parses a single config file, populating 'sections' to look like::
|
||||||
|
|
||||||
{'DEFAULT': {'key': [value, ...], ...},
|
{'DEFAULT': {'key': [value, ...], ...},
|
||||||
...}
|
...}
|
||||||
|
Loading…
Reference in New Issue
Block a user