Instance metadata now functionally works (completely to spec) through OSAPI
This commit is contained in:
commit
9d43baf7d3
@ -57,18 +57,12 @@ class Controller(object):
|
||||
|
||||
context = req.environ['nova.context']
|
||||
|
||||
try:
|
||||
self.compute_api.update_or_create_instance_metadata(context,
|
||||
server_id,
|
||||
metadata)
|
||||
except exception.InstanceNotFound:
|
||||
msg = _('Server does not exist')
|
||||
raise exc.HTTPNotFound(explanation=msg)
|
||||
new_metadata = self._update_instance_metadata(context,
|
||||
server_id,
|
||||
metadata,
|
||||
delete=False)
|
||||
|
||||
except quota.QuotaError as error:
|
||||
self._handle_quota_error(error)
|
||||
|
||||
return body
|
||||
return {'metadata': new_metadata}
|
||||
|
||||
def update(self, req, server_id, id, body):
|
||||
try:
|
||||
@ -78,19 +72,22 @@ class Controller(object):
|
||||
raise exc.HTTPBadRequest(explanation=expl)
|
||||
|
||||
try:
|
||||
meta_value = meta_item.pop(id)
|
||||
meta_value = meta_item[id]
|
||||
except (AttributeError, KeyError):
|
||||
expl = _('Request body and URI mismatch')
|
||||
raise exc.HTTPBadRequest(explanation=expl)
|
||||
|
||||
if len(meta_item) > 0:
|
||||
if len(meta_item) > 1:
|
||||
expl = _('Request body contains too many items')
|
||||
raise exc.HTTPBadRequest(explanation=expl)
|
||||
|
||||
context = req.environ['nova.context']
|
||||
self._set_instance_metadata(context, server_id, meta_item)
|
||||
self._update_instance_metadata(context,
|
||||
server_id,
|
||||
meta_item,
|
||||
delete=False)
|
||||
|
||||
return {'meta': {id: meta_value}}
|
||||
return {'meta': meta_item}
|
||||
|
||||
def update_all(self, req, server_id, body):
|
||||
try:
|
||||
@ -100,20 +97,26 @@ class Controller(object):
|
||||
raise exc.HTTPBadRequest(explanation=expl)
|
||||
|
||||
context = req.environ['nova.context']
|
||||
self._set_instance_metadata(context, server_id, metadata)
|
||||
new_metadata = self._update_instance_metadata(context,
|
||||
server_id,
|
||||
metadata,
|
||||
delete=True)
|
||||
|
||||
return {'metadata': metadata}
|
||||
return {'metadata': new_metadata}
|
||||
|
||||
def _set_instance_metadata(self, context, server_id, metadata):
|
||||
def _update_instance_metadata(self, context, server_id, metadata,
|
||||
delete=False):
|
||||
try:
|
||||
self.compute_api.update_or_create_instance_metadata(context,
|
||||
server_id,
|
||||
metadata)
|
||||
return self.compute_api.update_instance_metadata(context,
|
||||
server_id,
|
||||
metadata,
|
||||
delete)
|
||||
|
||||
except exception.InstanceNotFound:
|
||||
msg = _('Server does not exist')
|
||||
raise exc.HTTPNotFound(explanation=msg)
|
||||
|
||||
except ValueError:
|
||||
except (ValueError, AttributeError):
|
||||
msg = _("Malformed request body")
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
@ -138,12 +141,12 @@ class Controller(object):
|
||||
metadata = self._get_metadata(context, server_id)
|
||||
|
||||
try:
|
||||
meta_key = metadata[id]
|
||||
meta_value = metadata[id]
|
||||
except KeyError:
|
||||
msg = _("Metadata item was not found")
|
||||
raise exc.HTTPNotFound(explanation=msg)
|
||||
|
||||
self.compute_api.delete_instance_metadata(context, server_id, meta_key)
|
||||
self.compute_api.delete_instance_metadata(context, server_id, id)
|
||||
|
||||
def _handle_quota_error(self, error):
|
||||
"""Reraise quota errors as api-specific http exceptions."""
|
||||
|
@ -1214,11 +1214,20 @@ class API(base.Base):
|
||||
"""Delete the given metadata item from an instance."""
|
||||
self.db.instance_metadata_delete(context, instance_id, key)
|
||||
|
||||
def update_or_create_instance_metadata(self, context, instance_id,
|
||||
metadata):
|
||||
"""Updates or creates instance metadata."""
|
||||
combined_metadata = self.get_instance_metadata(context, instance_id)
|
||||
combined_metadata.update(metadata)
|
||||
self._check_metadata_properties_quota(context, combined_metadata)
|
||||
self.db.instance_metadata_update_or_create(context, instance_id,
|
||||
metadata)
|
||||
def update_instance_metadata(self, context, instance_id,
|
||||
metadata, delete=False):
|
||||
"""Updates or creates instance metadata.
|
||||
|
||||
If delete is True, metadata items that are not specified in the
|
||||
`metadata` argument will be deleted.
|
||||
|
||||
"""
|
||||
if delete:
|
||||
_metadata = metadata
|
||||
else:
|
||||
_metadata = self.get_instance_metadata(context, instance_id)
|
||||
_metadata.update(metadata)
|
||||
|
||||
self._check_metadata_properties_quota(context, _metadata)
|
||||
self.db.instance_metadata_update(context, instance_id, _metadata, True)
|
||||
return _metadata
|
||||
|
@ -1381,9 +1381,9 @@ def instance_metadata_delete(context, instance_id, key):
|
||||
IMPL.instance_metadata_delete(context, instance_id, key)
|
||||
|
||||
|
||||
def instance_metadata_update_or_create(context, instance_id, metadata):
|
||||
"""Create or update instance metadata."""
|
||||
IMPL.instance_metadata_update_or_create(context, instance_id, metadata)
|
||||
def instance_metadata_update(context, instance_id, metadata, delete):
|
||||
"""Update metadata if it exists, otherwise create it."""
|
||||
IMPL.instance_metadata_update(context, instance_id, metadata, delete)
|
||||
|
||||
|
||||
####################
|
||||
|
@ -1346,9 +1346,10 @@ def instance_update(context, instance_id, values):
|
||||
session = get_session()
|
||||
metadata = values.get('metadata')
|
||||
if metadata is not None:
|
||||
instance_metadata_delete_all(context, instance_id)
|
||||
instance_metadata_update_or_create(context, instance_id,
|
||||
values.pop('metadata'))
|
||||
instance_metadata_update(context,
|
||||
instance_id,
|
||||
values.pop('metadata'),
|
||||
delete=True)
|
||||
with session.begin():
|
||||
if utils.is_uuid_like(instance_id):
|
||||
instance_ref = instance_get_by_uuid(context, instance_id,
|
||||
@ -3218,21 +3219,37 @@ def instance_metadata_get_item(context, instance_id, key, session=None):
|
||||
|
||||
@require_context
|
||||
@require_instance_exists
|
||||
def instance_metadata_update_or_create(context, instance_id, metadata):
|
||||
def instance_metadata_update(context, instance_id, metadata, delete):
|
||||
session = get_session()
|
||||
|
||||
original_metadata = instance_metadata_get(context, instance_id)
|
||||
# Set existing metadata to deleted if delete argument is True
|
||||
if delete:
|
||||
original_metadata = instance_metadata_get(context, instance_id)
|
||||
for meta_key, meta_value in original_metadata.iteritems():
|
||||
if meta_key not in metadata:
|
||||
meta_ref = instance_metadata_get_item(context, instance_id,
|
||||
meta_key, session)
|
||||
meta_ref.update({'deleted': True})
|
||||
meta_ref.save(session=session)
|
||||
|
||||
meta_ref = None
|
||||
for key, value in metadata.iteritems():
|
||||
|
||||
# Now update all existing items with new values, or create new meta objects
|
||||
for meta_key, meta_value in metadata.iteritems():
|
||||
|
||||
# update the value whether it exists or not
|
||||
item = {"value": meta_value}
|
||||
|
||||
try:
|
||||
meta_ref = instance_metadata_get_item(context, instance_id, key,
|
||||
session)
|
||||
meta_ref = instance_metadata_get_item(context, instance_id,
|
||||
meta_key, session)
|
||||
|
||||
# if the item doesn't exist, we also need to set key and instance_id
|
||||
except exception.InstanceMetadataNotFound, e:
|
||||
meta_ref = models.InstanceMetadata()
|
||||
meta_ref.update({"key": key, "value": value,
|
||||
"instance_id": instance_id,
|
||||
"deleted": False})
|
||||
item.update({"key": meta_key, "instance_id": instance_id})
|
||||
|
||||
meta_ref.update(item)
|
||||
meta_ref.save(session=session)
|
||||
|
||||
return metadata
|
||||
|
@ -29,11 +29,11 @@ import nova.wsgi
|
||||
FLAGS = flags.FLAGS
|
||||
|
||||
|
||||
def return_create_instance_metadata_max(context, server_id, metadata):
|
||||
def return_create_instance_metadata_max(context, server_id, metadata, delete):
|
||||
return stub_max_server_metadata()
|
||||
|
||||
|
||||
def return_create_instance_metadata(context, server_id, metadata):
|
||||
def return_create_instance_metadata(context, server_id, metadata, delete):
|
||||
return stub_server_metadata()
|
||||
|
||||
|
||||
@ -202,21 +202,30 @@ class ServerMetaDataTest(test.TestCase):
|
||||
self.assertEqual(404, res.status_int)
|
||||
|
||||
def test_create(self):
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_get',
|
||||
return_server_metadata)
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update',
|
||||
return_create_instance_metadata)
|
||||
req = webob.Request.blank('/v1.1/servers/1/metadata')
|
||||
req.method = 'POST'
|
||||
req.content_type = "application/json"
|
||||
expected = {"metadata": {"key1": "value1"}}
|
||||
req.body = json.dumps(expected)
|
||||
input = {"metadata": {"key9": "value9"}}
|
||||
req.body = json.dumps(input)
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
|
||||
self.assertEqual(200, res.status_int)
|
||||
res_dict = json.loads(res.body)
|
||||
self.assertEqual(expected, res_dict)
|
||||
input['metadata'].update({
|
||||
"key1": "value1",
|
||||
"key2": "value2",
|
||||
"key3":"value3",
|
||||
})
|
||||
self.assertEqual(input, res_dict)
|
||||
|
||||
def test_create_xml(self):
|
||||
self.stubs.Set(nova.db.api, "instance_metadata_update_or_create",
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_get',
|
||||
return_server_metadata)
|
||||
self.stubs.Set(nova.db.api, "instance_metadata_update",
|
||||
return_create_instance_metadata)
|
||||
req = webob.Request.blank("/v1.1/servers/1/metadata")
|
||||
req.method = "POST"
|
||||
@ -225,22 +234,29 @@ class ServerMetaDataTest(test.TestCase):
|
||||
|
||||
request_metadata = minidom.parseString("""
|
||||
<metadata xmlns="http://docs.openstack.org/compute/api/v1.1">
|
||||
<meta key="key3">value3</meta>
|
||||
<meta key="key2">value2</meta>
|
||||
<meta key="key1">value1</meta>
|
||||
<meta key="key5">value5</meta>
|
||||
</metadata>
|
||||
""".replace(" ", "").replace("\n", ""))
|
||||
|
||||
req.body = str(request_metadata.toxml())
|
||||
response = req.get_response(fakes.wsgi_app())
|
||||
|
||||
expected_metadata = minidom.parseString("""
|
||||
<metadata xmlns="http://docs.openstack.org/compute/api/v1.1">
|
||||
<meta key="key3">value3</meta>
|
||||
<meta key="key2">value2</meta>
|
||||
<meta key="key1">value1</meta>
|
||||
<meta key="key5">value5</meta>
|
||||
</metadata>
|
||||
""".replace(" ", "").replace("\n", ""))
|
||||
|
||||
self.assertEqual(200, response.status_int)
|
||||
actual_metadata = minidom.parseString(response.body)
|
||||
|
||||
self.assertEqual(request_metadata.toxml(), actual_metadata.toxml())
|
||||
self.assertEqual(expected_metadata.toxml(), actual_metadata.toxml())
|
||||
|
||||
def test_create_empty_body(self):
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update',
|
||||
return_create_instance_metadata)
|
||||
req = webob.Request.blank('/v1.1/servers/1/metadata')
|
||||
req.method = 'POST'
|
||||
@ -258,7 +274,7 @@ class ServerMetaDataTest(test.TestCase):
|
||||
self.assertEqual(404, res.status_int)
|
||||
|
||||
def test_update_all(self):
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update',
|
||||
return_create_instance_metadata)
|
||||
req = webob.Request.blank('/v1.1/servers/1/metadata')
|
||||
req.method = 'PUT'
|
||||
@ -276,7 +292,7 @@ class ServerMetaDataTest(test.TestCase):
|
||||
self.assertEqual(expected, res_dict)
|
||||
|
||||
def test_update_all_empty_container(self):
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update',
|
||||
return_create_instance_metadata)
|
||||
req = webob.Request.blank('/v1.1/servers/1/metadata')
|
||||
req.method = 'PUT'
|
||||
@ -289,7 +305,7 @@ class ServerMetaDataTest(test.TestCase):
|
||||
self.assertEqual(expected, res_dict)
|
||||
|
||||
def test_update_all_malformed_container(self):
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update',
|
||||
return_create_instance_metadata)
|
||||
req = webob.Request.blank('/v1.1/servers/1/metadata')
|
||||
req.method = 'PUT'
|
||||
@ -300,7 +316,7 @@ class ServerMetaDataTest(test.TestCase):
|
||||
self.assertEqual(400, res.status_int)
|
||||
|
||||
def test_update_all_malformed_data(self):
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update',
|
||||
return_create_instance_metadata)
|
||||
req = webob.Request.blank('/v1.1/servers/1/metadata')
|
||||
req.method = 'PUT'
|
||||
@ -320,7 +336,7 @@ class ServerMetaDataTest(test.TestCase):
|
||||
self.assertEqual(404, res.status_int)
|
||||
|
||||
def test_update_item(self):
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update',
|
||||
return_create_instance_metadata)
|
||||
req = webob.Request.blank('/v1.1/servers/1/metadata/key1')
|
||||
req.method = 'PUT'
|
||||
@ -334,7 +350,7 @@ class ServerMetaDataTest(test.TestCase):
|
||||
self.assertEqual(expected, res_dict)
|
||||
|
||||
def test_update_item_xml(self):
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update',
|
||||
return_create_instance_metadata)
|
||||
req = webob.Request.blank('/v1.1/servers/1/metadata/key9')
|
||||
req.method = 'PUT'
|
||||
@ -361,7 +377,7 @@ class ServerMetaDataTest(test.TestCase):
|
||||
self.assertEqual(404, res.status_int)
|
||||
|
||||
def test_update_item_empty_body(self):
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update',
|
||||
return_create_instance_metadata)
|
||||
req = webob.Request.blank('/v1.1/servers/1/metadata/key1')
|
||||
req.method = 'PUT'
|
||||
@ -370,7 +386,7 @@ class ServerMetaDataTest(test.TestCase):
|
||||
self.assertEqual(400, res.status_int)
|
||||
|
||||
def test_update_item_too_many_keys(self):
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update',
|
||||
return_create_instance_metadata)
|
||||
req = webob.Request.blank('/v1.1/servers/1/metadata/key1')
|
||||
req.method = 'PUT'
|
||||
@ -380,7 +396,7 @@ class ServerMetaDataTest(test.TestCase):
|
||||
self.assertEqual(400, res.status_int)
|
||||
|
||||
def test_update_item_body_uri_mismatch(self):
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update',
|
||||
return_create_instance_metadata)
|
||||
req = webob.Request.blank('/v1.1/servers/1/metadata/bad')
|
||||
req.method = 'PUT'
|
||||
@ -390,7 +406,7 @@ class ServerMetaDataTest(test.TestCase):
|
||||
self.assertEqual(400, res.status_int)
|
||||
|
||||
def test_too_many_metadata_items_on_create(self):
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update',
|
||||
return_create_instance_metadata)
|
||||
data = {"metadata": {}}
|
||||
for num in range(FLAGS.quota_metadata_items + 1):
|
||||
@ -404,7 +420,7 @@ class ServerMetaDataTest(test.TestCase):
|
||||
self.assertEqual(400, res.status_int)
|
||||
|
||||
def test_to_many_metadata_items_on_update_item(self):
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update_or_create',
|
||||
self.stubs.Set(nova.db.api, 'instance_metadata_update',
|
||||
return_create_instance_metadata_max)
|
||||
req = webob.Request.blank('/v1.1/servers/1/metadata/key1')
|
||||
req.method = 'PUT'
|
||||
|
Loading…
Reference in New Issue
Block a user