From ef2d45aec71349eedac946f42fa4f6a6d030a3bc Mon Sep 17 00:00:00 2001 From: Nathaniel Potter Date: Mon, 28 Sep 2015 17:18:35 -0500 Subject: [PATCH] Add backup_swift_auth_url to swift backup driver Currently the config parameter backup_swift_url expects a keystone endpoint url in the swift backup driver if you're using single_user mode, but if you're in per_user mode it expects a swift endpoint url. This patch adds a parameter called backup_swift_auth_url to differentiate the two. Unit tests are also provided for testing backup_swift_auth_url. DocImpact: The config options "backup_swift_auth_url" and "keystone_catalog_info" will need to be added to the Cinder docs. Change-Id: Iee466fe1404eef9402a19d529dba19c7d5a4ef2b Closes-Bug: #1449972 --- cinder/backup/drivers/swift.py | 50 ++++++++++++++++++++-- cinder/tests/unit/test_backup_swift.py | 58 +++++++++++++++++++++++--- 2 files changed, 100 insertions(+), 8 deletions(-) diff --git a/cinder/backup/drivers/swift.py b/cinder/backup/drivers/swift.py index 8570ad2c5..42ba716b3 100644 --- a/cinder/backup/drivers/swift.py +++ b/cinder/backup/drivers/swift.py @@ -22,8 +22,12 @@ **Related Flags** :backup_swift_url: The URL of the Swift endpoint (default: None, use catalog). +:backup_swift_auth_url: The URL of the Keystone endpoint for authentication + (default: None, use catalog). :swift_catalog_info: Info to match when looking for swift in the service ' catalog. +:keystone_catalog_info: Info to match when looking for keystone in the service + catalog. :backup_swift_object_size: The size in bytes of the Swift objects used for volume backups (default: 52428800). :backup_swift_retry_attempts: The number of retries to make for Swift @@ -57,12 +61,21 @@ swiftbackup_service_opts = [ cfg.StrOpt('backup_swift_url', default=None, help='The URL of the Swift endpoint'), + cfg.StrOpt('backup_swift_auth_url', + default=None, + help='The URL of the Keystone endpoint'), cfg.StrOpt('swift_catalog_info', default='object-store:swift:publicURL', help='Info to match when looking for swift in the service ' 'catalog. Format is: separated values of the form: ' ':: - ' 'Only used if backup_swift_url is unset'), + cfg.StrOpt('keystone_catalog_info', + default='identity:Identity Service:publicURL', + help='Info to match when looking for keystone in the service ' + 'catalog. Format is: separated values of the form: ' + ':: - ' + 'Only used if backup_swift_auth_url is unset'), cfg.StrOpt('backup_swift_auth', default='per_user', help='Swift authentication mechanism'), @@ -138,17 +151,48 @@ class SwiftBackupDriver(chunkeddriver.ChunkedBackupDriver): "::")) for entry in context.service_catalog: if entry.get('type') == service_type: + # It is assumed that service_types are unique within + # the service catalog, so once the correct one is found + # it is safe to break out of the loop self.swift_url = entry.get( 'endpoints')[0].get(endpoint_type) + break else: self.swift_url = '%s%s' % (CONF.backup_swift_url, context.project_id) if self.swift_url is None: raise exception.BackupDriverException(_( "Could not determine which Swift endpoint to use. This can " - " either be set in the service catalog or with the " - " cinder.conf config option 'backup_swift_url'.")) + "either be set in the service catalog or with the " + "cinder.conf config option 'backup_swift_url'.")) + if CONF.backup_swift_auth_url is None: + self.auth_url = None + info = CONF.keystone_catalog_info + try: + service_type, service_name, endpoint_type = info.split(':') + except ValueError: + raise exception.BackupDriverException(_( + "Failed to parse the configuration option " + "'keystone_catalog_info', must be in the form " + "::")) + for entry in context.service_catalog: + if entry.get('type') == service_type: + # It is assumed that service_types are unique within + # the service catalog, so once the correct one is found + # it is safe to break out of the loop + self.auth_url = entry.get( + 'endpoints')[0].get(endpoint_type) + break + else: + self.auth_url = '%s%s' % (CONF.backup_swift_auth_url, + context.project_id) + if self.auth_url is None: + raise exception.BackupDriverException(_( + "Could not determine which Keystone endpoint to use. This can " + "either be set in the service catalog or with the " + "cinder.conf config option 'backup_swift_auth_url'.")) LOG.debug("Using swift URL %s", self.swift_url) + LOG.debug("Using auth URL %s", self.auth_url) self.swift_attempts = CONF.backup_swift_retry_attempts self.swift_backoff = CONF.backup_swift_retry_backoff LOG.debug('Connect to %s in "%s" mode', CONF.backup_swift_url, @@ -160,7 +204,7 @@ class SwiftBackupDriver(chunkeddriver.ChunkedBackupDriver): {'param': 'backup_swift_user'}) raise exception.ParameterNotFound(param='backup_swift_user') self.conn = swift.Connection( - authurl=CONF.backup_swift_url, + authurl=self.auth_url, auth_version=CONF.backup_swift_auth_version, tenant_name=CONF.backup_swift_tenant, user=CONF.backup_swift_user, diff --git a/cinder/tests/unit/test_backup_swift.py b/cinder/tests/unit/test_backup_swift.py index c5d639923..c1915b24f 100644 --- a/cinder/tests/unit/test_backup_swift.py +++ b/cinder/tests/unit/test_backup_swift.py @@ -78,6 +78,9 @@ class BackupSwiftTestCase(test.TestCase): def setUp(self): super(BackupSwiftTestCase, self).setUp() service_catalog = [{u'type': u'object-store', u'name': u'swift', + u'endpoints': [{ + u'publicURL': u'http://example.com'}]}, + {u'type': u'identity', u'name': u'keystone', u'endpoints': [{ u'publicURL': u'http://example.com'}]}] self.ctxt = context.get_admin_context() @@ -100,8 +103,28 @@ class BackupSwiftTestCase(test.TestCase): self.ctxt.service_catalog = [{u'type': u'object-store', u'name': u'swift', u'endpoints': [{ - u'adminURL': u'http://example.com'}] - }] + u'adminURL': + u'http://example.com'}]}, + {u'type': u'identity', + u'name': u'keystone', + u'endpoints': [{ + u'publicURL': + u'http://example.com'}]}] + self.assertRaises(exception.BackupDriverException, + swift_dr.SwiftBackupDriver, + self.ctxt) + + def test_backup_swift_auth_url(self): + self.ctxt.service_catalog = [{u'type': u'object-store', + u'name': u'swift', + u'endpoints': [{ + u'publicURL': + u'http://example.com'}]}, + {u'type': u'identity', + u'name': u'keystone', + u'endpoints': [{ + u'adminURL': + u'http://example.com'}]}] self.assertRaises(exception.BackupDriverException, swift_dr.SwiftBackupDriver, self.ctxt) @@ -110,15 +133,40 @@ class BackupSwiftTestCase(test.TestCase): self.ctxt.service_catalog = [{u'type': u'object-store', u'name': u'swift', u'endpoints': [{ - u'adminURL': u'http://example.com'}] - }] + u'adminURL': + u'http://example.com'}]}, + {u'type': u'identity', + u'name': u'keystone', + u'endpoints': [{ + u'publicURL': + u'http://example.com'}]}] self.ctxt.project_id = "12345678" - self.override_config("backup_swift_url", "http://public.example.com/") + self.override_config("backup_swift_url", + "http://public.example.com/") backup = swift_dr.SwiftBackupDriver(self.ctxt) self.assertEqual("%s%s" % (CONF.backup_swift_url, self.ctxt.project_id), backup.swift_url) + def test_backup_swift_auth_url_conf(self): + self.ctxt.service_catalog = [{u'type': u'object-store', + u'name': u'swift', + u'endpoints': [{ + u'publicURL': + u'http://example.com'}]}, + {u'type': u'identity', + u'name': u'keystone', + u'endpoints': [{ + u'adminURL': + u'http://example.com'}]}] + self.ctxt.project_id = "12345678" + self.override_config("backup_swift_auth_url", + "http://public.example.com/") + backup = swift_dr.SwiftBackupDriver(self.ctxt) + self.assertEqual("%s%s" % (CONF.backup_swift_auth_url, + self.ctxt.project_id), + backup.auth_url) + def test_backup_swift_info(self): self.override_config("swift_catalog_info", "dummy") self.assertRaises(exception.BackupDriverException, -- 2.45.2