]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
encryption_api_url requires a version
authorOllie Leahy <oliver.leahy@hp.com>
Thu, 1 Oct 2015 17:21:52 +0000 (18:21 +0100)
committerJohn Griffith <john.griffith8@gmail.com>
Tue, 13 Oct 2015 18:26:05 +0000 (18:26 +0000)
If the value configured for encryption_api_url does not include the
barbican API version, then some calls from cinder will fail. This can
mean that encrypted volumes cannot be deleted. To prevent this happening
raise an exception if the configured value for encryption_api_url does not
include the barbican version.

Change-Id: I1a4c9b9e93d7d189a3cdf1469e8bb87817473da5
Closes-Bug: #1501780

cinder/keymgr/barbican.py
cinder/tests/unit/keymgr/test_barbican.py

index 3af2d6f469ae48987aec7790a9136bb009bbf8bf..10373c2af782de9fedb370f0673e107dd92a5931 100644 (file)
@@ -20,6 +20,7 @@ Key manager implementation for Barbican
 import array
 import base64
 import binascii
+import re
 
 from barbicanclient import client as barbican_client
 from keystoneclient.auth import identity
@@ -37,6 +38,8 @@ CONF = cfg.CONF
 CONF.import_opt('encryption_auth_url', 'cinder.keymgr.key_mgr', group='keymgr')
 CONF.import_opt('encryption_api_url', 'cinder.keymgr.key_mgr', group='keymgr')
 LOG = logging.getLogger(__name__)
+URL_PATTERN = re.compile(
+    "(?P<url_base>http[s]?://[^/]*)[/]?(?P<url_version>(v[0-9.]+)?).*")
 
 
 class BarbicanKeyManager(key_mgr.KeyManager):
@@ -44,10 +47,33 @@ class BarbicanKeyManager(key_mgr.KeyManager):
 
     def __init__(self):
         self._base_url = CONF.keymgr.encryption_api_url
-        # the barbican endpoint can't have the '/v1' on the end
-        self._barbican_endpoint = self._base_url.rpartition('/')[0]
+        self._parse_barbican_api_url()
         self._barbican_client = None
 
+    def _parse_barbican_api_url(self):
+        """Setup member variables to reference the Barbican URL.
+
+        The key manipulation functions in this module need to use the
+        barbican URL with the version appended. But the barbicanclient
+        Client() class needs the URL without the version appended.
+        So set up a member variables here for each case.
+        """
+        m = URL_PATTERN.search(self._base_url)
+        if m is None:
+            raise exception.KeyManagerError(_(
+                "Invalid url: must be in the form "
+                "'http[s]://<ipaddr>|<fqdn>[:port]/<version>', "
+                "url specified is: %s"), self._base_url)
+        url_info = dict(m.groupdict())
+        if 'url_version' not in url_info or url_info['url_version'] == "":
+            raise exception.KeyManagerError(_(
+                "Invalid barbican api url: version is required, "
+                "e.g. 'http[s]://<ipaddr>|<fqdn>[:port]/<version>' "
+                "url specified is: %s") % self._base_url)
+        # We will also need the barbican API URL without the '/v1'.
+        # So save that now.
+        self._barbican_endpoint = url_info['url_base']
+
     def _get_barbican_client(self, ctxt):
         """Creates a client to connect to the Barbican service.
 
index a15b312e41736e25b19f742fea5bbd3df79f1648..44d20fa9421b54ac5482a60451b6e639a06742bc 100644 (file)
@@ -57,6 +57,7 @@ class BarbicanKeyManagerTestCase(test_key_mgr.KeyManagerTestCase):
         self.pre_hex = "AIDxQp2++uAbKaTVDMXFYIu8PIugJGqkK0JLqkU0rhY="
         self.hex = ("0080f1429dbefae01b29a4d50cc5c5608bbc3c8ba0246aa42b424baa4"
                     "534ae16")
+        self.original_api_url = CONF.keymgr.encryption_api_url
         self.addCleanup(self._restore)
 
     def _restore(self):
@@ -64,6 +65,8 @@ class BarbicanKeyManagerTestCase(test_key_mgr.KeyManagerTestCase):
             keymgr_key.SymmetricKey = self.original_key
         if hasattr(self, 'original_base64'):
             base64.b64encode = self.original_base64
+        if hasattr(self, 'original_api_url'):
+            CONF.keymgr.encryption_api_url = self.original_api_url
 
     def _build_mock_barbican(self):
         self.mock_barbican = mock.MagicMock(name='mock_barbican')
@@ -271,3 +274,17 @@ class BarbicanKeyManagerTestCase(test_key_mgr.KeyManagerTestCase):
         mock_session.assert_called_once_with(auth=mock_auth)
         mock_client.assert_called_once_with(session=mock_sess,
                                             endpoint=mock_endpoint)
+
+    def test_parse_barbican_api_url(self):
+        # assert that the correct format is handled correctly
+        CONF.keymgr.encryption_api_url = "http://host:port/v1/"
+        dummy = barbican.BarbicanKeyManager()
+        self.assertEqual(dummy._barbican_endpoint, "http://host:port")
+
+        # assert that invalid api url formats will raise an exception
+        CONF.keymgr.encryption_api_url = "http://host:port/"
+        self.assertRaises(exception.KeyManagerError,
+                          barbican.BarbicanKeyManager)
+        CONF.keymgr.encryption_api_url = "http://host:port/secrets"
+        self.assertRaises(exception.KeyManagerError,
+                          barbican.BarbicanKeyManager)