| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,360 @@ | ||
| ======================= | ||
| oslo-config-generator | ||
| ======================= | ||
|
|
||
| `oslo-config-generator` is a utility for generating sample config files in a | ||
| variety of formats. Sample config files list all of the available options, | ||
| along with their help string, type, deprecated aliases and defaults. These | ||
| sample files can be used as config files for `oslo.config` itself (``ini``) or | ||
| by configuration management tools (``json``, ``yaml``). | ||
|
|
||
| .. versionadded:: 1.4.0 | ||
|
|
||
| .. versionchanged:: 4.3.0 | ||
|
|
||
| The :option:`oslo-config-generator --format` parameter was added, which | ||
| allows outputting in additional formats. | ||
|
|
||
| Usage | ||
| ----- | ||
|
|
||
| .. program:: oslo-config-generator | ||
|
|
||
| .. code-block:: shell | ||
| oslo-config-generator | ||
| --namespace <namespace> [--namespace <namespace> ...] | ||
| [--output-file <output-file>] | ||
| [--wrap-width <wrap-width>] | ||
| [--format <format>] | ||
| [--minimal] | ||
| [--summarize] | ||
| .. option:: --namespace <namespace> | ||
|
|
||
| Option namespace under ``oslo.config.opts`` in which to query for options. | ||
|
|
||
| .. option:: --output-file <output-file> | ||
|
|
||
| Path of the file to write to. | ||
|
|
||
| :Default: stdout | ||
|
|
||
| .. option:: --wrap-width <wrap-width> | ||
|
|
||
| The maximum length of help lines. | ||
|
|
||
| :Default: 70 | ||
|
|
||
| .. option:: --format <format> | ||
|
|
||
| Desired format for the output. ``ini`` is the only format that can be used | ||
| directly with `oslo.config`. ``json`` and ``yaml`` are intended for | ||
| third-party tools that want to write config files based on the sample config | ||
| data. For more information, refer to :ref:`machine-readable-configs`. | ||
|
|
||
| :Choices: ini, json, yaml | ||
|
|
||
| .. option:: --minimal | ||
|
|
||
| Generate a minimal required configuration. | ||
|
|
||
| .. option:: --summarize | ||
|
|
||
| Only output summaries of help text to config files. Retain longer help text | ||
| for Sphinx documents. | ||
|
|
||
| For example, to generate a sample config file for `oslo.messaging` you would | ||
| run: | ||
|
|
||
| .. code-block:: shell | ||
| $ oslo-config-generator --namespace oslo.messaging > oslo.messaging.conf | ||
| To generate a sample config file for an application ``myapp`` that has its own | ||
| options and uses `oslo.messaging`, you would list both namespaces: | ||
|
|
||
| .. code-block:: shell | ||
| $ oslo-config-generator --namespace myapp \ | ||
| --namespace oslo.messaging > myapp.conf | ||
| To generate a sample config file for `oslo.messaging` in `JSON` format, you | ||
| would run: | ||
|
|
||
| .. code-block:: shell | ||
| $ oslo-config-generator --namespace oslo.messaging \ | ||
| --format json > oslo.messaging.conf | ||
| Defining Option Discovery Entry Points | ||
| -------------------------------------- | ||
|
|
||
| The :option:`oslo-config-generator --namespace` option specifies an entry point | ||
| name registered under the ``oslo.config.opts`` entry point namespace. For | ||
| example, in the `oslo.messaging` ``setup.cfg`` we have: | ||
|
|
||
| .. code-block:: ini | ||
| [entry_points] | ||
| oslo.config.opts = | ||
| oslo.messaging = oslo.messaging.opts:list_opts | ||
| The callable referenced by the entry point should take no arguments and return | ||
| a list of ``(group, [opt_1, opt_2])`` tuples, where ``group`` is either a group | ||
| name as a string or an ``OptGroup`` object. Passing the ``OptGroup`` object | ||
| allows the consumer of the ``list_opts`` method to access and publish group | ||
| help. An example, using both styles: | ||
|
|
||
| .. code-block:: python | ||
| from oslo_config import cfg | ||
| opts1 = [ | ||
| cfg.StrOpt('foo'), | ||
| cfg.StrOpt('bar'), | ||
| ] | ||
| opts2 = [ | ||
| cfg.StrOpt('baz'), | ||
| ] | ||
| baz_group = cfg.OptGroup(name='baz_group' | ||
| title='Baz group options', | ||
| help='Baz group help text') | ||
| cfg.CONF.register_group(baz_group) | ||
| cfg.CONF.register_opts(opts1, group='blaa') | ||
| cfg.CONF.register_opts(opts2, group=baz_group) | ||
| def list_opts(): | ||
| # Allows the generation of the help text for | ||
| # the baz_group OptGroup object. No help | ||
| # text is generated for the 'blaa' group. | ||
| return [('blaa', opts1), (baz_group, opts2)] | ||
| .. note:: | ||
|
|
||
| You should return the original options, not a copy, because the | ||
| default update hooks depend on the original option object being | ||
| returned. | ||
|
|
||
| The module holding the entry point *must* be importable, even if the | ||
| dependencies of that module are not installed. For example, driver | ||
| modules that define options but have optional dependencies on | ||
| third-party modules must still be importable if those modules are not | ||
| installed. To accomplish this, the optional dependency can either be | ||
| imported using :func:`oslo.utils.importutils.try_import` or the option | ||
| definitions can be placed in a file that does not try to import the | ||
| optional dependency. | ||
|
|
||
| Modifying Defaults from Other Namespaces | ||
| ---------------------------------------- | ||
|
|
||
| Occasionally applications need to override the defaults for options | ||
| defined in libraries. At runtime this is done using an API within the | ||
| library. Since the config generator cannot guarantee the order in | ||
| which namespaces will be imported, we can't ensure that application | ||
| code can change the option defaults before the generator loads the | ||
| options from a library. Instead, a separate optional processing hook | ||
| is provided for applications to register a function to update default | ||
| values after *all* options are loaded. | ||
|
|
||
| The hooks are registered in a separate entry point namespace | ||
| (``oslo.config.opts.defaults``), using the same entry point name as | ||
| **the application's** ``list_opts()`` function. | ||
|
|
||
| .. code-block:: ini | ||
| [entry_points] | ||
| oslo.config.opts.defaults = | ||
| keystone = keystone.common.config:update_opt_defaults | ||
| .. warning:: | ||
|
|
||
| Never, under any circumstances, register an entry point using a | ||
| name owned by another project. Doing so causes unexpected interplay | ||
| between projects within the config generator and will result in | ||
| failure to generate the configuration file or invalid values | ||
| showing in the sample. | ||
|
|
||
| In this case, the name of the entry point for the default override | ||
| function *must* match the name of one of the entry points defining | ||
| options for the application in order to be detected and | ||
| used. Applications that have multiple list_opts functions should use | ||
| one that is present in the inputs for the config generator where | ||
| the changed defaults need to appear. For example, if an application | ||
| defines ``foo.api`` to list the API-related options, and needs to | ||
| override the defaults in the ``oslo.middleware.cors`` library, the | ||
| application should register ``foo.api`` under | ||
| ``oslo.config.opts.defaults`` and point to a function within the | ||
| application code space that changes the defaults for | ||
| ``oslo.middleware.cors``. | ||
|
|
||
| The update function should take no arguments. It should invoke the | ||
| public :func:`set_defaults` functions in any libraries for which it | ||
| has option defaults to override, just as the application does during | ||
| its normal startup process. | ||
|
|
||
| .. code-block:: python | ||
| from oslo_log import log | ||
| def update_opt_defaults(): | ||
| log.set_defaults( | ||
| default_log_levels=log.get_default_log_levels() + ['noisy=WARN'], | ||
| ) | ||
| .. _machine-readable-configs: | ||
|
|
||
| Generating Machine Readable Configs | ||
| ----------------------------------- | ||
|
|
||
| All deployment tools have to solve a similar problem: how to generate the | ||
| config files for each service at deployment time. To help with this problem, | ||
| `oslo-config-generator` can generate machine-readable sample config files that | ||
| output the same data as the INI files used by `oslo.config` itself, but in a | ||
| YAML or JSON format that can be more easily consumed by deployment tools. | ||
|
|
||
| .. important:: | ||
|
|
||
| The YAML and JSON-formatted files generated by `oslo-config-generator` | ||
| cannot be used by `oslo.config` itself - they are only for use by other | ||
| tools. | ||
|
|
||
| For example, some YAML-formatted output might look like so: | ||
|
|
||
| .. code-block:: yaml | ||
| generator_options: | ||
| config_dir: [] | ||
| config_file: [] | ||
| format_: yaml | ||
| minimal: false | ||
| namespace: | ||
| - keystone | ||
| output_file: null | ||
| summarize: false | ||
| wrap_width: 70 | ||
| options: | ||
| DEFAULT: | ||
| help: '' | ||
| opts: | ||
| - advanced: false | ||
| choices: [] | ||
| default: null | ||
| deprecated_for_removal: false | ||
| deprecated_opts: [] | ||
| deprecated_reason: null | ||
| deprecated_since: null | ||
| dest: admin_token | ||
| help: Using this feature is *NOT* recommended. Instead, use the `keystone-manage | ||
| bootstrap` command. The value of this option is treated as a "shared secret" | ||
| that can be used to bootstrap Keystone through the API. This "token" does | ||
| not represent a user (it has no identity), and carries no explicit authorization | ||
| (it effectively bypasses most authorization checks). If set to `None`, the | ||
| value is ignored and the `admin_token` middleware is effectively disabled. | ||
| However, to completely disable `admin_token` in production (highly recommended, | ||
| as it presents a security risk), remove `AdminTokenAuthMiddleware` (the `admin_token_auth` | ||
| filter) from your paste application pipelines (for example, in `keystone-paste.ini`). | ||
| max: null | ||
| metavar: null | ||
| min: null | ||
| mutable: false | ||
| name: admin_token | ||
| namespace: keystone | ||
| positional: false | ||
| required: false | ||
| sample_default: null | ||
| secret: true | ||
| short: null | ||
| type: string value | ||
| - ... | ||
| ... | ||
| deprecated_options: | ||
| DEFAULT: | ||
| - name: bind_host | ||
| replacement_group: eventlet_server | ||
| replacement_name: public_bind_host | ||
| where the top-level keys are: | ||
|
|
||
| ``generator_options`` | ||
|
|
||
| The options passed to the :program:`oslo-config-generator` tool itself | ||
|
|
||
| ``options`` | ||
|
|
||
| All options registered in the provided namespace(s). These are grouped under | ||
| the ``OptGroup`` they are assigned to which defaults to ``DEFAULT`` if unset. | ||
|
|
||
| For information on the various attributes of each option, refer to | ||
| :class:`oslo_config.cfg.Opt` and its subclasses. | ||
|
|
||
| ``deprecated_options`` | ||
|
|
||
| All **deprecated** options registered in the provided namespace(s). Like | ||
| ``options``, these options are grouped by ``OptGroup``. | ||
|
|
||
| Generating Multiple Sample Configs | ||
| ---------------------------------- | ||
|
|
||
| A single codebase might have multiple programs, each of which use a subset of | ||
| the total set of options registered by the codebase. In that case, you can | ||
| register multiple entry points: | ||
|
|
||
| .. code-block:: ini | ||
| [entry_points] | ||
| oslo.config.opts = | ||
| nova.common = nova.config:list_common_opts | ||
| nova.api = nova.config:list_api_opts | ||
| nova.compute = nova.config:list_compute_opts | ||
| and generate a config file specific to each program: | ||
|
|
||
| .. code-block:: shell | ||
| $ oslo-config-generator --namespace oslo.messaging \ | ||
| --namespace nova.common \ | ||
| --namespace nova.api > nova-api.conf | ||
| $ oslo-config-generator --namespace oslo.messaging \ | ||
| --namespace nova.common \ | ||
| --namespace nova.compute > nova-compute.conf | ||
| To make this more convenient, you can use config files to describe your config | ||
| files: | ||
|
|
||
| .. code-block:: shell | ||
| $ cat > config-generator/api.conf <<EOF | ||
| [DEFAULT] | ||
| output_file = etc/nova/nova-api.conf | ||
| namespace = oslo.messaging | ||
| namespace = nova.common | ||
| namespace = nova.api | ||
| EOF | ||
| $ cat > config-generator/compute.conf <<EOF | ||
| [DEFAULT] | ||
| output_file = etc/nova/nova-compute.conf | ||
| namespace = oslo.messaging | ||
| namespace = nova.common | ||
| namespace = nova.compute | ||
| EOF | ||
| $ oslo-config-generator --config-file config-generator/api.conf | ||
| $ oslo-config-generator --config-file config-generator/compute.conf | ||
| Sample Default Values | ||
| --------------------- | ||
| The default runtime values of configuration options are not always the most | ||
| suitable values to include in sample config files - for example, rather than | ||
| including the IP address or hostname of the machine where the config file | ||
| was generated, you might want to include something like ``10.0.0.1``. To | ||
| facilitate this, options can be supplied with a ``sample_default`` attribute: | ||
| .. code-block:: python | ||
| cfg.StrOpt('base_dir' | ||
| default=os.getcwd(), | ||
| sample_default='/usr/lib/myapp') |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| ================================ | ||
| oslo.config Command Line Tools | ||
| ================================ | ||
|
|
||
| .. toctree:: | ||
| :maxdepth: 2 | ||
|
|
||
| generator | ||
| validator | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| ============================== | ||
| Configuration Source Drivers | ||
| ============================== | ||
|
|
||
| In addition to command line options and configuration files, | ||
| oslo.config can access configuration settings in other locations using | ||
| *drivers* to define new *sources*. | ||
|
|
||
| .. list-plugins:: oslo.config.driver | ||
| :detailed: |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,188 @@ | ||
| ========================= | ||
| Configuration file format | ||
| ========================= | ||
|
|
||
| OpenStack uses the INI file format for configuration files. | ||
| An INI file is a simple text file that specifies options as | ||
| ``key=value`` pairs, grouped into sections. | ||
| The ``DEFAULT`` section contains most of the configuration options. | ||
| Lines starting with a hash sign (``#``) are comment lines. | ||
| For example: | ||
|
|
||
| .. code-block:: ini | ||
| [DEFAULT] | ||
| # Print debugging output (set logging level to DEBUG instead | ||
| # of default WARNING level). (boolean value) | ||
| debug = true | ||
| [database] | ||
| # The SQLAlchemy connection string used to connect to the | ||
| # database (string value) | ||
| connection = mysql+pymysql://keystone:KEYSTONE_DBPASS@controller/keystone | ||
| Options can have different types for values. | ||
| The comments in the sample config files always mention these and the | ||
| tables mention the ``Opt`` value as first item like ``(BoolOpt) Toggle...``. | ||
| The following types are used by OpenStack: | ||
|
|
||
| boolean value (``BoolOpt``) | ||
| Enables or disables an option. The allowed values are ``true`` and ``false``. | ||
|
|
||
| .. code-block:: ini | ||
| # Enable the experimental use of database reconnect on | ||
| # connection lost (boolean value) | ||
| use_db_reconnect = false | ||
| floating point value (``FloatOpt``) | ||
| A floating point number like ``0.25`` or ``1000``. | ||
|
|
||
| .. code-block:: ini | ||
| # Sleep time in seconds for polling an ongoing async task | ||
| # (floating point value) | ||
| task_poll_interval = 0.5 | ||
| integer value (``IntOpt``) | ||
| An integer number is a number without fractional components, | ||
| like ``0`` or ``42``. | ||
|
|
||
| .. code-block:: ini | ||
| # The port which the OpenStack Compute service listens on. | ||
| # (integer value) | ||
| compute_port = 8774 | ||
| IP address (``IPOpt``) | ||
| An IPv4 or IPv6 address. | ||
|
|
||
| .. code-block:: ini | ||
| # Address to bind the server. Useful when selecting a particular network | ||
| # interface. (ip address value) | ||
| bind_host = 0.0.0.0 | ||
| key-value pairs (``DictOpt``) | ||
| A key-value pairs, also known as a dictionary. The key value pairs are | ||
| separated by commas and a colon is used to separate key and value. | ||
| Example: ``key1:value1,key2:value2``. | ||
|
|
||
| .. code-block:: ini | ||
| # Parameter for l2_l3 workflow setup. (dict value) | ||
| l2_l3_setup_params = data_ip_address:192.168.200.99, \ | ||
| data_ip_mask:255.255.255.0,data_port:1,gateway:192.168.200.1,ha_port:2 | ||
| list value (``ListOpt``) | ||
| Represents values of other types, separated by commas. | ||
| As an example, the following sets ``allowed_rpc_exception_modules`` | ||
| to a list containing the four elements ``oslo.messaging.exceptions``, | ||
| ``nova.exception``, ``cinder.exception``, and ``exceptions``: | ||
|
|
||
| .. code-block:: ini | ||
| # Modules of exceptions that are permitted to be recreated | ||
| # upon receiving exception data from an rpc call. (list value) | ||
| allowed_rpc_exception_modules = oslo.messaging.exceptions,nova.exception | ||
| multi valued (``MultiStrOpt``) | ||
| A multi-valued option is a string value and can be given | ||
| more than once, all values will be used. | ||
|
|
||
| .. code-block:: ini | ||
| # Driver or drivers to handle sending notifications. (multi valued) | ||
| notification_driver = nova.openstack.common.notifier.rpc_notifier | ||
| notification_driver = ceilometer.compute.nova_notifier | ||
| port value (``PortOpt``) | ||
| A TCP/IP port number. Ports can range from 1 to 65535. | ||
|
|
||
| .. code-block:: ini | ||
| # Port to which the UDP socket is bound. (port value) | ||
| # Minimum value: 1 | ||
| # Maximum value: 65535 | ||
| udp_port = 4952 | ||
| string value (``StrOpt``) | ||
| Strings can be optionally enclosed with single or double quotes. | ||
|
|
||
| .. code-block:: ini | ||
| # The format for an instance that is passed with the log message. | ||
| # (string value) | ||
| instance_format = "[instance: %(uuid)s] " | ||
| Sections | ||
| ~~~~~~~~ | ||
|
|
||
| Configuration options are grouped by section. | ||
| Most configuration files support at least the following sections: | ||
|
|
||
| [DEFAULT] | ||
| Contains most configuration options. | ||
| If the documentation for a configuration option does not | ||
| specify its section, assume that it appears in this section. | ||
|
|
||
| [database] | ||
| Configuration options for the database that stores | ||
| the state of the OpenStack service. | ||
|
|
||
| Substitution | ||
| ~~~~~~~~~~~~ | ||
|
|
||
| The configuration file supports variable substitution. | ||
| After you set a configuration option, it can be referenced | ||
| in later configuration values when you precede it with | ||
| a ``$``, like ``$OPTION``. | ||
|
|
||
| The following example uses the values of ``rabbit_host`` and | ||
| ``rabbit_port`` to define the value of the ``rabbit_hosts`` | ||
| option, in this case as ``controller:5672``. | ||
|
|
||
| .. code-block:: ini | ||
| # The RabbitMQ broker address where a single node is used. | ||
| # (string value) | ||
| rabbit_host = controller | ||
| # The RabbitMQ broker port where a single node is used. | ||
| # (integer value) | ||
| rabbit_port = 5672 | ||
| # RabbitMQ HA cluster host:port pairs. (list value) | ||
| rabbit_hosts = $rabbit_host:$rabbit_port | ||
| To avoid substitution, escape the ``$`` with ``$$`` or ``\$``. | ||
| For example, if your LDAP DNS password is ``$xkj432``, specify it, as follows: | ||
|
|
||
| .. code-block:: ini | ||
| ldap_dns_password = $$xkj432 | ||
| The code uses the Python ``string.Template.safe_substitute()`` | ||
| method to implement variable substitution. | ||
| For more details on how variable substitution is resolved, see | ||
| https://docs.python.org/2/library/string.html#template-strings | ||
| and `PEP 292 <https://www.python.org/dev/peps/pep-0292/>`_. | ||
|
|
||
| Whitespace | ||
| ~~~~~~~~~~ | ||
|
|
||
| To include whitespace in a configuration value, use a quoted string. | ||
| For example: | ||
|
|
||
| .. code-block:: ini | ||
| ldap_dns_password='a password with spaces' | ||
| Define an alternate location for a config file | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
|
||
| Most services and the ``*-manage`` command-line clients load | ||
| the configuration file. | ||
| To define an alternate location for the configuration file, | ||
| pass the ``--config-file CONFIG_FILE`` parameter | ||
| when you start a service or call a ``*-manage`` command. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| ===================== | ||
| Configuration Guide | ||
| ===================== | ||
|
|
||
| .. toctree:: | ||
| :maxdepth: 2 | ||
|
|
||
| quickstart | ||
| format | ||
| mutable | ||
| options | ||
| drivers |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| ========================== | ||
| Changing config at runtime | ||
| ========================== | ||
|
|
||
| OpenStack Newton introduces the ability to reload (or 'mutate') certain | ||
| configuration options at runtime without a service restart. The following | ||
| projects support this: | ||
|
|
||
| * Compute (nova) | ||
|
|
||
| Check individual options to discover if they are mutable. | ||
|
|
||
|
|
||
| In practice | ||
| ~~~~~~~~~~~ | ||
|
|
||
| A common use case is to enable debug logging after a failure. Use the mutable | ||
| config option called 'debug' to do this (providing ``log_config_append`` | ||
| has not been set). An admin user may perform the following steps: | ||
|
|
||
| #. Log onto the compute node. | ||
| #. Edit the config file (EG ``nova.conf``) and change 'debug' to ``True``. | ||
| #. Send a SIGHUP signal to the nova process (For example, ``pkill -HUP nova``). | ||
|
|
||
| A log message will be written out confirming that the option has been changed. | ||
| If you use a CMS like Ansible, Chef, or Puppet, we recommend scripting these | ||
| steps through your CMS. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| ======================================== | ||
| Configuration Options from oslo.config | ||
| ======================================== | ||
|
|
||
| When loading values from the sources defined by the following options, the | ||
| precedence is as follows: | ||
|
|
||
| #. Command Line | ||
| #. Environment Variables | ||
| #. Config Files from ``--config-dir`` [1]_ | ||
| #. Config Files from ``--config-file`` | ||
| #. Pluggable Config Sources | ||
|
|
||
| If a value is specified in multiple locations, the location used will be the | ||
| one higher in the list. For example, if a value is specified both on the | ||
| command line and in an environment variable, the value from the command line | ||
| will be the one returned. | ||
|
|
||
| .. [1] Files in a config dir are parsed in alphabetical order. Later files | ||
| take precedence over earlier ones. | ||
| .. show-options:: | ||
|
|
||
| oslo.config |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| ========================== | ||
| oslo.config Quick Start! | ||
| ========================== | ||
|
|
||
| Are you brand new to oslo.config? This brief tutorial will get you started | ||
| understanding some of the fundamentals. | ||
|
|
||
| Prerequisites | ||
| ------------- | ||
| * A plain text editor or Python-enabled IDE | ||
| * A Python interpreter | ||
| * A command shell from which the interpreter can be invoked | ||
| * The oslo_config library in your Python path. | ||
|
|
||
| Test Script | ||
| ----------- | ||
| Put this in a file called ``oslocfgtest.py``. | ||
|
|
||
| .. code:: python | ||
| # The sys module lets you get at the command line arguments. | ||
| import sys | ||
| # Load up the cfg module, which contains all the classes and methods | ||
| # you'll need. | ||
| from oslo_config import cfg | ||
| # Define an option group | ||
| grp = cfg.OptGroup('mygroup') | ||
| # Define a couple of options | ||
| opts = [cfg.StrOpt('option1'), | ||
| cfg.IntOpt('option2', default=42)] | ||
| # Register your config group | ||
| cfg.CONF.register_group(grp) | ||
| # Register your options within the config group | ||
| cfg.CONF.register_opts(opts, group=grp) | ||
| # Process command line arguments. The arguments tell CONF where to | ||
| # find your config file, which it loads and parses to populate itself. | ||
| cfg.CONF(sys.argv[1:]) | ||
| # Now you can access the values from the config file as | ||
| # CONF.<group>.<opt> | ||
| print("The value of option1 is %s" % cfg.CONF.mygroup.option1) | ||
| print("The value of option2 is %d" % cfg.CONF.mygroup.option2) | ||
| Conf File | ||
| --------- | ||
| Put this in a file called ``oslocfgtest.conf`` in the same directory as | ||
| ``oslocfgtest.py``. | ||
|
|
||
| .. code:: ini | ||
| [mygroup] | ||
| option1 = foo | ||
| # Comment out option2 to test the default value | ||
| # option2 = 123 | ||
| Run It! | ||
| ------- | ||
| From your command shell, in the same directory as your script and conf, invoke: | ||
|
|
||
| .. code:: shell | ||
| python oslocfgtest.py --config-file oslocfgtest.conf | ||
| Revel in the output being exactly as expected. If you've done everything | ||
| right, you should see: | ||
|
|
||
| .. code:: shell | ||
| The value of option1 is foo | ||
| The value of option2 is 42 | ||
| Now go play with some more advanced option settings! |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,4 +2,4 @@ | |
| Contributing | ||
| ============== | ||
|
|
||
| .. include:: ../../../CONTRIBUTING.rst | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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, | ||
| ...) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| ====================== | ||
| 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'] | ||
| By default, positional arguments are also required. You may opt-out of this | ||
| behavior by setting ``required=False``, to have an optional positional | ||
| argument. | ||
|
|
||
| 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') |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| ============================= | ||
| Loading Configuration Files | ||
| ============================= | ||
|
|
||
| The config manager has two CLI options defined by default, ``--config-file`` | ||
| and ``--config-dir``: | ||
|
|
||
| .. code-block:: python | ||
| class ConfigOpts: | ||
| 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. Files in a | ||
| configuration directory are parsed after any individual configuration files, | ||
| so values that appear in both a configuration file and configuration directory | ||
| will use the value from the directory. | ||
|
|
||
| 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}. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,320 @@ | ||
| ================== | ||
| Defining Options | ||
| ================== | ||
|
|
||
| Configuration options may be set on the command line, in the | ||
| :mod:`environment <oslo_config.sources._environment>`, or in config files. | ||
| Options are processed in that order. | ||
|
|
||
| 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: | ||
| 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). | ||
|
|
||
| Note that options registered for CLI use do not need to be registered again for | ||
| use from other config sources, such as files. CLI options can be read from | ||
| either the CLI or from the other enabled config sources. | ||
|
|
||
| .. 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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
|
|
||
| --------------- | ||
| Backend Drivers | ||
| --------------- | ||
|
|
||
| Refer to :py:mod:`oslo_config.sources` | ||
|
|
||
|
|
||
| Known Backend Drivers | ||
| --------------------- | ||
|
|
||
| .. NOTE(bnemec): These are private modules, so we need to explicitly | ||
| document them | ||
| .. automodule:: oslo_config.sources._uri | ||
| .. automodule:: oslo_config.sources._environment |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| ---------------- | ||
| Helper Functions | ||
| ---------------- | ||
|
|
||
| Showing detailed locations for configuration settings | ||
| ----------------------------------------------------- | ||
|
|
||
| ``oslo.config`` can track the location in application and library code | ||
| where an option is defined, defaults are set, or values are | ||
| overridden. This feature is disabled by default because it is | ||
| expensive and incurs a significant performance penalty, but it can be | ||
| useful for developers tracing down issues with configuration option | ||
| definitions. | ||
|
|
||
| To turn on detailed location tracking, set the environment variable | ||
| ``OSLO_CONFIG_SHOW_CODE_LOCATIONS`` to any non-empty value (for | ||
| example, ``"1"`` or ``"yes, please"``) before starting the | ||
| application, test suite, or script. Then use | ||
| :func:`ConfigOpts.get_location` to access the location data for the | ||
| option. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| ============================= | ||
| oslo.config Reference Guide | ||
| ============================= | ||
|
|
||
| .. toctree:: | ||
| :maxdepth: 2 | ||
|
|
||
| API <api/modules> | ||
| defining | ||
| naming | ||
| accessing | ||
| configuration-files | ||
| command-line | ||
| deprecating | ||
| globals | ||
| helpers | ||
| styleguide | ||
| mutable | ||
| locations | ||
| sphinxext | ||
| sphinxconfiggen | ||
| drivers | ||
| faq |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| ========================== | ||
| Option Setting Locations | ||
| ========================== | ||
|
|
||
| .. currentmodule:: oslo_config.cfg | ||
|
|
||
| The :func:`~ConfigOpts.get_location` method of :class:`ConfigOpts` can | ||
| be used to determine where the value for an option was set, either by | ||
| the user or by the application code. The return value is a | ||
| :class:`LocationInfo` instance, which includes 2 fields: ``location`` | ||
| and ``detail``. | ||
|
|
||
| The ``location`` value is a member of the :class:`Locations` enum, | ||
| which has 5 possible values. The ``detail`` value is a string | ||
| describing the location. Its value depends on the ``location``. | ||
|
|
||
| .. list-table:: | ||
| :header-rows: 1 | ||
| :widths: 15 15 35 35 | ||
|
|
||
| * - Value | ||
| - ``is_user_controlled`` | ||
| - Description | ||
| - ``detail`` | ||
| * - ``opt_default`` | ||
| - ``False`` | ||
| - The original default set when the option was defined. | ||
| - The source file name where the option is defined. | ||
| * - ``set_default`` | ||
| - ``False`` | ||
| - A default value set by the application as an override of the | ||
| original default. This usually only applies to options defined | ||
| in libraries. | ||
| - The source file name where :func:`~ConfigOpts.set_default` or | ||
| :func:`set_defaults` was called. | ||
| * - ``set_override`` | ||
| - ``False`` | ||
| - A forced value set by the application. | ||
| - The source file name where :func:`~ConfigOpts.set_override` was | ||
| called. | ||
| * - ``user`` | ||
| - ``True`` | ||
| - A value set by the user through a configuration backend such as | ||
| a file. | ||
| - The configuration file where the option is set. | ||
| * - ``command_line`` | ||
| - ``True`` | ||
| - A value set by the user on the command line. | ||
| - Empty string. | ||
| * - ``environment`` | ||
| - ``True`` | ||
| - A value set by the user in the process environment. | ||
| - The name of the environment variable. | ||
|
|
||
| Did a user set a configuration option? | ||
| ====================================== | ||
|
|
||
| Each :class:`Locations` enum value has a boolean property indicating | ||
| whether that type of location is managed by the user. This eliminates | ||
| the need for application code to track which types of locations are | ||
| user-controlled separately. | ||
|
|
||
| .. code-block:: python | ||
| loc = CONF.get_location('normal_opt').location | ||
| if loc.is_user_controlled: | ||
| print('normal_opt was set by the user') | ||
| else: | ||
| print('normal_opt was set by the application') |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| # 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. | ||
| r""" | ||
| Oslo.config's primary source of configuration data are plaintext, INI-like | ||
| style, configuration files. With the addition of backend drivers support, | ||
| it is possible to store configuration data in different places and with | ||
| different formats, as long as there exists a proper driver to connect to those | ||
| external sources and provide a way to fetch configuration values from them. | ||
| A backend driver implementation is divided in two main classes, a driver | ||
| class of type :class:`ConfigurationSourceDriver` and a configuration source | ||
| class of type :class:`ConfigurationSource`. | ||
| **IMPORTANT:** At this point, all backend drivers are only able to provide | ||
| immutable values. This protects applications and services from having options | ||
| in external sources mutated when they reload configuration files. | ||
| """ | ||
|
|
||
| import abc | ||
|
|
||
|
|
||
| # We cannot use None as a sentinel indicating a missing value because it | ||
| # may be a valid value or default, so we use a custom singleton instead. | ||
| _NoValue = object() | ||
|
|
||
|
|
||
| class ConfigurationSourceDriver(metaclass=abc.ABCMeta): | ||
| """A backend driver option for oslo.config. | ||
| For each group name listed in **config_source** in the **DEFAULT** group, | ||
| a :class:`ConfigurationSourceDriver` is responsible for creating one new | ||
| instance of a :class:`ConfigurationSource`. The proper driver class to be | ||
| used is selected based on the **driver** option inside each one of the | ||
| groups listed in config_source and loaded through entry points managed by | ||
| stevedore using the namespace oslo.config.driver:: | ||
| [DEFAULT] | ||
| config_source = source1 | ||
| config_source = source2 | ||
| ... | ||
| [source1] | ||
| driver = remote_file | ||
| ... | ||
| [source2] | ||
| driver = castellan | ||
| ... | ||
| Each specific driver knows all the available options to properly instatiate | ||
| a ConfigurationSource using the values comming from the given group in the | ||
| open_source_from_opt_group() method and is able to generate sample config | ||
| through the list_options_for_discovery() method. | ||
| """ | ||
|
|
||
| @abc.abstractmethod | ||
| def open_source_from_opt_group(self, conf, group_name): | ||
| """Return an open configuration source. | ||
| Uses group_name to find the configuration settings for the new | ||
| source and then open the configuration source and return it. | ||
| If a source cannot be open, raises an appropriate exception. | ||
| :param conf: The active configuration option handler from which | ||
| to seek configuration values. | ||
| :type conf: ConfigOpts | ||
| :param group_name: The configuration option group name where the | ||
| options for the source are stored. | ||
| :type group_name: str | ||
| :returns: an instance of a subclass of ConfigurationSource | ||
| """ | ||
|
|
||
| @abc.abstractmethod | ||
| def list_options_for_discovery(self): | ||
| """Return the list of options available to configure a new source. | ||
| Drivers should advertise all supported options in this method | ||
| for the purpose of sample generation by oslo-config-generator. | ||
| For an example on how to implement this method | ||
| you can check the **remote_file** driver at | ||
| oslo_config.sources._uri.URIConfigurationSourceDriver. | ||
| :returns: a list of supported options of a ConfigurationSource. | ||
| """ | ||
|
|
||
|
|
||
| class ConfigurationSource(metaclass=abc.ABCMeta): | ||
| """A configuration source option for oslo.config. | ||
| A configuration source is able to fetch configuration values based on | ||
| a (group, option) key from an external source that supports key-value | ||
| mapping such as INI files, key-value stores, secret stores, and so on. | ||
| """ | ||
|
|
||
| @abc.abstractmethod | ||
| def get(self, group_name, option_name, opt): | ||
| """Return the value of the option from the group. | ||
| :param group_name: Name of the group. | ||
| :type group_name: str | ||
| :param option_name: Name of the option. | ||
| :type option_name: str | ||
| :param opt: The option definition. | ||
| :type opt: Opt | ||
| :returns: A tuple (value, location) where value is the option value | ||
| or oslo_config.sources._NoValue if the (group, option) is | ||
| not present in the source, and location is a LocationInfo. | ||
| """ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| # 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. | ||
| r""" | ||
| Environment | ||
| ----------- | ||
| The **environment** backend driver provides a method of accessing | ||
| configuration data in environment variables. It is enabled by default | ||
| and requires no additional configuration to use. The environment is | ||
| checked after command line options, but before configuration files. | ||
| Environment variables are checked for any configuration data. The variable | ||
| names take the form: | ||
| * A prefix of ``OS_`` | ||
| * The group name, uppercased | ||
| * Separated from the option name by a `__` (double underscore) | ||
| * Followed by the name | ||
| For an option that looks like this in the usual INI format:: | ||
| [placement_database] | ||
| connection = sqlite:/// | ||
| the corresponding environment variable would be | ||
| ``OS_PLACEMENT_DATABASE__CONNECTION``. | ||
| The Driver Class | ||
| ================ | ||
| .. autoclass:: EnvironmentConfigurationSourceDriver | ||
| The Configuration Source Class | ||
| ============================== | ||
| .. autoclass:: EnvironmentConfigurationSource | ||
| """ | ||
|
|
||
| import os | ||
|
|
||
| # Avoid circular import | ||
| import oslo_config.cfg | ||
| from oslo_config import sources | ||
|
|
||
|
|
||
| # In current practice this class is not used because the | ||
| # EnvironmentConfigurationSource is loaded by default, but we keep it | ||
| # here in case we choose to change that behavior in the future. | ||
| class EnvironmentConfigurationSourceDriver(sources.ConfigurationSourceDriver): | ||
| """A backend driver for environment variables. | ||
| This configuration source is available by default and does not need special | ||
| configuration to use. The sample config is generated automatically but is | ||
| not necessary. | ||
| """ | ||
|
|
||
| def list_options_for_discovery(self): | ||
| """There are no options for this driver.""" | ||
| return [] | ||
|
|
||
| def open_source_from_opt_group(self, conf, group_name): | ||
| return EnvironmentConfigurationSource() | ||
|
|
||
|
|
||
| class EnvironmentConfigurationSource(sources.ConfigurationSource): | ||
| """A configuration source for options in the environment.""" | ||
|
|
||
| @staticmethod | ||
| def get_name(group_name, option_name): | ||
| """Return the expected environment variable name for the given option. | ||
| :param group_name: The group name or None. Defaults to 'DEFAULT' if | ||
| None. | ||
| :param option_name: The option name. | ||
| :returns: Th expected environment variable name. | ||
| """ | ||
| group_name = group_name or 'DEFAULT' | ||
| return 'OS_{}__{}'.format(group_name.upper(), option_name.upper()) | ||
|
|
||
| def get(self, group_name, option_name, opt): | ||
| env_name = self.get_name(group_name, option_name) | ||
| try: | ||
| value = os.environ[env_name] | ||
| loc = oslo_config.cfg.LocationInfo( | ||
| oslo_config.cfg.Locations.environment, env_name) | ||
| return (value, loc) | ||
| except KeyError: | ||
| return (sources._NoValue, None) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,181 @@ | ||
| # 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. | ||
| r""" | ||
| Remote File | ||
| ----------- | ||
| The **remote_file** backend driver is the first driver implemented by | ||
| oslo.config. It extends the previous limit of only accessing local files | ||
| to a new scenario where it is possible to access configuration data over | ||
| the network. The **remote_file** driver is based on the **requests** module | ||
| and is capable of accessing remote files through **HTTP** or **HTTPS**. | ||
| To definition of a remote_file configuration data source can be as minimal as:: | ||
| [DEFAULT] | ||
| config_source = external_config_group | ||
| [external_config_group] | ||
| driver = remote_file | ||
| uri = http://mydomain.com/path/to/config/data.conf | ||
| Or as complete as:: | ||
| [DEFAULT] | ||
| config_source = external_config_group | ||
| [external_config_group] | ||
| driver = remote_file | ||
| uri = https://mydomain.com/path/to/config/data.conf | ||
| ca_path = /path/to/server/ca.pem | ||
| client_key = /path/to/my/key.pem | ||
| client_cert = /path/to/my/cert.pem | ||
| On the following sessions, you can find more information about this driver's | ||
| classes and its options. | ||
| The Driver Class | ||
| ================ | ||
| .. autoclass:: URIConfigurationSourceDriver | ||
| The Configuration Source Class | ||
| ============================== | ||
| .. autoclass:: URIConfigurationSource | ||
| """ | ||
|
|
||
| import requests | ||
| import tempfile | ||
|
|
||
| from oslo_config import cfg | ||
| from oslo_config import sources | ||
|
|
||
|
|
||
| class URIConfigurationSourceDriver(sources.ConfigurationSourceDriver): | ||
| """A backend driver for remote files served through http[s]. | ||
| Required options: | ||
| - uri: URI containing the file location. | ||
| Non-required options: | ||
| - ca_path: The path to a CA_BUNDLE file or directory with | ||
| certificates of trusted CAs. | ||
| - client_cert: Client side certificate, as a single file path | ||
| containing either the certificate only or the | ||
| private key and the certificate. | ||
| - client_key: Client side private key, in case client_cert is | ||
| specified but does not includes the private key. | ||
| """ | ||
|
|
||
| _uri_driver_opts = [ | ||
| cfg.URIOpt( | ||
| 'uri', | ||
| schemes=['http', 'https'], | ||
| required=True, | ||
| sample_default='https://example.com/my-configuration.ini', | ||
| help=('Required option with the URI of the ' | ||
| 'extra configuration file\'s location.'), | ||
| ), | ||
| cfg.StrOpt( | ||
| 'ca_path', | ||
| sample_default='/etc/ca-certificates', | ||
| help=('The path to a CA_BUNDLE file or directory ' | ||
| 'with certificates of trusted CAs.'), | ||
| ), | ||
| cfg.StrOpt( | ||
| 'client_cert', | ||
| sample_default='/etc/ca-certificates/service-client-keystore', | ||
| help=('Client side certificate, as a single file path ' | ||
| 'containing either the certificate only or the ' | ||
| 'private key and the certificate.'), | ||
| ), | ||
| cfg.StrOpt( | ||
| 'client_key', | ||
| help=('Client side private key, in case client_cert is ' | ||
| 'specified but does not includes the private key.'), | ||
| ), | ||
| cfg.StrOpt( | ||
| 'timeout', | ||
| default=60, | ||
| help=('Timeout is the number of seconds the request will wait ' | ||
| 'for your client to establish a connection to a remote ' | ||
| 'machine call on the socket.'), | ||
| ), | ||
| ] | ||
|
|
||
| def list_options_for_discovery(self): | ||
| return self._uri_driver_opts | ||
|
|
||
| def open_source_from_opt_group(self, conf, group_name): | ||
| conf.register_opts(self._uri_driver_opts, group_name) | ||
|
|
||
| return URIConfigurationSource( | ||
| conf[group_name].uri, | ||
| conf[group_name].ca_path, | ||
| conf[group_name].client_cert, | ||
| conf[group_name].client_key, | ||
| conf[group_name].timeout) | ||
|
|
||
|
|
||
| class URIConfigurationSource(sources.ConfigurationSource): | ||
| """A configuration source for remote files served through http[s]. | ||
| :param uri: The Uniform Resource Identifier of the configuration to be | ||
| retrieved. | ||
| :param ca_path: The path to a CA_BUNDLE file or directory with | ||
| certificates of trusted CAs. | ||
| :param client_cert: Client side certificate, as a single file path | ||
| containing either the certificate only or the | ||
| private key and the certificate. | ||
| :param client_key: Client side private key, in case client_cert is | ||
| specified but does not includes the private key. | ||
| """ | ||
|
|
||
| def __init__(self, uri, ca_path=None, client_cert=None, client_key=None, | ||
| timeout=60): | ||
| self._uri = uri | ||
| self._namespace = cfg._Namespace(cfg.ConfigOpts()) | ||
|
|
||
| data = self._fetch_uri(uri, ca_path, client_cert, client_key, timeout) | ||
|
|
||
| with tempfile.NamedTemporaryFile() as tmpfile: | ||
| tmpfile.write(data.encode("utf-8")) | ||
| tmpfile.flush() | ||
|
|
||
| cfg.ConfigParser._parse_file(tmpfile.name, self._namespace) | ||
|
|
||
| def _fetch_uri(self, uri, ca_path, client_cert, client_key, | ||
| timeout): | ||
| verify = ca_path if ca_path else True | ||
| cert = (client_cert, client_key) if client_cert and client_key else \ | ||
| client_cert | ||
|
|
||
| with requests.get(uri, verify=verify, cert=cert, | ||
| timeout=timeout) as response: | ||
| response.raise_for_status() # raises only in case of HTTPError | ||
|
|
||
| return response.text | ||
|
|
||
| def get(self, group_name, option_name, opt): | ||
| try: | ||
| return self._namespace._get_value( | ||
| [(group_name, option_name)], | ||
| multi=opt.multi) | ||
| except KeyError: | ||
| return (sources._NoValue, None) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| #!/bin/bash completion for {scriptname} | ||
|
|
||
| _{scriptname}(){{ | ||
| local cur prev | ||
| local -A ARGS MAP FORCE OPTS OPTS_SUB MULTI | ||
|
|
||
| COMPREPLY=() | ||
| cur="${{COMP_WORDS[COMP_CWORD]}}" | ||
| prev="${{COMP_WORDS[COMP_CWORD-1]}}" | ||
|
|
||
| OPTS=({opts}) | ||
| OPTS_SUB=({opts_sub}) | ||
| ARGS=({args}) | ||
| MAP=({map}) | ||
| MULTI=({multi}) | ||
|
|
||
| if [ ! -z "$prev" ]; then | ||
| # if is an argument complete with list of choice if define | ||
| prev_key=${{MAP[$prev]}} | ||
| if [ ! -z $prev_key ] && [ ! -z "${{ARGS[$prev_key]}}" ]; then | ||
| COMPREPLY=($(compgen -W "${{ARGS[$prev_key]}}" -- "${{cur}}")) | ||
| return 0 | ||
| fi | ||
| fi | ||
| for in_use in ${{COMP_WORDS[@]:1}}; do | ||
| key=${{MAP[$in_use]}} | ||
| IFS='|' | ||
| if [[ -v OPTS_SUB[$key] ]];then | ||
| # If is a subcommand redefine completion | ||
| unset OPTS | ||
| local -A OPTS | ||
| for el in ${{OPTS_SUB[$key]}}; do | ||
| IFS='=' | ||
| read k v <<< ${{el}} | ||
| IFS='|' | ||
| OPTS+=( [${{k}}]="${{v}}" ) | ||
| done | ||
| fi | ||
| unset IFS | ||
| # Unset option that is already use | ||
| if [[ -z "MULTI[$key]" ]]; then | ||
| unset OPTS[$key] | ||
| unset ARGS[$key] | ||
| fi | ||
| done | ||
| compl="${{OPTS[@]}}" | ||
| COMPREPLY=($(compgen -W "${{compl}}" -- "${{cur}}")) | ||
| return 0 | ||
| }} | ||
|
|
||
| complete -F _{scriptname} {scriptname} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| #compdef _{scriptname} {scriptname} | ||
|
|
||
| _{scriptname}_commands(){{ | ||
| #Script used only if subcommand | ||
| local -a _{scriptname}_cmds | ||
|
|
||
| # Add subcommands list | ||
| _{scriptname}_cmds=( | ||
| {commands_list} | ||
| ) | ||
|
|
||
| if (( CURRENT == 1 )); then | ||
| _describe -t commands '{scriptname} command' _{scriptname}_cmds || compadd "$@" | ||
| else | ||
| local curcontext="$curcontext" | ||
| #Check if subcommand and redefine completion | ||
| case "$words[1]" in | ||
| {commands_opts} | ||
| esac | ||
| fi | ||
| }} | ||
|
|
||
| _{scriptname}(){{ | ||
| local curcontext="$curcontext" state line | ||
| _arguments -s \ | ||
| {opts} | ||
| }} |