Apply expected patch format when updating tags in v2.images
Currently, glanceclient.v2.update builds a patch request that does not match glance API. This patch overrides the default behaviour to customize the patch request with the right format for the API. Co-Authored-By: Steve Lewis <steve.lewis@rackspace.com> Fixes bug 1306774 Change-Id: If0739ac285da1e741bfa40b6c719331a5ce49319
This commit is contained in:
@@ -14,6 +14,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
import json
|
||||||
import jsonpatch
|
import jsonpatch
|
||||||
import six
|
import six
|
||||||
import warlock.model as warlock
|
import warlock.model as warlock
|
||||||
@@ -29,18 +30,35 @@ class SchemaBasedModel(warlock.Model):
|
|||||||
expects.
|
expects.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def _make_custom_patch(self, new, original):
|
||||||
|
if not self.get('tags'):
|
||||||
|
tags_patch = []
|
||||||
|
else:
|
||||||
|
tags_patch = [{"path": "/tags",
|
||||||
|
"value": self.get('tags'),
|
||||||
|
"op": "replace"}]
|
||||||
|
|
||||||
|
patch_string = jsonpatch.make_patch(original, new).to_string()
|
||||||
|
patch = json.loads(patch_string)
|
||||||
|
if not patch:
|
||||||
|
return json.dumps(tags_patch)
|
||||||
|
else:
|
||||||
|
return json.dumps(patch + tags_patch)
|
||||||
|
|
||||||
@warlock.Model.patch.getter
|
@warlock.Model.patch.getter
|
||||||
def patch(self):
|
def patch(self):
|
||||||
"""Return a jsonpatch object representing the delta."""
|
"""Return a jsonpatch object representing the delta."""
|
||||||
original = copy.deepcopy(self.__dict__['__original__'])
|
original = copy.deepcopy(self.__dict__['__original__'])
|
||||||
new = dict(self)
|
new = dict(self)
|
||||||
if self.__dict__['schema']:
|
if self.schema:
|
||||||
for (name, prop) in six.iteritems(self.schema['properties']):
|
for (name, prop) in six.iteritems(self.schema['properties']):
|
||||||
if (name not in original and name in new and
|
if (name not in original and name in new and
|
||||||
prop.get('is_base', True)):
|
prop.get('is_base', True)):
|
||||||
original[name] = None
|
original[name] = None
|
||||||
|
|
||||||
return jsonpatch.make_patch(original, dict(self)).to_string()
|
original['tags'] = None
|
||||||
|
new['tags'] = None
|
||||||
|
return self._make_custom_patch(new, original)
|
||||||
|
|
||||||
|
|
||||||
class SchemaProperty(object):
|
class SchemaProperty(object):
|
||||||
|
@@ -58,7 +58,7 @@ data_fixtures = {
|
|||||||
},
|
},
|
||||||
'color': {'type': 'string', 'is_base': False},
|
'color': {'type': 'string', 'is_base': False},
|
||||||
},
|
},
|
||||||
'additionalProperties': {'type': 'string'}
|
'additionalProperties': {'type': 'string'},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@@ -418,8 +418,9 @@ schema_fixtures = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'color': {'type': 'string', 'is_base': False},
|
'color': {'type': 'string', 'is_base': False},
|
||||||
|
'tags': {'type': 'array'},
|
||||||
},
|
},
|
||||||
'additionalProperties': {'type': 'string'}
|
'additionalProperties': {'type': 'string'},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -889,6 +890,22 @@ class TestController(testtools.TestCase):
|
|||||||
self._empty_get(image_id)
|
self._empty_get(image_id)
|
||||||
])
|
])
|
||||||
|
|
||||||
|
def test_update_tags(self):
|
||||||
|
image_id = 'a2b83adc-888e-11e3-8872-78acc0b951d8'
|
||||||
|
tag_map = {'tags': ['tag01', 'tag02', 'tag03']}
|
||||||
|
|
||||||
|
image = self.controller.update(image_id, **tag_map)
|
||||||
|
|
||||||
|
expected_body = [{'path': '/tags', 'op': 'replace',
|
||||||
|
'value': tag_map['tags']}]
|
||||||
|
expected = [
|
||||||
|
self._empty_get(image_id),
|
||||||
|
self._patch_req(image_id, expected_body),
|
||||||
|
self._empty_get(image_id)
|
||||||
|
]
|
||||||
|
self.assertEqual(expected, self.api.calls)
|
||||||
|
self.assertEqual(image_id, image.id)
|
||||||
|
|
||||||
def test_update_missing_location(self):
|
def test_update_missing_location(self):
|
||||||
image_id = 'a2b83adc-888e-11e3-8872-78acc0b951d8'
|
image_id = 'a2b83adc-888e-11e3-8872-78acc0b951d8'
|
||||||
new_loc = {'url': 'http://spam.com/', 'metadata': {'spam': 'ham'}}
|
new_loc = {'url': 'http://spam.com/', 'metadata': {'spam': 'ham'}}
|
||||||
|
@@ -37,8 +37,11 @@ fixtures = {
|
|||||||
{
|
{
|
||||||
'name': 'image',
|
'name': 'image',
|
||||||
'properties': {
|
'properties': {
|
||||||
'name': {'type': 'string', 'description': 'Name of image'},
|
'name': {'type': 'string',
|
||||||
|
'description': 'Name of image'},
|
||||||
|
'tags': {'type': 'array'}
|
||||||
},
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@@ -51,6 +54,7 @@ _SCHEMA = schemas.Schema({
|
|||||||
'name': {'type': 'string'},
|
'name': {'type': 'string'},
|
||||||
'color': {'type': 'string'},
|
'color': {'type': 'string'},
|
||||||
'shape': {'type': 'string', 'is_base': False},
|
'shape': {'type': 'string', 'is_base': False},
|
||||||
|
'tags': {'type': 'array'}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -99,7 +103,8 @@ class TestController(testtools.TestCase):
|
|||||||
def test_get_schema(self):
|
def test_get_schema(self):
|
||||||
schema = self.controller.get('image')
|
schema = self.controller.get('image')
|
||||||
self.assertEqual('image', schema.name)
|
self.assertEqual('image', schema.name)
|
||||||
self.assertEqual(['name'], [p.name for p in schema.properties])
|
self.assertEqual(['name', 'tags'],
|
||||||
|
[p.name for p in schema.properties])
|
||||||
|
|
||||||
|
|
||||||
class TestSchemaBasedModel(testtools.TestCase):
|
class TestSchemaBasedModel(testtools.TestCase):
|
||||||
@@ -195,3 +200,14 @@ class TestSchemaBasedModel(testtools.TestCase):
|
|||||||
patch = original.patch
|
patch = original.patch
|
||||||
expected = '[{"path": "/shape", "value": "square", "op": "replace"}]'
|
expected = '[{"path": "/shape", "value": "square", "op": "replace"}]'
|
||||||
self.assertTrue(compare_json_patches(patch, expected))
|
self.assertTrue(compare_json_patches(patch, expected))
|
||||||
|
|
||||||
|
def test_patch_should_replace_tags(self):
|
||||||
|
obj = {'name': 'fred', }
|
||||||
|
|
||||||
|
original = self.model(obj)
|
||||||
|
original['tags'] = ['tag1', 'tag2']
|
||||||
|
|
||||||
|
patch = original.patch
|
||||||
|
expected = '[{"path": "/tags", "value": ["tag1", "tag2"], ' \
|
||||||
|
'"op": "replace"}]'
|
||||||
|
self.assertTrue(compare_json_patches(patch, expected))
|
||||||
|
Reference in New Issue
Block a user