Merge "Use the catalog to retrieve glance_api_servers"

This commit is contained in:
Jenkins 2016-03-18 21:41:09 +00:00 committed by Gerrit Code Review
commit 75212a9df6
5 changed files with 60 additions and 22 deletions

View File

@ -54,15 +54,8 @@ global_opts = [
cfg.StrOpt('my_ip', cfg.StrOpt('my_ip',
default=netutils.get_my_ipv4(), default=netutils.get_my_ipv4(),
help='IP address of this host'), help='IP address of this host'),
cfg.StrOpt('glance_host',
default='$my_ip',
help='Default glance host name or IP'),
cfg.IntOpt('glance_port',
default=9292,
min=1, max=65535,
help='Default glance port'),
cfg.ListOpt('glance_api_servers', cfg.ListOpt('glance_api_servers',
default=['$glance_host:$glance_port'], default=None,
help='A list of the URLs of glance API servers available to ' help='A list of the URLs of glance API servers available to '
'cinder ([http[s]://][hostname|ip]:port). If protocol ' 'cinder ([http[s]://][hostname|ip]:port). If protocol '
'is not specified it defaults to http.'), 'is not specified it defaults to http.'),

View File

@ -92,7 +92,8 @@ class RequestContext(context.RequestContext):
# Only include required parts of service_catalog # Only include required parts of service_catalog
self.service_catalog = [s for s in service_catalog self.service_catalog = [s for s in service_catalog
if s.get('type') in if s.get('type') in
('identity', 'compute', 'object-store')] ('identity', 'compute', 'object-store',
'image')]
else: else:
# if list is empty or none # if list is empty or none
self.service_catalog = [] self.service_catalog = []

View File

@ -36,7 +36,7 @@ from six.moves import range
from six.moves import urllib from six.moves import urllib
from cinder import exception from cinder import exception
from cinder.i18n import _LE, _LW from cinder.i18n import _, _LE, _LW
glance_opts = [ glance_opts = [
@ -45,6 +45,12 @@ glance_opts = [
help='A list of url schemes that can be downloaded directly ' help='A list of url schemes that can be downloaded directly '
'via the direct_url. Currently supported schemes: ' 'via the direct_url. Currently supported schemes: '
'[file].'), '[file].'),
cfg.StrOpt('glance_catalog_info',
default='image:glance:publicURL',
help='Info to match when looking for glance in the service '
'catalog. Format is: separated values of the form: '
'<service_type>:<service_name>:<endpoint_type> - '
'Only used if glance_api_servers are not provided.'),
] ]
glance_core_properties_opts = [ glance_core_properties_opts = [
cfg.ListOpt('glance_core_properties', cfg.ListOpt('glance_core_properties',
@ -97,23 +103,44 @@ def _create_glance_client(context, netloc, use_ssl, version=None):
return glanceclient.Client(str(version), endpoint, **params) return glanceclient.Client(str(version), endpoint, **params)
def get_api_servers(): def get_api_servers(context):
"""Return Iterable over shuffled api servers. """Return Iterable over shuffled api servers.
Shuffle a list of CONF.glance_api_servers and return an iterator Shuffle a list of glance_api_servers and return an iterator
that will cycle through the list, looping around to the beginning that will cycle through the list, looping around to the beginning
if necessary. if necessary. If CONF.glance_api_servers is None then they will
be retrieved from the catalog.
""" """
api_servers = [] api_servers = []
for api_server in CONF.glance_api_servers: api_servers_info = []
if CONF.glance_api_servers is None:
info = CONF.glance_catalog_info
try:
service_type, service_name, endpoint_type = info.split(':')
except ValueError:
raise exception.InvalidConfigurationValue(_(
"Failed to parse the configuration option "
"'glance_catalog_info', must be in the form "
"<service_type>:<service_name>:<endpoint_type>"))
for entry in context.service_catalog:
if entry.get('type') == service_type:
api_servers.append(
entry.get('endpoints')[0].get(endpoint_type))
else:
for api_server in CONF.glance_api_servers:
api_servers.append(api_server)
for api_server in api_servers:
if '//' not in api_server: if '//' not in api_server:
api_server = 'http://' + api_server api_server = 'http://' + api_server
url = urllib.parse.urlparse(api_server) url = urllib.parse.urlparse(api_server)
netloc = url.netloc netloc = url.netloc
use_ssl = (url.scheme == 'https') use_ssl = (url.scheme == 'https')
api_servers.append((netloc, use_ssl)) api_servers_info.append((netloc, use_ssl))
random.shuffle(api_servers)
return itertools.cycle(api_servers) random.shuffle(api_servers_info)
return itertools.cycle(api_servers_info)
class GlanceClientWrapper(object): class GlanceClientWrapper(object):
@ -149,7 +176,7 @@ class GlanceClientWrapper(object):
def _create_onetime_client(self, context, version): def _create_onetime_client(self, context, version):
"""Create a client that will be used for one call.""" """Create a client that will be used for one call."""
if self.api_servers is None: if self.api_servers is None:
self.api_servers = get_api_servers() self.api_servers = get_api_servers(context)
self.netloc, self.use_ssl = next(self.api_servers) self.netloc, self.use_ssl = next(self.api_servers)
return _create_glance_client(context, return _create_glance_client(context,
self.netloc, self.netloc,

View File

@ -15,6 +15,7 @@
import datetime import datetime
import itertools
import glanceclient.exc import glanceclient.exc
import mock import mock
@ -94,8 +95,12 @@ class TestGlanceImageService(test.TestCase):
super(TestGlanceImageService, self).setUp() super(TestGlanceImageService, self).setUp()
client = glance_stubs.StubGlanceClient() client = glance_stubs.StubGlanceClient()
service_catalog = [{u'type': u'image', u'name': u'glance',
u'endpoints': [{
u'publicURL': u'http://example.com:9292'}]}]
self.service = self._create_image_service(client) self.service = self._create_image_service(client)
self.context = context.RequestContext('fake', 'fake', auth_token=True) self.context = context.RequestContext('fake', 'fake', auth_token=True)
self.context.service_catalog = service_catalog
self.stubs.Set(glance.time, 'sleep', lambda s: None) self.stubs.Set(glance.time, 'sleep', lambda s: None)
def _create_image_service(self, client): def _create_image_service(self, client):
@ -123,6 +128,11 @@ class TestGlanceImageService(test.TestCase):
updated_at=self.NOW_GLANCE_FORMAT, updated_at=self.NOW_GLANCE_FORMAT,
deleted_at=self.NOW_GLANCE_FORMAT) deleted_at=self.NOW_GLANCE_FORMAT)
def test_get_api_servers(self):
result = glance.get_api_servers(self.context)
expected = (u'example.com:9292', False)
self.assertEqual(expected, next(result))
def test_create_with_instance_id(self): def test_create_with_instance_id(self):
"""Ensure instance_id is persisted as an image-property.""" """Ensure instance_id is persisted as an image-property."""
fixture = {'name': 'test image', fixture = {'name': 'test image',
@ -533,7 +543,10 @@ class TestGlanceImageService(test.TestCase):
@mock.patch('six.moves.builtins.open') @mock.patch('six.moves.builtins.open')
@mock.patch('shutil.copyfileobj') @mock.patch('shutil.copyfileobj')
def test_download_from_direct_file(self, mock_copyfileobj, mock_open): @mock.patch('cinder.image.glance.get_api_servers',
return_value=itertools.cycle([(False, 'localhost:9292')]))
def test_download_from_direct_file(self, api_servers,
mock_copyfileobj, mock_open):
fixture = self._make_fixture(name='test image', fixture = self._make_fixture(name='test image',
locations=[{'url': 'file:///tmp/test'}]) locations=[{'url': 'file:///tmp/test'}])
image_id = self.service.create(self.context, fixture)['id'] image_id = self.service.create(self.context, fixture)['id']
@ -545,7 +558,9 @@ class TestGlanceImageService(test.TestCase):
@mock.patch('six.moves.builtins.open') @mock.patch('six.moves.builtins.open')
@mock.patch('shutil.copyfileobj') @mock.patch('shutil.copyfileobj')
def test_download_from_direct_file_non_file(self, @mock.patch('cinder.image.glance.get_api_servers',
return_value=itertools.cycle([(False, 'localhost:9292')]))
def test_download_from_direct_file_non_file(self, api_servers,
mock_copyfileobj, mock_open): mock_copyfileobj, mock_open):
fixture = self._make_fixture(name='test image', fixture = self._make_fixture(name='test image',
direct_url='swift+http://test/image') direct_url='swift+http://test/image')
@ -734,7 +749,9 @@ class TestGlanceClientVersion(test.TestCase):
self.assertEqual('2', _mockglanceclient.call_args[0][0]) self.assertEqual('2', _mockglanceclient.call_args[0][0])
@mock.patch('cinder.image.glance.glanceclient.Client') @mock.patch('cinder.image.glance.glanceclient.Client')
def test_call_glance_version_by_arg(self, _mockglanceclient): @mock.patch('cinder.image.glance.get_api_servers',
return_value=itertools.cycle([(False, 'localhost:9292')]))
def test_call_glance_version_by_arg(self, api_servers, _mockglanceclient):
"""Test glance version set by arg to GlanceClientWrapper""" """Test glance version set by arg to GlanceClientWrapper"""
glance_wrapper = glance.GlanceClientWrapper() glance_wrapper = glance.GlanceClientWrapper()
glance_wrapper.call('fake_context', 'method', version=2) glance_wrapper.call('fake_context', 'method', version=2)

View File

@ -82,7 +82,7 @@ class ContextTestCase(test.TestCase):
object_catalog = [{u'name': u'swift', u'type': u'object-store'}] object_catalog = [{u'name': u'swift', u'type': u'object-store'}]
ctxt = context.RequestContext('111', '222', ctxt = context.RequestContext('111', '222',
service_catalog=service_catalog) service_catalog=service_catalog)
self.assertEqual(3, len(ctxt.service_catalog)) self.assertEqual(4, len(ctxt.service_catalog))
return_compute = [v for v in ctxt.service_catalog if return_compute = [v for v in ctxt.service_catalog if
v['type'] == u'compute'] v['type'] == u'compute']
return_object = [v for v in ctxt.service_catalog if return_object = [v for v in ctxt.service_catalog if