xenapi: send identity headers from glance plugin

Send identity headers while uploading/downloading images from glance. Related
to:

1) Add identity headers while calling glanceclient from nova
Ife02059abbdce7920f1f408b71e9745d777fa770

2) Pass identity headers received in glanceclient to nova
Ifbef582aa4e64a2e7a46db43a9cc6cf8c3531dbd

3) Pass identity headers received by glance api to glance registry
Ie5f07ed6dfeaa8428de4f79c4d40d182328e6ab4

NOTE: since this is a change to a Dom0 plugin API, it requires the lock-step
upgrade of both the compute-manager and the dom0 plugin.

DocImpact

Change-Id: I6d5e3448d2c0acc392d18e0b88cec25cf313da5b
This commit is contained in:
Jared Culp 2013-07-23 15:25:25 -04:00 committed by Rick Harris
parent 27ff32ad09
commit 47a20a9f44
5 changed files with 58 additions and 48 deletions

View File

@ -104,6 +104,17 @@ def _parse_image_ref(image_href):
return (image_id, host, port, use_ssl) return (image_id, host, port, use_ssl)
def generate_identity_headers(context, status='Confirmed'):
return {
'X-Auth-Token': getattr(context, 'auth_token', None),
'X-User-Id': getattr(context, 'user', None),
'X-Tenant-Id': getattr(context, 'tenant', None),
'X-Roles': ','.join(context.roles),
'X-Identity-Status': status,
'X-Service-Catalog': json.dumps(context.service_catalog),
}
def _create_glance_client(context, host, port, use_ssl, version=1): def _create_glance_client(context, host, port, use_ssl, version=1):
"""Instantiate a new glanceclient.Client object.""" """Instantiate a new glanceclient.Client object."""
params = {} params = {}
@ -120,15 +131,7 @@ def _create_glance_client(context, host, port, use_ssl, version=1):
# keyword 'token', but later versions accept both the # keyword 'token', but later versions accept both the
# header 'X-Auth-Token' and 'token' # header 'X-Auth-Token' and 'token'
params['token'] = context.auth_token params['token'] = context.auth_token
identity_headers = { params['identity_headers'] = generate_identity_headers(context)
'X-Auth-Token': context.auth_token,
'X-User-Id': context.user,
'X-Tenant-Id': context.tenant,
'X-Roles': ','.join(context.roles),
'X-Identity-Status': 'Confirmed',
'X-Service-Catalog': json.dumps(context.service_catalog),
}
params['identity_headers'] = identity_headers
endpoint = '%s://%s:%s' % (scheme, host, port) endpoint = '%s://%s:%s' % (scheme, host, port)
return glanceclient.Client(str(version), endpoint, **params) return glanceclient.Client(str(version), endpoint, **params)

View File

@ -16,8 +16,6 @@
# under the License. # under the License.
import mox
from nova import context from nova import context
from nova import exception from nova import exception
from nova.tests.virt.xenapi import stubs from nova.tests.virt.xenapi import stubs
@ -31,7 +29,6 @@ class TestGlanceStore(stubs.XenAPITestBase):
def setUp(self): def setUp(self):
super(TestGlanceStore, self).setUp() super(TestGlanceStore, self).setUp()
self.store = glance.GlanceStore() self.store = glance.GlanceStore()
self.mox = mox.Mox()
self.flags(glance_host='1.1.1.1', self.flags(glance_host='1.1.1.1',
glance_port=123, glance_port=123,
@ -56,14 +53,26 @@ class TestGlanceStore(stubs.XenAPITestBase):
'os_type': 'default', 'os_type': 'default',
'xenapi_use_agent': 'true'} 'xenapi_use_agent': 'true'}
def _get_params(self):
return {'image_id': 'fake_image_uuid',
'glance_host': '1.1.1.1',
'glance_port': 123,
'glance_use_ssl': False,
'sr_path': '/fake/sr/path',
'extra_headers': {'X-Service-Catalog': '[]',
'X-Auth-Token': 'foobar',
'X-Roles': '',
'X-Tenant-Id': 'project',
'X-User-Id': 'user',
'X-Identity-Status': 'Confirmed'}}
def _get_download_params(self):
params = self._get_params()
params['uuid_stack'] = ['uuid1']
return params
def test_download_image(self): def test_download_image(self):
params = {'image_id': 'fake_image_uuid', params = self._get_download_params()
'glance_host': '1.1.1.1',
'glance_port': 123,
'glance_use_ssl': False,
'sr_path': '/fake/sr/path',
'auth_token': 'foobar',
'uuid_stack': ['uuid1']}
self.stubs.Set(vm_utils, '_make_uuid_stack', self.stubs.Set(vm_utils, '_make_uuid_stack',
lambda *a, **kw: ['uuid1']) lambda *a, **kw: ['uuid1'])
@ -78,15 +87,10 @@ class TestGlanceStore(stubs.XenAPITestBase):
self.mox.VerifyAll() self.mox.VerifyAll()
def _get_upload_params(self): def _get_upload_params(self):
params = {'vdi_uuids': ['fake_vdi_uuid'], params = self._get_params()
'image_id': 'fake_image_uuid', params['vdi_uuids'] = ['fake_vdi_uuid']
'glance_host': '1.1.1.1', params['properties'] = {'auto_disk_config': True,
'glance_port': 123, 'os_type': 'default'}
'glance_use_ssl': False,
'sr_path': '/fake/sr/path',
'auth_token': 'foobar',
'properties': {'auto_disk_config': True,
'os_type': 'default'}}
return params return params
def test_upload_image(self): def test_upload_image(self):
@ -105,10 +109,10 @@ class TestGlanceStore(stubs.XenAPITestBase):
self.mox.StubOutWithMock(self.session, 'call_plugin_serialized') self.mox.StubOutWithMock(self.session, 'call_plugin_serialized')
self.session.call_plugin_serialized('glance', 'upload_vhd', self.session.call_plugin_serialized('glance', 'upload_vhd',
**params).AndRaise(Exception) **params).AndRaise(RuntimeError)
self.mox.ReplayAll() self.mox.ReplayAll()
self.assertRaises(Exception, self.store.upload_image, self.assertRaises(RuntimeError, self.store.upload_image,
self.context, self.session, self.instance, self.context, self.session, self.instance,
['fake_vdi_uuid'], 'fake_image_uuid') ['fake_vdi_uuid'], 'fake_image_uuid')
self.mox.VerifyAll() self.mox.VerifyAll()

