From bd463ee3b66a71312275ca23d3eb9c537a29b3ad Mon Sep 17 00:00:00 2001 From: Doug Hellmann Date: Thu, 19 Jul 2018 17:26:38 -0400 Subject: [PATCH] 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 --- doc/source/reference/accessing.rst | 16 + doc/source/reference/cfg.rst | 5 - doc/source/reference/command-line.rst | 37 ++ doc/source/reference/configuration-files.rst | 84 ++++ doc/source/reference/defining.rst | 314 ++++++++++++ doc/source/reference/deprecating.rst | 47 ++ doc/source/reference/globals.rst | 21 + doc/source/reference/index.rst | 15 +- .../reference/{namespaces.rst => naming.rst} | 0 doc/source/reference/opts.rst | 6 +- doc/source/reference/types.rst | 6 +- oslo_config/cfg.py | 472 +----------------- 12 files changed, 537 insertions(+), 486 deletions(-) create mode 100644 doc/source/reference/accessing.rst delete mode 100644 doc/source/reference/cfg.rst create mode 100644 doc/source/reference/command-line.rst create mode 100644 doc/source/reference/configuration-files.rst create mode 100644 doc/source/reference/defining.rst create mode 100644 doc/source/reference/deprecating.rst create mode 100644 doc/source/reference/globals.rst rename doc/source/reference/{namespaces.rst => naming.rst} (100%) diff --git a/doc/source/reference/accessing.rst b/doc/source/reference/accessing.rst new file mode 100644 index 00000000..22b49317 --- /dev/null +++ b/doc/source/reference/accessing.rst @@ -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, + ...) diff --git a/doc/source/reference/cfg.rst b/doc/source/reference/cfg.rst deleted file mode 100644 index 5e3f9882..00000000 --- a/doc/source/reference/cfg.rst +++ /dev/null @@ -1,5 +0,0 @@ --------------- -The cfg Module --------------- - -.. automodule:: oslo_config.cfg diff --git a/doc/source/reference/command-line.rst b/doc/source/reference/command-line.rst new file mode 100644 index 00000000..169b4ba5 --- /dev/null +++ b/doc/source/reference/command-line.rst @@ -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') diff --git a/doc/source/reference/configuration-files.rst b/doc/source/reference/configuration-files.rst new file mode 100644 index 00000000..7544749c --- /dev/null +++ b/doc/source/reference/configuration-files.rst @@ -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}. diff --git a/doc/source/reference/defining.rst b/doc/source/reference/defining.rst new file mode 100644 index 00000000..65a602fe --- /dev/null +++ b/doc/source/reference/defining.rst @@ -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 + ... + + ... + # 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 diff --git a/doc/source/reference/deprecating.rst b/doc/source/reference/deprecating.rst new file mode 100644 index 00000000..8e6ef8cf --- /dev/null +++ b/doc/source/reference/deprecating.rst @@ -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. diff --git a/doc/source/reference/globals.rst b/doc/source/reference/globals.rst new file mode 100644 index 00000000..d910a066 --- /dev/null +++ b/doc/source/reference/globals.rst @@ -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) diff --git a/doc/source/reference/index.rst b/doc/source/reference/index.rst index 9f7e3901..3a6290df 100644 --- a/doc/source/reference/index.rst +++ b/doc/source/reference/index.rst @@ -1,11 +1,17 @@ -=================== - Using oslo.config -=================== +============================= + oslo.config Reference Guide +============================= .. toctree:: :maxdepth: 2 - cfg + defining + naming + accessing + configuration-files + command-line + deprecating + globals opts types configopts @@ -14,7 +20,6 @@ fixture parser exceptions - namespaces styleguide mutable locations diff --git a/doc/source/reference/namespaces.rst b/doc/source/reference/naming.rst similarity index 100% rename from doc/source/reference/namespaces.rst rename to doc/source/reference/naming.rst diff --git a/doc/source/reference/opts.rst b/doc/source/reference/opts.rst index aaf5eadb..b7532ed8 100644 --- a/doc/source/reference/opts.rst +++ b/doc/source/reference/opts.rst @@ -1,8 +1,8 @@ .. _option-definitions: ------------------- -Option Definitions ------------------- +==================== + Opt and Subclasses +==================== .. currentmodule:: oslo_config.cfg diff --git a/doc/source/reference/types.rst b/doc/source/reference/types.rst index 9f7ea131..848d75de 100644 --- a/doc/source/reference/types.rst +++ b/doc/source/reference/types.rst @@ -1,6 +1,6 @@ ---------------------------- -Option Types and Validation ---------------------------- +============================= + Option Types and Validation +============================= .. automodule:: oslo_config.types :members: diff --git a/oslo_config/cfg.py b/oslo_config/cfg.py index e42e52e9..a914f650 100644 --- a/oslo_config/cfg.py +++ b/oslo_config/cfg.py @@ -12,475 +12,7 @@ # License for the specific language governing permissions and limitations # under the License. -r""" -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 - ... - - ... - # 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. - +"""Primary module in oslo_config. """ import argparse @@ -1983,7 +1515,7 @@ class ParseError(iniparser.ParseError): 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, ...], ...}, ...}