Use url_for from keystoneclient in swift store

glance doesn't pass ServiceCatalog to glance_store
in user context(glance just passes a list of service endpoints).
So when  swift multi-tenant store is enabled then there is no
method url_for for context.service_catalog.
We can use ServiceCatalog from keystoneclient for these
purposes and convert this list to ServiceCatalog if url_for
method is not present.
Please also note that keystone.middleware converts
X-Service-Catalog to v2 so we can safely initialize and use
ServiceCatalogV2 in glance_store.

Closes-Bug: #1538482

Change-Id: I3c4c56e91656f09067d28923ed45595395e9880e
This commit is contained in:
kairat_kushaev 2016-01-27 13:18:27 +03:00
parent 30ae6b020c
commit 8677f92877
3 changed files with 72 additions and 81 deletions

View File

@ -19,6 +19,7 @@ import hashlib
import logging import logging
import math import math
from keystoneclient import service_catalog as keystone_sc
from oslo_config import cfg from oslo_config import cfg
from oslo_utils import encodeutils from oslo_utils import encodeutils
from oslo_utils import excutils from oslo_utils import excutils
@ -871,8 +872,8 @@ class MultiTenantStore(BaseStore):
reason=reason) reason=reason)
self.storage_url = self.conf_endpoint self.storage_url = self.conf_endpoint
if not self.storage_url: if not self.storage_url:
sc = {'serviceCatalog': context.service_catalog}
self.storage_url = context.service_catalog.url_for( self.storage_url = keystone_sc.ServiceCatalogV2(sc).url_for(
service_type=self.service_type, region_name=self.region, service_type=self.service_type, region_name=self.region,
endpoint_type=self.endpoint_type) endpoint_type=self.endpoint_type)

View File

