diff --git a/doc/source/faq.rst b/doc/source/faq.rst index 3325e40e..2171d13a 100644 --- a/doc/source/faq.rst +++ b/doc/source/faq.rst @@ -28,3 +28,71 @@ projects. This debate will probably never completely go away, though. See `this latest discussion in August, 2014 `__ + +Why are configuration options not part of a library's API? +========================================================== + +Configuration options are a way for deployers to change the behavior +of OpenStack. Applications are not supposed to be aware of the +configuration options defined and used within libraries, because the +library API is supposed to work transparently no matter which backend +is configured. + +Configuration options in libraries can be renamed, moved, and +deprecated just like configuration options in applications. However, +if applications are allowed to read or write the configuration options +directly, treating them as an API, the option cannot be renamed +without breaking the application. Instead, libraries should provide a +programmatic API (usually a :func:`set_defaults` function) for setting +the defaults for configuration options. For example, this function +from ``oslo.log`` lets the caller change the format string and default +logging levels: + +:: + + def set_defaults(logging_context_format_string=None, + default_log_levels=None): + """Set default values for the configuration options used by oslo.log.""" + # Just in case the caller is not setting the + # default_log_level. This is insurance because + # we introduced the default_log_level parameter + # later in a backwards in-compatible change + if default_log_levels is not None: + cfg.set_defaults( + _options.log_opts, + default_log_levels=default_log_levels) + if logging_context_format_string is not None: + cfg.set_defaults( + _options.log_opts, + logging_context_format_string=logging_context_format_string) + +If the name of either option changes, the API of :func:`set_defaults` +can be updated to allow both names, and warn if the old one is +provided. Using a supported API like this is better than having an +application call :func:`set_default` on the configuration object +directly, such as: + +:: + + cfg.CONF.set_default('default_log_levels', default_log_levels) + +This form will trigger an error if the logging options are moved out +of the default option group into their own section of the +configuration file. It will also fail if the ``default_log_levels`` +option is not yet registered, or if it is renamed. All of those cases +can be protected against with a :func:`set_defaults` function in the +library that owns the options. + +Similarly, code that does not *own* the configuration option +definition should not read the option value. An application should +never, for example, do something like: + +:: + + log_file = cfg.CONF.log_file + +The type, name, and existence of the ``log_file`` configuration option +is subject to change. ``oslo.config`` makes it easy to communicate +that change to a deployer in a way that allows their old configuration +files to continue to work. It has no mechanism for doing that in +application code, however.