From 0bd6b99b9fb677b036e4847fb923377c414d1d7f Mon Sep 17 00:00:00 2001 From: Ollie Leahy Date: Wed, 20 Aug 2014 17:31:36 +0000 Subject: [PATCH] Allow backup-to-swift to take swift URL from service catalogue Since the swift URL is usually in the service catalogue, there is no need to configure it explicitly. It can still be set explicitly where manual override is desired. Change-Id: Ia6c08289b532faed3f6e718d4bbcc1f91978db21 --- cinder/backup/drivers/swift.py | 38 +++++++++++++++++++++++++++---- cinder/context.py | 3 ++- cinder/tests/test_backup_swift.py | 36 +++++++++++++++++++++++++++++ cinder/tests/test_context.py | 11 +++++++-- etc/cinder/cinder.conf.sample | 8 ++++++- 5 files changed, 87 insertions(+), 9 deletions(-) diff --git a/cinder/backup/drivers/swift.py b/cinder/backup/drivers/swift.py index 21c35b96a..1c1035ef2 100644 --- a/cinder/backup/drivers/swift.py +++ b/cinder/backup/drivers/swift.py @@ -17,8 +17,9 @@ **Related Flags** -:backup_swift_url: The URL of the Swift endpoint (default: - localhost:8080). +:backup_swift_url: The URL of the Swift endpoint (default: None, use catalog). +:swift_catalog_info: Info to match when looking for swift 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 @@ -53,8 +54,14 @@ LOG = logging.getLogger(__name__) swiftbackup_service_opts = [ cfg.StrOpt('backup_swift_url', - default='http://localhost:8080/v1/AUTH_', + default=None, help='The URL of the Swift 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('backup_swift_auth', default='per_user', help='Swift authentication mechanism'), @@ -117,8 +124,29 @@ class SwiftBackupDriver(BackupDriver): def __init__(self, context, db_driver=None): super(SwiftBackupDriver, self).__init__(context, db_driver) - self.swift_url = '%s%s' % (CONF.backup_swift_url, - self.context.project_id) + if CONF.backup_swift_url is None: + self.swift_url = None + info = CONF.swift_catalog_info + try: + service_type, service_name, endpoint_type = info.split(':') + except ValueError: + raise exception.BackupDriverException(_( + "Failed to parse the configuration option " + "'swift_catalog_info', must be in the form " + "::")) + for entry in context.service_catalog: + if entry.get('type') == service_type: + self.swift_url = entry.get( + 'endpoints')[0].get(endpoint_type) + 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'.")) + LOG.debug("Using swift URL %s", self.swift_url) self.az = CONF.storage_availability_zone self.data_block_size_bytes = CONF.backup_swift_object_size self.swift_attempts = CONF.backup_swift_retry_attempts diff --git a/cinder/context.py b/cinder/context.py index cfb6dd8ab..5a826891f 100644 --- a/cinder/context.py +++ b/cinder/context.py @@ -91,7 +91,8 @@ class RequestContext(object): if service_catalog: # Only include required parts of service_catalog self.service_catalog = [s for s in service_catalog - if s.get('type') in ('compute',)] + if s.get('type') in ('compute', + 'object-store')] else: # if list is empty or none self.service_catalog = [] diff --git a/cinder/tests/test_backup_swift.py b/cinder/tests/test_backup_swift.py index 4a0834a7d..87d1e018c 100644 --- a/cinder/tests/test_backup_swift.py +++ b/cinder/tests/test_backup_swift.py @@ -23,6 +23,7 @@ import os import tempfile import zlib +from oslo.config import cfg from swiftclient import client as swift from cinder.backup.drivers.swift import SwiftBackupDriver @@ -37,6 +38,8 @@ from cinder.tests.backup.fake_swift_client import FakeSwiftClient LOG = logging.getLogger(__name__) +CONF = cfg.CONF + def fake_md5(arg): class result(object): @@ -65,7 +68,11 @@ 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'}]}] self.ctxt = context.get_admin_context() + self.ctxt.service_catalog = service_catalog self.stubs.Set(swift, 'Connection', FakeSwiftClient.Connection) self.stubs.Set(hashlib, 'md5', fake_md5) @@ -76,6 +83,35 @@ class BackupSwiftTestCase(test.TestCase): for i in xrange(0, 128): self.volume_file.write(os.urandom(1024)) + def test_backup_swift_url(self): + self.ctxt.service_catalog = [{u'type': u'object-store', + u'name': u'swift', + u'endpoints': [{ + u'adminURL': u'http://example.com'}] + }] + self.assertRaises(exception.BackupDriverException, + SwiftBackupDriver, + self.ctxt) + + def test_backup_swift_url_conf(self): + self.ctxt.service_catalog = [{u'type': u'object-store', + u'name': u'swift', + u'endpoints': [{ + u'adminURL': u'http://example.com'}] + }] + self.ctxt.project_id = "12345678" + CONF.set_override("backup_swift_url", "http://public.example.com/") + backup = SwiftBackupDriver(self.ctxt) + self.assertEqual("%s%s" % (CONF.backup_swift_url, + self.ctxt.project_id), + backup.swift_url) + + def test_backup_swift_info(self): + CONF.set_override("swift_catalog_info", "dummy") + self.assertRaises(exception.BackupDriverException, + SwiftBackupDriver, + self.ctxt) + def test_backup_uncompressed(self): self._create_backup_db_entry() self.flags(backup_compression_algorithm='none') diff --git a/cinder/tests/test_context.py b/cinder/tests/test_context.py index c32fd3ebe..bcb25859b 100644 --- a/cinder/tests/test_context.py +++ b/cinder/tests/test_context.py @@ -54,7 +54,7 @@ class ContextTestCase(test.TestCase): 'read_deleted', True) - def test_service_catalog_nova_only(self): + def test_service_catalog_nova_and_swift(self): service_catalog = [ {u'type': u'compute', u'name': u'nova'}, {u'type': u's3', u'name': u's3'}, @@ -67,9 +67,16 @@ class ContextTestCase(test.TestCase): {u'type': u'co', u'name': u'S_partofcompute'}] compute_catalog = [{u'type': u'compute', u'name': u'nova'}] + object_catalog = [{u'name': u'swift', u'type': u'object-store'}] ctxt = context.RequestContext('111', '222', service_catalog=service_catalog) - self.assertEqual(ctxt.service_catalog, compute_catalog) + self.assertEqual(len(ctxt.service_catalog), 2) + return_compute = [v for v in ctxt.service_catalog if + v['type'] == u'compute'] + return_object = [v for v in ctxt.service_catalog if + v['type'] == u'object-store'] + self.assertEqual(return_compute, compute_catalog) + self.assertEqual(return_object, object_catalog) def test_user_identity(self): ctx = context.RequestContext("user", "tenant", diff --git a/etc/cinder/cinder.conf.sample b/etc/cinder/cinder.conf.sample index 7cc9b4168..2cffc6598 100644 --- a/etc/cinder/cinder.conf.sample +++ b/etc/cinder/cinder.conf.sample @@ -404,7 +404,13 @@ # # The URL of the Swift endpoint (string value) -#backup_swift_url=http://localhost:8080/v1/AUTH_ +#backup_swift_url= + +# 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 (string value) +#swift_catalog_info=object-store:swift:publicURL # Swift authentication mechanism (string value) #backup_swift_auth=per_user -- 2.45.2