@ -670,8 +670,21 @@ class SwiftTests(object):
self.config(swift_store_container='container') self.config(swift_store_container='container')
self.config(swift_store_create_container_on_put=True) self.config(swift_store_create_container_on_put=True)
self.config(swift_store_multiple_containers_seed=2) self.config(swift_store_multiple_containers_seed=2)
service_catalog = mock.MagicMock() service_catalog = [
service_catalog.url_for.return_value = 'https://some_endpoint' {
'endpoint_links': [],
'endpoints': [
{
'adminURL': 'https://some_admin_endpoint',
'region': 'RegionOne',
'internalURL': 'https://some_internal_endpoint',
'publicURL': 'https://some_endpoint',
},
],
'type': 'object-store',
'name': 'Object Storage Service',
}
]
ctxt = mock.MagicMock( ctxt = mock.MagicMock(
user='user', tenant='tenant', auth_token='123', user='user', tenant='tenant', auth_token='123',
service_catalog=service_catalog) service_catalog=service_catalog)
@ -1344,8 +1357,22 @@ class TestMultiTenantStoreContext(base.StoreBaseTest):
self.config(**conf) self.config(**conf)
self.store.configure() self.store.configure()
self.register_store_schemes(self.store, 'swift') self.register_store_schemes(self.store, 'swift')
self.service_catalog = mock.MagicMock() service_catalog = [
self.service_catalog.url_for.return_value = "http://127.0.0.1:0" {
'endpoint_links': [],
'endpoints': [
{
'region': 'RegionOne',
'publicURL': 'http://127.0.0.1:0',
},
],
'type': 'object-store',
'name': 'Object Storage Service',
}
]
self.ctx = mock.MagicMock(
service_catalog=service_catalog, user='tenant:user1',
tenant='tenant', auth_token='0123')
self.addCleanup(self.conf.reset) self.addCleanup(self.conf.reset)
@requests_mock.mock() @requests_mock.mock()
@ -1356,12 +1383,8 @@ class TestMultiTenantStoreContext(base.StoreBaseTest):
store.configure() store.configure()
uri = "swift+http://127.0.0.1/glance_123/123" uri = "swift+http://127.0.0.1/glance_123/123"
loc = location.get_location_from_uri(uri, conf=self.conf) loc = location.get_location_from_uri(uri, conf=self.conf)
ctx = mock.MagicMock(
service_catalog=self.service_catalog, user='tenant:user1',
tenant='tenant', auth_token='0123')
m.get("http://127.0.0.1/glance_123/123") m.get("http://127.0.0.1/glance_123/123")
store.get(loc, context=ctx) store.get(loc, context=self.ctx)
self.assertEqual(b'0123', m.last_request.headers['X-Auth-Token']) self.assertEqual(b'0123', m.last_request.headers['X-Auth-Token'])
@requests_mock.mock() @requests_mock.mock()
@ -1377,30 +1400,14 @@ class TestMultiTenantStoreContext(base.StoreBaseTest):
store.configure() store.configure()
content = b'Some data' content = b'Some data'
pseudo_file = six.BytesIO(content) pseudo_file = six.BytesIO(content)
ctx = mock.MagicMock(
service_catalog=self.service_catalog, user='tenant:user1',
tenant='tenant', auth_token='0123')
store.add('123', pseudo_file, len(content), store.add('123', pseudo_file, len(content),
context=ctx) context=self.ctx)
self.assertEqual(b'0123', self.assertEqual(b'0123',
head_req.last_request.headers['X-Auth-Token']) head_req.last_request.headers['X-Auth-Token'])
self.assertEqual(b'0123', self.assertEqual(b'0123',
put_req.last_request.headers['X-Auth-Token']) put_req.last_request.headers['X-Auth-Token'])
class FakeGetEndpoint(object):
def __init__(self, response):
self.response = response
def __call__(self, service_catalog, service_type=None,
endpoint_region=None, endpoint_type=None):
self.service_type = service_type
self.endpoint_region = endpoint_region
self.endpoint_type = endpoint_type
return self.response
class TestCreatingLocations(base.StoreBaseTest): class TestCreatingLocations(base.StoreBaseTest):
_CONF = cfg.CONF _CONF = cfg.CONF
@ -1414,6 +1421,25 @@ class TestCreatingLocations(base.StoreBaseTest):
moves.reload_module(swift) moves.reload_module(swift)
self.addCleanup(self.conf.reset) self.addCleanup(self.conf.reset)
service_catalog = [
{
'endpoint_links': [],
'endpoints': [
{
'adminURL': 'https://some_admin_endpoint',
'region': 'RegionOne',
'internalURL': 'https://some_internal_endpoint',
'publicURL': 'https://some_endpoint',
},
],
'type': 'object-store',
'name': 'Object Storage Service',
}
]
self.ctxt = mock.MagicMock(user='user', tenant='tenant',
auth_token='123',
service_catalog=service_catalog)
def test_single_tenant_location(self): def test_single_tenant_location(self):
conf = copy.deepcopy(SWIFT_CONF) conf = copy.deepcopy(SWIFT_CONF)
conf['swift_store_container'] = 'container' conf['swift_store_container'] = 'container'
@ -1450,85 +1476,48 @@ class TestCreatingLocations(base.StoreBaseTest):
def test_multi_tenant_location(self): def test_multi_tenant_location(self):
self.config(swift_store_container='container') self.config(swift_store_container='container')
service_catalog = mock.MagicMock()
service_catalog.url_for.return_value = 'https://some_endpoint'
ctxt = mock.MagicMock(
user='user', tenant='tenant', auth_token='123',
service_catalog=service_catalog)
store = swift.MultiTenantStore(self.conf) store = swift.MultiTenantStore(self.conf)
store.configure() store.configure()
location = store.create_location('image-id', context=ctxt) location = store.create_location('image-id', context=self.ctxt)
self.assertEqual(location.scheme, 'swift+https') self.assertEqual(location.scheme, 'swift+https')
self.assertEqual(location.swift_url, 'https://some_endpoint') self.assertEqual(location.swift_url, 'https://some_endpoint')
self.assertEqual(location.container, 'container_image-id') self.assertEqual(location.container, 'container_image-id')
self.assertEqual(location.obj, 'image-id') self.assertEqual(location.obj, 'image-id')
self.assertIsNone(location.user) self.assertIsNone(location.user)
self.assertIsNone(location.key) self.assertIsNone(location.key)
service_catalog.url_for.assert_called_once_with(
service_type=store.service_type,
region_name=store.region,
endpoint_type=store.endpoint_type)
def test_multi_tenant_location_http(self): def test_multi_tenant_location_http(self):
service_catalog = mock.MagicMock()
service_catalog.url_for.return_value = 'http://some_endpoint'
ctxt = mock.MagicMock(
user='user', tenant='tenant', auth_token='123',
service_catalog=service_catalog)
store = swift.MultiTenantStore(self.conf) store = swift.MultiTenantStore(self.conf)
store.configure() store.configure()
location = store.create_location('image-id', context=ctxt) self.ctxt.service_catalog[0]['endpoints'][0]['publicURL'] = \
self.assertEqual(location.scheme, 'swift+http') 'http://some_endpoint'
self.assertEqual(location.swift_url, 'http://some_endpoint') location = store.create_location('image-id', context=self.ctxt)
service_catalog.url_for.assert_called_once_with( self.assertEqual('swift+http', location.scheme)
service_type=store.service_type, self.assertEqual('http://some_endpoint', location.swift_url)
region_name=store.region,
endpoint_type=store.endpoint_type)
def test_multi_tenant_location_with_region(self): def test_multi_tenant_location_with_region(self):
self.config(swift_store_region='WestCarolina') self.config(swift_store_region='WestCarolina')
service_catalog = mock.MagicMock()
service_catalog.url_for.return_value = 'https://some_endpoint'
ctxt = mock.MagicMock(
user='user', tenant='tenant', auth_token='123',
service_catalog=service_catalog)
store = swift.MultiTenantStore(self.conf) store = swift.MultiTenantStore(self.conf)
store.configure() store.configure()
store._get_endpoint(ctxt) self.ctxt.service_catalog[0]['endpoints'][0]['region'] = 'WestCarolina'
service_catalog.url_for.assert_called_once_with( self.assertEqual('https://some_endpoint',
service_type=store.service_type, store._get_endpoint(self.ctxt))
region_name=store.region,
endpoint_type=store.endpoint_type)
def test_multi_tenant_location_custom_service_type(self): def test_multi_tenant_location_custom_service_type(self):
self.config(swift_store_service_type='toy-store') self.config(swift_store_service_type='toy-store')
service_catalog = mock.MagicMock() self.ctxt.service_catalog[0]['type'] = 'toy-store'
service_catalog.url_for.return_value = 'https://some_endpoint'
ctxt = mock.MagicMock(
user='user', tenant='tenant', auth_token='123',
service_catalog=service_catalog)
store = swift.MultiTenantStore(self.conf) store = swift.MultiTenantStore(self.conf)
store.configure() store.configure()
store._get_endpoint(ctxt) store._get_endpoint(self.ctxt)
service_catalog.url_for.assert_called_once_with( self.assertEqual('https://some_endpoint',
service_type=store.service_type, store._get_endpoint(self.ctxt))
region_name=store.region,
endpoint_type=store.endpoint_type)
def test_multi_tenant_location_custom_endpoint_type(self): def test_multi_tenant_location_custom_endpoint_type(self):
self.config(swift_store_endpoint_type='InternalURL') self.config(swift_store_endpoint_type='internalURL')
service_catalog = mock.MagicMock()
service_catalog.url_for.return_value = 'https://some_endpoint'
ctxt = mock.MagicMock(
user='user', tenant='tenant', auth_token='123',
service_catalog=service_catalog)
store = swift.MultiTenantStore(self.conf) store = swift.MultiTenantStore(self.conf)
store.configure() store.configure()
store._get_endpoint(ctxt) self.assertEqual('https://some_internal_endpoint',
service_catalog.url_for.assert_called_once_with( store._get_endpoint(self.ctxt))
service_type=store.service_type,
region_name=store.region,
endpoint_type=store.endpoint_type)
class TestChunkReader(base.StoreBaseTest): class TestChunkReader(base.StoreBaseTest):

View File

@ -14,3 +14,4 @@ six>=1.9.0 # MIT
debtcollector>=0.3.0 # Apache-2.0 debtcollector>=0.3.0 # Apache-2.0
jsonschema!=2.5.0,<3.0.0,>=2.0.0 # MIT jsonschema!=2.5.0,<3.0.0,>=2.0.0 # MIT
python-keystoneclient>=1.6.0,!=1.8.0,!=2.1.0 # Apache-2.0