View File

@ -243,7 +243,12 @@ class FetchVhdImageTestCase(test.TestCase):
self.session, 'call_plugin_serialized_with_retry') self.session, 'call_plugin_serialized_with_retry')
self.session.call_plugin_serialized_with_retry( self.session.call_plugin_serialized_with_retry(
'glance', 'download_vhd', 0, mox.IgnoreArg(), 'glance', 'download_vhd', 0, mox.IgnoreArg(),
auth_token='auth_token', extra_headers={'X-Service-Catalog': '[]',
'X-Auth-Token': 'auth_token',
'X-Roles': '',
'X-Tenant-Id': None,
'X-User-Id': None,
'X-Identity-Status': 'Confirmed'},
image_id='image_id', image_id='image_id',
uuid_stack=["uuid_stack"], uuid_stack=["uuid_stack"],
sr_path='sr_path').AndReturn({'root': {'uuid': 'vdi'}}) sr_path='sr_path').AndReturn({'root': {'uuid': 'vdi'}})
@ -316,7 +321,12 @@ class FetchVhdImageTestCase(test.TestCase):
self.session, 'call_plugin_serialized_with_retry') self.session, 'call_plugin_serialized_with_retry')
self.session.call_plugin_serialized_with_retry( self.session.call_plugin_serialized_with_retry(
'glance', 'download_vhd', 0, mox.IgnoreArg(), 'glance', 'download_vhd', 0, mox.IgnoreArg(),
auth_token='auth_token', extra_headers={'X-Service-Catalog': '[]',
'X-Auth-Token': 'auth_token',
'X-Roles': '',
'X-Tenant-Id': None,
'X-User-Id': None,
'X-Identity-Status': 'Confirmed'},
image_id='image_id', image_id='image_id',
uuid_stack=["uuid_stack"], uuid_stack=["uuid_stack"],
sr_path='sr_path').AndReturn({'root': {'uuid': 'vdi'}}) sr_path='sr_path').AndReturn({'root': {'uuid': 'vdi'}})

View File

@ -39,7 +39,7 @@ class GlanceStore(object):
def _make_params(self, context, session, image_id): def _make_params(self, context, session, image_id):
return {'image_id': image_id, return {'image_id': image_id,
'sr_path': vm_utils.get_sr_path(session), 'sr_path': vm_utils.get_sr_path(session),
'auth_token': getattr(context, 'auth_token', None)} 'extra_headers': glance.generate_identity_headers(context)}
def download_image(self, context, session, instance, image_id): def download_image(self, context, session, instance, image_id):
params = self._make_params(context, session, image_id) params = self._make_params(context, session, image_id)

View File

