]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Update config format for replication_devices
authorJohn Griffith <john.griffith8@gmail.com>
Fri, 9 Oct 2015 23:31:15 +0000 (17:31 -0600)
committerJohn Griffith <john.griffith8@gmail.com>
Tue, 13 Oct 2015 15:00:41 +0000 (09:00 -0600)
The first pass at setting up config entries for
replication targets was a hacky custom string parser
with its own unique syntax.

A better option is to use oslo.cfg's MultiOpt in conjunction
with Dict types so we can eliminate quite a bit of custom
parsing and most importantly use a standard syntax for conf
entries to make things easy for admins and reduce the
probability of syntax errors and mistakes in config setttings.

Change-Id: Ie300c1f1db548d258906eebbcea8265583086468
Closes-Bug: #1504696

cinder/volume/driver.py
doc/source/devref/replication.rst

index 2eba2cca3014924a41c3630b57e51d4e5126a898..b9faae9d19bd8130a15cb4a91264df5454677961 100644 (file)
@@ -20,6 +20,7 @@ import time
 
 from oslo_concurrency import processutils
 from oslo_config import cfg
+from oslo_config import types
 from oslo_log import log as logging
 from oslo_utils import excutils
 import six
@@ -217,20 +218,17 @@ volume_opts = [
                 help='List of options that control which trace info '
                      'is written to the DEBUG log level to assist '
                      'developers. Valid values are method and api.'),
