summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2012-05-28 09:59:58 +0000
committerGerrit Code Review <review@openstack.org>2012-05-28 09:59:58 +0000
commitd7e613dabc2dbc28d9405a5b450dc2b4dfa9d47b (patch)
tree8cdd40cd47da365242aef96d5ff97f192a6723e8
parent0add75a7ff674cd650a962bfbc1f24121313bfde (diff)
parent7b89917ece552b6b3dfe92ecc878531d9bfd9125 (diff)
downloadnova-d7e613dabc2dbc28d9405a5b450dc2b4dfa9d47b.tar.gz
nova-d7e613dabc2dbc28d9405a5b450dc2b4dfa9d47b.tar.xz
nova-d7e613dabc2dbc28d9405a5b450dc2b4dfa9d47b.zip
Merge "_s3_create update only pertinent metadata"
-rw-r--r--nova/image/fake.py18
-rw-r--r--nova/image/glance.py5
-rw-r--r--nova/image/s3.py47
-rw-r--r--nova/tests/glance/stubs.py2
-rw-r--r--nova/tests/image/test_s3.py59
5 files changed, 105 insertions, 26 deletions
diff --git a/nova/image/fake.py b/nova/image/fake.py
index 4f29cdb6e..41a68269a 100644
--- a/nova/image/fake.py
+++ b/nova/image/fake.py
@@ -210,7 +210,8 @@ class _FakeImageService(object):
self._imagedata[image_id] = data.read()
return self.images[image_id]
- def update(self, context, image_id, metadata, data=None):
+ def update(self, context, image_id, metadata, data=None,
+ headers=None):
"""Replace the contents of the given image with the new data.
:raises: ImageNotFound if the image does not exist.
@@ -218,7 +219,20 @@ class _FakeImageService(object):
"""
if not self.images.get(image_id):
raise exception.ImageNotFound(image_id=image_id)
- self.images[image_id] = copy.deepcopy(metadata)
+ try:
+ purge = headers['x-glance-registry-purge-props']
+ except Exception:
+ purge = True
+ if purge:
+ self.images[image_id] = copy.deepcopy(metadata)
+ else:
+ image = self.images[image_id]
+ try:
+ image['properties'].update(metadata.pop('properties'))
+ except Exception:
+ pass
+ image.update(metadata)
+ return self.images[image_id]
def delete(self, context, image_id):
"""Delete the given image.
diff --git a/nova/image/glance.py b/nova/image/glance.py
index 1e98cbe11..dc7ae89ad 100644
--- a/nova/image/glance.py
+++ b/nova/image/glance.py
@@ -290,7 +290,7 @@ class GlanceImageService(object):
base_image_meta)
return base_image_meta
- def update(self, context, image_id, image_meta, data=None):
+ def update(self, context, image_id, image_meta, data=None, features=None):
"""Replace the contents of the given image with the new data.
:raises: ImageNotFound if the image does not exist.
@@ -301,7 +301,8 @@ class GlanceImageService(object):
image_meta = self._translate_to_glance(image_meta)
client = self._get_client(context)
try:
- image_meta = client.update_image(image_id, image_meta, data)
+ image_meta = client.update_image(image_id, image_meta, data,
+ features)
except Exception:
_reraise_translated_image_exception(image_id)
diff --git a/nova/image/s3.py b/nova/image/s3.py
index 9ed060464..d0746922f 100644
--- a/nova/image/s3.py
+++ b/nova/image/s3.py
@@ -288,8 +288,20 @@ class S3ImageService(object):
context.update_store()
log_vars = {'image_location': image_location,
'image_path': image_path}
- metadata['properties']['image_state'] = 'downloading'
- self.service.update(context, image_uuid, metadata)
+
+ def _update_image_state(context, image_uuid, image_state):
+ metadata = {'properties': {'image_state': image_state}}
+ headers = {'x-glance-registry-purge-props': False}
+ self.service.update(context, image_uuid, metadata, None,
+ headers)
+
+ def _update_image_data(context, image_uuid, image_data):
+ metadata = {}
+ headers = {'x-glance-registry-purge-props': False}
+ self.service.update(context, image_uuid, metadata, image_data,
+ headers)
+
+ _update_image_state(context, image_uuid, 'downloading')
try:
parts = []
@@ -310,12 +322,10 @@ class S3ImageService(object):
except Exception:
LOG.exception(_("Failed to download %(image_location)s "
"to %(image_path)s"), log_vars)
- metadata['properties']['image_state'] = 'failed_download'
- self.service.update(context, image_uuid, metadata)
+ _update_image_state(context, image_uuid, 'failed_download')
return
- metadata['properties']['image_state'] = 'decrypting'
- self.service.update(context, image_uuid, metadata)
+ _update_image_state(context, image_uuid, 'decrypting')
try:
hex_key = manifest.find('image/ec2_encrypted_key').text
@@ -329,38 +339,33 @@ class S3ImageService(object):
except Exception:
LOG.exception(_("Failed to decrypt %(image_location)s "
"to %(image_path)s"), log_vars)
- metadata['properties']['image_state'] = 'failed_decrypt'
- self.service.update(context, image_uuid, metadata)
+ _update_image_state(context, image_uuid, 'failed_decrypt')
return
- metadata['properties']['image_state'] = 'untarring'
- self.service.update(context, image_uuid, metadata)
+ _update_image_state(context, image_uuid, 'untarring')
try:
unz_filename = self._untarzip_image(image_path, dec_filename)
except Exception:
LOG.exception(_("Failed to untar %(image_location)s "
"to %(image_path)s"), log_vars)
- metadata['properties']['image_state'] = 'failed_untar'
- self.service.update(context, image_uuid, metadata)
+ _update_image_state(context, image_uuid, 'failed_untar')
return
- metadata['properties']['image_state'] = 'uploading'
- self.service.update(context, image_uuid, metadata)
+ _update_image_state(context, image_uuid, 'uploading')
try:
with open(unz_filename) as image_file:
- self.service.update(context, image_uuid,
- metadata, image_file)
+ _update_image_data(context, image_uuid, image_file)
except Exception:
LOG.exception(_("Failed to upload %(image_location)s "
"to %(image_path)s"), log_vars)
- metadata['properties']['image_state'] = 'failed_upload'
- self.service.update(context, image_uuid, metadata)
+ _update_image_state(context, image_uuid, 'failed_upload')
return
- metadata['properties']['image_state'] = 'available'
- metadata['status'] = 'active'
- self.service.update(context, image_uuid, metadata)
+ metadata = {'status': 'active',
+ 'properties': {'image_state': 'available'}}
+ headers = {'x-glance-registry-purge-props': False}
+ self.service.update(context, image_uuid, metadata, None, headers)
shutil.rmtree(image_path)
diff --git a/nova/tests/glance/stubs.py b/nova/tests/glance/stubs.py
index ccf431b69..e3bdf9dab 100644
--- a/nova/tests/glance/stubs.py
+++ b/nova/tests/glance/stubs.py
@@ -140,7 +140,7 @@ class StubGlanceClient(object):
return self.images[-1]
- def update_image(self, image_id, metadata, data):
+ def update_image(self, image_id, metadata, data, features):
for i, image in enumerate(self.images):
if image['id'] == str(image_id):
if 'id' in metadata:
diff --git a/nova/tests/image/test_s3.py b/nova/tests/image/test_s3.py
index 124666df9..9f078fc49 100644
--- a/nova/tests/image/test_s3.py
+++ b/nova/tests/image/test_s3.py
@@ -15,7 +15,11 @@
# License for the specific language governing permissions and limitations
# under the License.
+import binascii
+import eventlet
+import mox
import os
+import tempfile
from nova import context
import nova.db.api
@@ -58,6 +62,21 @@ ami_manifest_xml = """<?xml version="1.0" ?>
</manifest>
"""
+file_manifest_xml = """<?xml version="1.0" ?>
+<manifest>
+ <image>
+ <ec2_encrypted_key>foo</ec2_encrypted_key>
+ <user_encrypted_key>foo</user_encrypted_key>
+ <ec2_encrypted_iv>foo</ec2_encrypted_iv>
+ <parts count="1">
+ <part index="0">
+ <filename>foo</filename>
+ </part>
+ </parts>
+ </image>
+</manifest>
+"""
+
class TestS3ImageService(test.TestCase):
def setUp(self):
@@ -133,6 +152,46 @@ class TestS3ImageService(test.TestCase):
'no_device': True}]
self.assertEqual(block_device_mapping, expected_bdm)
+ def test_s3_create_is_public(self):
+ metadata = {'properties': {
+ 'image_location': 'mybucket/my.img.manifest.xml'},
+ 'name': 'mybucket/my.img'}
+ handle, tempf = tempfile.mkstemp(dir='/tmp')
+
+ ignore = mox.IgnoreArg()
+ mockobj = self.mox.CreateMockAnything()
+ self.stubs.Set(self.image_service, '_conn', mockobj)
+ mockobj(ignore).AndReturn(mockobj)
+ self.stubs.Set(mockobj, 'get_bucket', mockobj)
+ mockobj(ignore).AndReturn(mockobj)
+ self.stubs.Set(mockobj, 'get_key', mockobj)
+ mockobj(ignore).AndReturn(mockobj)
+ self.stubs.Set(mockobj, 'get_contents_as_string', mockobj)
+ mockobj().AndReturn(file_manifest_xml)
+ self.stubs.Set(self.image_service, '_download_file', mockobj)
+ mockobj(ignore, ignore, ignore).AndReturn(tempf)
+ self.stubs.Set(binascii, 'a2b_hex', mockobj)
+ mockobj(ignore).AndReturn('foo')
+ mockobj(ignore).AndReturn('foo')
+ self.stubs.Set(self.image_service, '_decrypt_image', mockobj)
+ mockobj(ignore, ignore, ignore, ignore, ignore).AndReturn(mockobj)
+ self.stubs.Set(self.image_service, '_untarzip_image', mockobj)
+ mockobj(ignore, ignore).AndReturn(tempf)
+ self.mox.ReplayAll()
+
+ img = self.image_service._s3_create(self.context, metadata)
+ eventlet.sleep()
+ translated = self.image_service._translate_id_to_uuid(context, img)
+ uuid = translated['id']
+ self.glance_service = nova.image.get_default_image_service()
+ updated_image = self.glance_service.update(self.context, uuid,
+ {'is_public': True}, None,
+ {'x-glance-registry-purge-props': False})
+ self.assertTrue(updated_image['is_public'])
+ self.assertEqual(updated_image['status'], 'active')
+ self.assertEqual(updated_image['properties']['image_state'],
+ 'available')
+
def test_s3_malicious_tarballs(self):
self.assertRaises(exception.NovaException,
self.image_service._test_for_malicious_tarball,