@ -89,15 +89,10 @@ def _download_tarball_and_verify(request, staging_path):
def _download_tarball(sr_path, staging_path, image_id, glance_host, def _download_tarball(sr_path, staging_path, image_id, glance_host,
glance_port, glance_use_ssl, auth_token): glance_port, glance_use_ssl, extra_headers):
"""Download the tarball image from Glance and extract it into the staging """Download the tarball image from Glance and extract it into the staging
area. Retry if there is any failure. area. Retry if there is any failure.
""" """
# Build request headers
headers = {}
if auth_token:
headers['x-auth-token'] = auth_token
if glance_use_ssl: if glance_use_ssl:
scheme = 'https' scheme = 'https'
else: else:
@ -107,7 +102,7 @@ def _download_tarball(sr_path, staging_path, image_id, glance_host,
"%(image_id)s" % locals()) "%(image_id)s" % locals())
logging.info("Downloading %s" % url) logging.info("Downloading %s" % url)
request = urllib2.Request(url, headers=headers) request = urllib2.Request(url, headers=extra_headers)
try: try:
_download_tarball_and_verify(request, staging_path) _download_tarball_and_verify(request, staging_path)
except Exception: except Exception:
@ -116,7 +111,7 @@ def _download_tarball(sr_path, staging_path, image_id, glance_host,
def _upload_tarball(staging_path, image_id, glance_host, glance_port, def _upload_tarball(staging_path, image_id, glance_host, glance_port,
glance_use_ssl, auth_token, properties): glance_use_ssl, extra_headers, properties):
""" """
Create a tarball of the image and then stream that into Glance Create a tarball of the image and then stream that into Glance
using chunked-transfer-encoded HTTP. using chunked-transfer-encoded HTTP.
@ -166,9 +161,7 @@ def _upload_tarball(staging_path, image_id, glance_host, glance_port,
'x-image-meta-container-format': 'ovf', 'x-image-meta-container-format': 'ovf',
'x-glance-registry-purge-props': 'False'} 'x-glance-registry-purge-props': 'False'}
# If we have an auth_token, set an x-auth-token header headers.update(**extra_headers)
if auth_token:
headers['x-auth-token'] = auth_token
for key, value in properties.iteritems(): for key, value in properties.iteritems():
header_key = "x-image-meta-property-%s" % key.replace('_', '-') header_key = "x-image-meta-property-%s" % key.replace('_', '-')
@ -229,7 +222,7 @@ def _upload_tarball(staging_path, image_id, glance_host, glance_port,
def download_vhd(session, image_id, glance_host, glance_port, glance_use_ssl, def download_vhd(session, image_id, glance_host, glance_port, glance_use_ssl,
uuid_stack, sr_path, auth_token): uuid_stack, sr_path, extra_headers):
"""Download an image from Glance, unbundle it, and then deposit the VHDs """Download an image from Glance, unbundle it, and then deposit the VHDs
into the storage repository into the storage repository
""" """
@ -238,7 +231,7 @@ def download_vhd(session, image_id, glance_host, glance_port, glance_use_ssl,
# Download tarball into staging area and extract it # Download tarball into staging area and extract it
_download_tarball( _download_tarball(
sr_path, staging_path, image_id, glance_host, glance_port, sr_path, staging_path, image_id, glance_host, glance_port,
glance_use_ssl, auth_token) glance_use_ssl, extra_headers)
# Move the VHDs from the staging area into the storage repository # Move the VHDs from the staging area into the storage repository
return utils.import_vhds(sr_path, staging_path, uuid_stack) return utils.import_vhds(sr_path, staging_path, uuid_stack)
@ -247,14 +240,14 @@ def download_vhd(session, image_id, glance_host, glance_port, glance_use_ssl,
def upload_vhd(session, vdi_uuids, image_id, glance_host, glance_port, def upload_vhd(session, vdi_uuids, image_id, glance_host, glance_port,
glance_use_ssl, sr_path, auth_token, properties): glance_use_ssl, sr_path, extra_headers, properties):
"""Bundle the VHDs comprising an image and then stream them into Glance. """Bundle the VHDs comprising an image and then stream them into Glance.
""" """
staging_path = utils.make_staging_area(sr_path) staging_path = utils.make_staging_area(sr_path)
try: try:
utils.prepare_staging_area(sr_path, staging_path, vdi_uuids) utils.prepare_staging_area(sr_path, staging_path, vdi_uuids)
_upload_tarball(staging_path, image_id, glance_host, glance_port, _upload_tarball(staging_path, image_id, glance_host, glance_port,
glance_use_ssl, auth_token, properties) glance_use_ssl, extra_headers, properties)
finally: finally:
utils.cleanup_staging_area(staging_path) utils.cleanup_staging_area(staging_path)