-    cfg.BoolOpt('managed_replication_target',
-                default=True,
-                help='There are two types of target configurations '
-                     'managed (replicate to another configured backend) '
-                     'or unmanaged (replicate to a device not managed '
-                     'by Cinder).'),
-    cfg.ListOpt('replication_devices',
-                default=None,
-                help="List of k/v pairs representing a replication target "
-                     "for this backend device.  For unmanaged the format "
-                     "is: {'key-1'='val1' 'key-2'='val2'...},{...} "
-                     "and for managed devices its simply a list of valid "
-                     "configured backend_names that the driver supports "
-                     "replicating to: backend-a,bakcend-b..."),
+    cfg.MultiOpt('replication_device',
+                 item_type=types.Dict(),
+                 default=None,
+                 help="Multi opt of dictionaries to represent a replication "
+                      "target device.  This option may be specified multiple "
+                      "times in a single config section to specify multiple "
+                      "replication target devices.  Each entry takes the "
+                      "standard dict config form: replication_device = "
+                      "device_target_id:<required>,"
+                      "managed_backend_name:<host@backend_name>,"
+                      "key1:value1,key2:value2..."),
     cfg.BoolOpt('image_upload_use_cinder_backend',
                 default=False,
                 help='If set to True, upload-to-image in raw format will '
index efccd15714b314bc14c3b3f180ba2fe6597f9ec0..46a7595995a2d073011903338f61f247e6c85dc3 100644 (file)
@@ -16,26 +16,27 @@ Config file examples
 --------------------
 
 The cinder.conf file is used to specify replication target
-devices for a specific driver.  There are two types of target
-devices that can be configured:
+devices for a specific driver.  Replication targets may
+be specified as external (unmanaged) or internally
+Cinder managed backend devices.
 
-   1. Cinder Managed (represented by the volume-backend name)
-   2. External devices (require vendor specific data to configure)
+**replication_device**
 
-NOTE that it is expected to be an error to have both managed and unmanaged replication
-config variables set for a single driver.
+Is a multi-dict opt, that should be specified
+for each replication target device the admin would
+like to configure.
 
-Cinder managed target device
------------------------------
+*NOTE:*
 
-In the case of a Cinder managed target device, we simply
-use another Cinder configured backend as the replication
-target.
+There are two standardized keys in the config
+entry, all others are vendor-unique:
 
-For example if we have two backend devices foo and biz that
-can replicate to each other, we can set up backend biz as
-a replication target for device foo using the following
-config entries::
+* device_target_id:<vendor-identifier-for-rep-target>
+* managed_backend_name:<cinder-backend-host-entry>,"
+
+
+An example config entry for a managed replication device
+would look like this::
 
     .....
     [driver-biz]
@@ -45,42 +46,98 @@ config entries::
     [driver-foo]
     volume_driver=xxxx
     volume_backend_name=foo
-    managed_replication_target=True
-    replication_devices=volume_backend_name-1,volume_backend_name-2....
+    replication_device = device_target_id:vendor-id-info,managed_backend_name:biz,unique_key:val....
+
+The use of multiopt will result in self.configuration.get('replication_device')
+returning a list of properly formed python dictionaries that can
+be easily consumed::
+
+    [{device_target_id: blahblah, managed_backend_name: biz, unique_key: val1}]
 
-Notice that the only change from the usual driver configuration
-section here is the addition of the replication_devices option.
 
+In the case of multiple replication target devices::
+
+    .....
+    [driver-biz]
+    volume_driver=xxxx
+    volume_backend_name=biz
+
+    [driver-baz]
+    volume_driver=xxxx
+    volume_backend_name=baz
+
+    [driver-foo]
+    volume_driver=xxxx
+    volume_backend_name=foo
+    managed_replication_target=True
+    replication_device = device_target_id:vendor-id-info,managed_backend_name:biz,unique_key:val....
+    replication_device = device_target_id:vendor-id-info,managed_backend_name:baz,unique_key:val....
 
-Unmanaged target device
-------------------------
+In this example the result is self.configuration.get('replication_device')
+returning a list of properly formed python dictionaries::
 
-In some cases the replication target device may not be a
-configured Cinder backend.  In this case it's the configured
-drivers responsibility to route commands to the active device
-and to update provider info to ensure the proper iSCSI targets
-are being used.
+    [{device_target_id: blahblah, managed_backend_name: biz, unique_key: val1},
+     {device_target_id: moreblah, managed_backend_name: baz, unique_key: val1}]
 
-This type of config changes only slightly, and instead of using
-a backend_name, it takes the vendor unique config options::
+
+In the case of unmanaged replication target devices::
 
     .....
+    [driver-biz]
+    volume_driver=xxxx
+    volume_backend_name=biz
+
+    [driver-baz]
+    volume_driver=xxxx
+    volume_backend_name=baz
+
     [driver-foo]
     volume_driver=xxxx
     volume_backend_name=foo
-    managed_replication_target=False
-    replication_devices={'remote_device_id'='vendor-id-of-remote-backend',
-                         'key1'='val1' 'key2'='val2' ...},
-                        {'remote_device_id'='vendor-id-of-remote-backend',
-                         'key7'='val7'....},...
+    replication_device = device_target_id:vendor-id-info,managed_backend_name:None,unique_key:val....
+    replication_device = device_target_id:vendor-id-info,managed_backend_name:None,unique_key:val....
+
+The managed_backend_name entry may also be omitted altogether in the case of unmanaged targets.
+
+In this example the result is self.configuration.get('replication_device) with the list::
+
+    [{device_target_id: blahblah, managed_backend_name: None, unique_key: val1},
+     {device_target_id: moreblah, managed_backend_name: None, unique_key: val1}]
+
+
+
+Special note about Managed target device
+----------------------------------------
+Remember that in the case where another Cinder backend is
+used that it's likely you'll still need some special data
+to instruct the primary driver how to communicate with the
+secondary.  In this case we use the same structure and entries
+but we set the key **managed_backend_name** to a valid
+Cinder backend name.
+
+**WARNING**
+The building of the host string for a driver is not always
+very straight forward.  The enabled_backends names which
+correspond to the driver-section are what actually get used
+to form the host string for the volume service.
+
+Also, take care that your driver knows how to parse out the
+host correctly, although the secondary backend may be managed
+it may not be on the same host, it may have a pool specification
+etc.  In the example above we can assume the same host, in other
+cases we would need to use the form::
+
+    <host>@<driver-section-name>
 
-Note the key/value entries can be whatever the device requires, we treat the actual
-variable in the config parser as a comma delimited list, the {} and = notations are
-convenient/common parser delimeters, and the K/V entries are space seperated.
+and for some vendors we may require pool specification::
 
-We provide a literal evaluator to convert these entries into a proper dict, thus
-format is extremely important here.
+    <host>@<driver-section-name>#<pool-name>
 
+Regardless, it's best that you actually check the services entry
+and verify that you've set this correctly, and likely to avoid
+problems your vendor documentation for customers to configure this
+should recommend configuring backends, then verifying settings
+from cinder services list.
 
 Volume Types / Extra Specs
 ---------------------------
@@ -101,7 +158,7 @@ If you needed to provide a specific backend device (multiple backends supporting
 
 Additionally you could provide additional details using scoped keys::
     {replication: enabled, volume_backend_name: foo,
-     replication:replication_type: async}
+     replication: replication_type: async}
 
 Again, it's up to the driver to parse the volume type info on create and set things up
 as requested.  While the scoping key can be anything, it's strongly recommended that all
@@ -153,7 +210,7 @@ act as a toggle, allowing to switch back and forth betweeen primary and secondar
 **list_replication_targets**
 
 Used by the admin to query a volume for a list of configured replication targets
-The expected return for this call is expeceted to mimic the form used in the config file.
+The expected return for this call is expected to mimic the form used in the config file.
 
 For a volume replicating to managed replication targets::