Allow connecting to a ssl-based glance
This introduces a new glance_api_insecure setting that can be used to not verify the certificate of the glance server against the certificate authorities. Fix bug 1042081. Change-Id: I0a9f081425854e9c01e00dfd641e42276c878c67
This commit is contained in:
parent
68e9a9e351
commit
fa5be443ba
@ -125,9 +125,13 @@
|
||||
#### (IntOpt) default glance port
|
||||
|
||||
# glance_api_servers=$glance_host:$glance_port
|
||||
#### (ListOpt) A list of the glance api servers available to nova
|
||||
#### (ListOpt) A list of the glance api servers available to nova.
|
||||
#### Prefix with https:// for ssl-based glance api servers.
|
||||
#### ([hostname|ip]:port)
|
||||
|
||||
# glance_api_insecure=false
|
||||
#### (BoolOpt) If passed, allow to perform insecure SSL (https) requests to glance
|
||||
|
||||
# glance_num_retries=0
|
||||
#### (IntOpt) Number retries when downloading an image from glance
|
||||
|
||||
|
@ -137,8 +137,13 @@ global_opts = [
|
||||
help='default glance port'),
|
||||
cfg.ListOpt('glance_api_servers',
|
||||
default=['$glance_host:$glance_port'],
|
||||
help='A list of the glance api servers available to nova '
|
||||
help='A list of the glance api servers available to nova. '
|
||||
'Prefix with https:// for ssl-based glance api servers. '
|
||||
'([hostname|ip]:port)'),
|
||||
cfg.BoolOpt('glance_api_insecure',
|
||||
default=False,
|
||||
help='Allow to perform insecure SSL (https) requests to '
|
||||
'glance'),
|
||||
cfg.IntOpt('glance_num_retries',
|
||||
default=0,
|
||||
help='Number retries when downloading an image from glance'),
|
||||
|
@ -52,15 +52,21 @@ def _parse_image_ref(image_href):
|
||||
port = o.port or 80
|
||||
host = o.netloc.split(':', 1)[0]
|
||||
image_id = o.path.split('/')[-1]
|
||||
return (image_id, host, port)
|
||||
use_ssl = (o.scheme == 'https')
|
||||
return (image_id, host, port, use_ssl)
|
||||
|
||||
|
||||
def _create_glance_client(context, host, port):
|
||||
def _create_glance_client(context, host, port, use_ssl):
|
||||
"""Instantiate a new glanceclient.Client object"""
|
||||
if use_ssl:
|
||||
scheme = 'https'
|
||||
else:
|
||||
scheme = 'http'
|
||||
params = {}
|
||||
params['insecure'] = FLAGS.glance_api_insecure
|
||||
if FLAGS.auth_strategy == 'keystone':
|
||||
params['token'] = context.auth_token
|
||||
endpoint = 'http://%s:%s' % (host, port)
|
||||
endpoint = '%s://%s:%s' % (scheme, host, port)
|
||||
return glanceclient.Client('1', endpoint, **params)
|
||||
|
||||
|
||||
@ -72,8 +78,13 @@ def get_api_servers():
|
||||
"""
|
||||
api_servers = []
|
||||
for api_server in FLAGS.glance_api_servers:
|
||||
host, port_str = api_server.split(':')
|
||||
api_servers.append((host, int(port_str)))
|
||||
if '//' not in api_server:
|
||||
api_server = 'http://' + api_server
|
||||
o = urlparse.urlparse(api_server)
|
||||
port = o.port or 80
|
||||
host = o.netloc.split(':', 1)[0]
|
||||
use_ssl = (o.scheme == 'https')
|
||||
api_servers.append((host, port, use_ssl))
|
||||
random.shuffle(api_servers)
|
||||
return itertools.cycle(api_servers)
|
||||
|
||||
@ -81,25 +92,29 @@ def get_api_servers():
|
||||
class GlanceClientWrapper(object):
|
||||
"""Glance client wrapper class that implements retries."""
|
||||
|
||||
def __init__(self, context=None, host=None, port=None):
|
||||
def __init__(self, context=None, host=None, port=None, use_ssl=False):
|
||||
if host is not None:
|
||||
self.client = self._create_static_client(context, host, port)
|
||||
self.client = self._create_static_client(context,
|
||||
host, port, use_ssl)
|
||||
else:
|
||||
self.client = None
|
||||
self.api_servers = None
|
||||
|
||||
def _create_static_client(self, context, host, port):
|
||||
def _create_static_client(self, context, host, port, use_ssl):
|
||||
"""Create a client that we'll use for every call."""
|
||||
self.host = host
|
||||
self.port = port
|
||||
return _create_glance_client(context, self.host, self.port)
|
||||
self.use_ssl = use_ssl
|
||||
return _create_glance_client(context,
|
||||
self.host, self.port, self.use_ssl)
|
||||
|
||||
def _create_onetime_client(self, context):
|
||||
"""Create a client that will be used for one call."""
|
||||
if self.api_servers is None:
|
||||
self.api_servers = get_api_servers()
|
||||
self.host, self.port = self.api_servers.next()
|
||||
return _create_glance_client(context, self.host, self.port)
|
||||
self.host, self.port, self.use_ssl = self.api_servers.next()
|
||||
return _create_glance_client(context,
|
||||
self.host, self.port, self.use_ssl)
|
||||
|
||||
def call(self, context, method, *args, **kwargs):
|
||||
"""
|
||||
@ -398,9 +413,10 @@ def get_remote_image_service(context, image_href):
|
||||
return image_service, image_href
|
||||
|
||||
try:
|
||||
(image_id, glance_host, glance_port) = _parse_image_ref(image_href)
|
||||
(image_id, glance_host, glance_port, use_ssl) = \
|
||||
_parse_image_ref(image_href)
|
||||
glance_client = GlanceClientWrapper(context=context,
|
||||
host=glance_host, port=glance_port)
|
||||
host=glance_host, port=glance_port, use_ssl=use_ssl)
|
||||
except ValueError:
|
||||
raise exception.InvalidImageRef(image_href=image_href)
|
||||
|
||||
|
@ -105,7 +105,7 @@ class TestGlanceImageService(test.TestCase):
|
||||
self.context = context.RequestContext('fake', 'fake', auth_token=True)
|
||||
|
||||
def _create_image_service(self, client):
|
||||
def _fake_create_glance_client(context, host, port):
|
||||
def _fake_create_glance_client(context, host, port, use_ssl):
|
||||
return client
|
||||
|
||||
self.stubs.Set(glance, '_create_glance_client',
|
||||
@ -550,8 +550,9 @@ class TestGlanceClientWrapper(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestGlanceClientWrapper, self).setUp()
|
||||
self.flags(glance_api_servers=['host1:9292', 'host2:9293',
|
||||
'host3:9294'])
|
||||
# host1 has no scheme, which is http by default
|
||||
self.flags(glance_api_servers=['host1:9292', 'https://host2:9293',
|
||||
'http://host3:9294'])
|
||||
|
||||
# Make the test run fast
|
||||
def _fake_sleep(secs):
|
||||
@ -564,19 +565,21 @@ class TestGlanceClientWrapper(test.TestCase):
|
||||
ctxt = context.RequestContext('fake', 'fake')
|
||||
fake_host = 'host4'
|
||||
fake_port = 9295
|
||||
fake_use_ssl = False
|
||||
|
||||
info = {'num_calls': 0}
|
||||
|
||||
def _fake_create_glance_client(context, host, port):
|
||||
def _fake_create_glance_client(context, host, port, use_ssl):
|
||||
self.assertEqual(host, fake_host)
|
||||
self.assertEqual(port, fake_port)
|
||||
self.assertEqual(use_ssl, fake_use_ssl)
|
||||
return _create_failing_glance_client(info)
|
||||
|
||||
self.stubs.Set(glance, '_create_glance_client',
|
||||
_fake_create_glance_client)
|
||||
|
||||
client = glance.GlanceClientWrapper(context=ctxt,
|
||||
host=fake_host, port=fake_port)
|
||||
host=fake_host, port=fake_port, use_ssl=fake_use_ssl)
|
||||
self.assertRaises(exception.GlanceConnectionFailed,
|
||||
client.call, ctxt, 'get', 'meow')
|
||||
self.assertEqual(info['num_calls'], 1)
|
||||
@ -588,15 +591,17 @@ class TestGlanceClientWrapper(test.TestCase):
|
||||
|
||||
info = {'num_calls': 0,
|
||||
'host': 'host1',
|
||||
'port': 9292}
|
||||
'port': 9292,
|
||||
'use_ssl': False}
|
||||
|
||||
# Leave the list in a known-order
|
||||
def _fake_shuffle(servers):
|
||||
pass
|
||||
|
||||
def _fake_create_glance_client(context, host, port):
|
||||
def _fake_create_glance_client(context, host, port, use_ssl):
|
||||
self.assertEqual(host, info['host'])
|
||||
self.assertEqual(port, info['port'])
|
||||
self.assertEqual(use_ssl, info['use_ssl'])
|
||||
return _create_failing_glance_client(info)
|
||||
|
||||
self.stubs.Set(random, 'shuffle', _fake_shuffle)
|
||||
@ -611,7 +616,8 @@ class TestGlanceClientWrapper(test.TestCase):
|
||||
|
||||
info = {'num_calls': 0,
|
||||
'host': 'host2',
|
||||
'port': 9293}
|
||||
'port': 9293,
|
||||
'use_ssl': True}
|
||||
|
||||
def _fake_shuffle2(servers):
|
||||
# fake shuffle in a known manner
|
||||
@ -629,19 +635,21 @@ class TestGlanceClientWrapper(test.TestCase):
|
||||
ctxt = context.RequestContext('fake', 'fake')
|
||||
fake_host = 'host4'
|
||||
fake_port = 9295
|
||||
fake_use_ssl = False
|
||||
|
||||
info = {'num_calls': 0}
|
||||
|
||||
def _fake_create_glance_client(context, host, port):
|
||||
def _fake_create_glance_client(context, host, port, use_ssl):
|
||||
self.assertEqual(host, fake_host)
|
||||
self.assertEqual(port, fake_port)
|
||||
self.assertEqual(use_ssl, fake_use_ssl)
|
||||
return _create_failing_glance_client(info)
|
||||
|
||||
self.stubs.Set(glance, '_create_glance_client',
|
||||
_fake_create_glance_client)
|
||||
|
||||
client = glance.GlanceClientWrapper(context=ctxt,
|
||||
host=fake_host, port=fake_port)
|
||||
host=fake_host, port=fake_port, use_ssl=fake_use_ssl)
|
||||
client.call(ctxt, 'get', 'meow')
|
||||
self.assertEqual(info['num_calls'], 2)
|
||||
|
||||
@ -653,17 +661,20 @@ class TestGlanceClientWrapper(test.TestCase):
|
||||
info = {'num_calls': 0,
|
||||
'host0': 'host1',
|
||||
'port0': 9292,
|
||||
'use_ssl0': False,
|
||||
'host1': 'host2',
|
||||
'port1': 9293}
|
||||
'port1': 9293,
|
||||
'use_ssl1': True}
|
||||
|
||||
# Leave the list in a known-order
|
||||
def _fake_shuffle(servers):
|
||||
pass
|
||||
|
||||
def _fake_create_glance_client(context, host, port):
|
||||
def _fake_create_glance_client(context, host, port, use_ssl):
|
||||
attempt = info['num_calls']
|
||||
self.assertEqual(host, info['host%s' % attempt])
|
||||
self.assertEqual(port, info['port%s' % attempt])
|
||||
self.assertEqual(use_ssl, info['use_ssl%s' % attempt])
|
||||
return _create_failing_glance_client(info)
|
||||
|
||||
self.stubs.Set(random, 'shuffle', _fake_shuffle)
|
||||
@ -684,8 +695,10 @@ class TestGlanceClientWrapper(test.TestCase):
|
||||
info = {'num_calls': 0,
|
||||
'host0': 'host2',
|
||||
'port0': 9293,
|
||||
'use_ssl0': True,
|
||||
'host1': 'host3',
|
||||
'port1': 9294}
|
||||
'port1': 9294,
|
||||
'use_ssl1': False}
|
||||
|
||||
client2.call(ctxt, 'get', 'meow')
|
||||
self.assertEqual(info['num_calls'], 2)
|
||||
|
@ -649,7 +649,7 @@ def upload_image(context, session, instance, vdi_uuids, image_id):
|
||||
" ID %(image_id)s"), locals(), instance=instance)
|
||||
|
||||
glance_api_servers = glance.get_api_servers()
|
||||
glance_host, glance_port = glance_api_servers.next()
|
||||
glance_host, glance_port, glance_use_ssl = glance_api_servers.next()
|
||||
|
||||
# TODO(sirp): this inherit-image-property code should probably go in
|
||||
# nova/compute/manager so it can be shared across hypervisors
|
||||
@ -669,6 +669,7 @@ def upload_image(context, session, instance, vdi_uuids, image_id):
|
||||
'image_id': image_id,
|
||||
'glance_host': glance_host,
|
||||
'glance_port': glance_port,
|
||||
'glance_use_ssl': glance_use_ssl,
|
||||
'sr_path': get_sr_path(session),
|
||||
'auth_token': getattr(context, 'auth_token', None),
|
||||
'properties': properties}
|
||||
@ -1011,9 +1012,10 @@ def _fetch_vhd_image(context, session, instance, image_id):
|
||||
glance_api_servers = glance.get_api_servers()
|
||||
|
||||
def pick_glance(params):
|
||||
glance_host, glance_port = glance_api_servers.next()
|
||||
glance_host, glance_port, glance_use_ssl = glance_api_servers.next()
|
||||
params['glance_host'] = glance_host
|
||||
params['glance_port'] = glance_port
|
||||
params['glance_use_ssl'] = glance_use_ssl
|
||||
|
||||
plugin_name = 'glance'
|
||||
vdis = _fetch_using_dom0_plugin_with_retry(
|
||||
|
@ -95,7 +95,7 @@ def _download_tarball_and_verify(request, staging_path):
|
||||
|
||||
|
||||
def _download_tarball(sr_path, staging_path, image_id, glance_host,
|
||||
glance_port, auth_token):
|
||||
glance_port, glance_use_ssl, auth_token):
|
||||
"""Download the tarball image from Glance and extract it into the staging
|
||||
area. Retry if there is any failure.
|
||||
"""
|
||||
@ -104,7 +104,12 @@ def _download_tarball(sr_path, staging_path, image_id, glance_host,
|
||||
if auth_token:
|
||||
headers['x-auth-token'] = auth_token
|
||||
|
||||
url = ("http://%(glance_host)s:%(glance_port)d/v1/images/"
|
||||
if glance_use_ssl:
|
||||
scheme = 'https'
|
||||
else:
|
||||
scheme = 'http'
|
||||
|
||||
url = ("%(scheme)s://%(glance_host)s:%(glance_port)d/v1/images/"
|
||||
"%(image_id)s" % locals())
|
||||
logging.info("Downloading %s" % url)
|
||||
|
||||
@ -117,14 +122,23 @@ def _download_tarball(sr_path, staging_path, image_id, glance_host,
|
||||
|
||||
|
||||
def _upload_tarball(staging_path, image_id, glance_host, glance_port,
|
||||
auth_token, properties):
|
||||
glance_use_ssl, auth_token, properties):
|
||||
"""
|
||||
Create a tarball of the image and then stream that into Glance
|
||||
using chunked-transfer-encoded HTTP.
|
||||
"""
|
||||
url = 'http://%s:%s/v1/images/%s' % (glance_host, glance_port, image_id)
|
||||
if glance_use_ssl:
|
||||
scheme = 'https'
|
||||
else:
|
||||
scheme = 'http'
|
||||
|
||||
url = '%s://%s:%s/v1/images/%s' % (scheme, glance_host, glance_port,
|
||||
image_id)
|
||||
logging.info("Writing image data to %s" % url)
|
||||
conn = httplib.HTTPConnection(glance_host, glance_port)
|
||||
if glance_use_ssl:
|
||||
conn = httplib.HTTPSConnection(glance_host, glance_port)
|
||||
else:
|
||||
conn = httplib.HTTPConnection(glance_host, glance_port)
|
||||
|
||||
# NOTE(sirp): httplib under python2.4 won't accept a file-like object
|
||||
# to request
|
||||
@ -196,6 +210,7 @@ def download_vhd(session, args):
|
||||
image_id = params["image_id"]
|
||||
glance_host = params["glance_host"]
|
||||
glance_port = params["glance_port"]
|
||||
glance_use_ssl = params["glance_use_ssl"]
|
||||
uuid_stack = params["uuid_stack"]
|
||||
sr_path = params["sr_path"]
|
||||
auth_token = params["auth_token"]
|
||||
@ -205,7 +220,7 @@ def download_vhd(session, args):
|
||||
# Download tarball into staging area and extract it
|
||||
_download_tarball(
|
||||
sr_path, staging_path, image_id, glance_host, glance_port,
|
||||
auth_token)
|
||||
glance_use_ssl, auth_token)
|
||||
|
||||
# Move the VHDs from the staging area into the storage repository
|
||||
imported_vhds = utils.import_vhds(sr_path, staging_path, uuid_stack)
|
||||
@ -225,6 +240,7 @@ def upload_vhd(session, args):
|
||||
image_id = params["image_id"]
|
||||
glance_host = params["glance_host"]
|
||||
glance_port = params["glance_port"]
|
||||
glance_use_ssl = params["glance_use_ssl"]
|
||||
sr_path = params["sr_path"]
|
||||
auth_token = params["auth_token"]
|
||||
properties = params["properties"]
|
||||
@ -233,7 +249,7 @@ def upload_vhd(session, args):
|
||||
try:
|
||||
utils.prepare_staging_area(sr_path, staging_path, vdi_uuids)
|
||||
_upload_tarball(staging_path, image_id, glance_host, glance_port,
|
||||
auth_token, properties)
|
||||
glance_use_ssl, auth_token, properties)
|
||||
finally:
|
||||
utils.cleanup_staging_area(staging_path)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user