summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexis Lee <lxsli@hpe.com>2016-07-07 11:31:44 +0100
committerAlexis Lee <lxsli@hpe.com>2016-07-07 11:37:30 +0100
commitd174a4e3c01adde78c6999daf62d5c3c246c885b (patch)
tree95c5c486d32ea2f60195d32137c1f90a13d05537
parent272a701f1f4dd1b4227e19670ab088ef9ab20fac (diff)
downloadoslo-config-d174a4e3c01adde78c6999daf62d5c3c246c885b.tar.gz
Enabling your project for mutable-config
Change-Id: I1c71a2d571bba619434360a4319c7305c5880642
-rw-r--r--doc/source/index.rst1
-rw-r--r--doc/source/mutable.rst121
2 files changed, 122 insertions, 0 deletions
diff --git a/doc/source/index.rst b/doc/source/index.rst
index cb883c9..af4ba20 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -21,6 +21,7 @@ Contents
exceptions
namespaces
styleguide
+ mutable
generator
builtins
sphinxext
diff --git a/doc/source/mutable.rst b/doc/source/mutable.rst
new file mode 100644
index 0000000..ba89a16
--- /dev/null
+++ b/doc/source/mutable.rst
@@ -0,0 +1,121 @@
+Enabling your project for mutable config
+========================================
+
+As of OpenStack Newton, config options can be marked as 'mutable'. This means
+they can be reloaded (usually via SIGHUP) at runtime, without a service
+restart. However, each project has to be enabled before this will work and some
+care needs to be taken over how each option is used before it can safely be
+marked mutable.
+
+.. contents:: Table of Contents
+ :local:
+
+
+Calling mutate_config_files
+---------------------------
+
+Config mutation is triggered by ``ConfigOpts#mutate_config_files`` being
+called. Services launched with oslo.service get a signal handler on SIGHUP but
+by default that calls the older ``ConfigOpts#reload_config_files`` method. To
+get the new behaviour, we have to pass ``restart_method='mutate'``. For
+example::
+
+ service.ProcessLauncher(CONF, restart_method='mutate')
+
+An example patch is here: https://review.openstack.org/#/c/280851
+
+Some projects may call ``reload_config_files`` directly, in this case just
+change that call to ``mutate_config_files``. If there is no signal handler or
+you want to trigger reload by a different method, maybe via a web UI or
+watching a file, just ensure your trigger calls ``mutate_config_files``.
+
+
+
+Making options mutable-safe
+---------------------------
+
+When options are mutated, they change in the ConfigOpts object but this will
+not necessarily affect your service immediately. There are three main cases to
+deal with:
+
+* The option is checked every time
+* The option is cached on the stack
+* The option affects state
+
+
+The option is checked every time
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This pattern is already safe. Example code::
+
+ while True:
+ progress_timeout = CONF.libvirt.live_migration_progress_timeout
+ completion_timeout = int(
+ CONF.libvirt.live_migration_completion_timeout * data_gb)
+ if libvirt_migrate.should_abort(instance, now, progress_time,
+ progress_timeout, completion_timeout):
+ guest.abort_job()
+
+
+The option is cached on the stack
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Just putting the option value in a local variable is enough to cache it. This
+is tempting to do with loops. Example code::
+
+ progress_timeout = CONF.libvirt.live_migration_progress_timeout
+ completion_timeout = int(
+ CONF.libvirt.live_migration_completion_timeout * data_gb)
+ while True:
+ if libvirt_migrate.should_abort(instance, now, progress_time,
+ progress_timeout, completion_timeout):
+ guest.abort_job()
+
+The goal is to check the option exactly once every time it could have an
+effect. Usually this is as simple as checking it every time, for example by
+moving the locals into the loop. Example patch:
+https://review.openstack.org/#/c/319203
+
+Sometimes multiple computations have to be performed using the option values
+and it's important that the result is consistent. In this case, it's necessary
+to cache the option values in locals. Example patch:
+https://review.openstack.org/#/c/319254
+
+
+The option affects state
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+An option value can also be cached, after a fashion, by state - either system
+or external. For example, the 'debug' option of oslo.log is used to set the
+default log level on startup. The option is not normally checked again, so if
+it is mutated, the system state will not reflect the new value of the option.
+In this case we have to use a *mutate hook*::
+
+ def _mutate_hook(conf, fresh):
+ if (None, 'debug') in fresh:
+ if conf.debug:
+ log_root.setLevel(logging.DEBUG)
+
+ def register_options(conf):
+ ... snip ...
+ conf.register_mutate_hook(_mutate_hook)
+
+Mutate hook functions will be passed two positional parameters, 'conf' and
+'fresh'. 'conf' is a reference to the updated ConfigOpts object. 'fresh' looks
+like::
+
+ { (group, option_name): (old_value, new_value), ... }
+
+for example::
+
+ { (None, 'debug'): (False, True),
+ ('libvirt', 'live_migration_progress_timeout'): (50, 75) }
+
+Hooks may be called in any order.
+
+Each project should register one hook, which does whatever is necessary to
+apply all the new option values. This hook function could grow very large. For
+good style, modularise the hook using secondary functions rather than accreting
+a monolith or registering multiple hooks.
+
+Example patch: https://review.openstack.org/#/c/254821/