diff options
author | Bartosz Fic <bartosz.fic@intel.com> | 2014-10-08 10:47:31 +0200 |
---|---|---|
committer | Nikhil Komawar <nikhilskomawar@gmail.com> | 2014-10-09 09:48:15 -0400 |
commit | 6b0c7ed29ec1e716e704e19112d9ee24553faf19 (patch) | |
tree | 4fffd6b8a6086c63bca3c7757cde65495cfdeb7e | |
parent | 9eff67b8fff812acdbf787f2dc119761f3cf3153 (diff) | |
download | glance-6b0c7ed29ec1e716e704e19112d9ee24553faf19.tar.gz |
GET property which name includes resource type prefix
Currently GET call to API to retrieve property details ends with
404 error when property name includes resource type prefix.
This patch extends show method to take filters as a parameter.
If 'resource_type' is included in filters then the prefix of included
resource type is removed from property name. This enables user to look
for property name starting with prefix that comes from associated
resource type.
Change-Id: I3c4d96fbc9ce15016631017bf76089c338ac3cdc
Closes-Bug: #1367564
DocImpact
Co-Authored-By: Bartosz Fic <bartosz.fic@intel.com>
Co-Authored-By: Pawel Koniszewski <pawel.koniszewski@intel.com>
-rw-r--r-- | etc/policy.json | 1 | ||||
-rw-r--r-- | glance/api/authorization.py | 4 | ||||
-rw-r--r-- | glance/api/policy.py | 4 | ||||
-rw-r--r-- | glance/api/v2/metadef_properties.py | 25 | ||||
-rw-r--r-- | glance/db/__init__.py | 13 | ||||
-rw-r--r-- | glance/domain/proxy.py | 4 | ||||
-rw-r--r-- | glance/tests/functional/v2/test_metadef_properties.py | 37 | ||||
-rw-r--r-- | glance/tests/unit/v2/test_metadef_resources.py | 31 |
8 files changed, 113 insertions, 6 deletions
diff --git a/etc/policy.json b/etc/policy.json index e72363f6d..325f00b21 100644 --- a/etc/policy.json +++ b/etc/policy.json @@ -41,6 +41,7 @@ "add_metadef_object":"", "list_metadef_resource_types":"", + "get_metadef_resource_type":"", "add_metadef_resource_type_association":"", "get_metadef_property":"", diff --git a/glance/api/authorization.py b/glance/api/authorization.py index ea8d1d494..149ff55a7 100644 --- a/glance/api/authorization.py +++ b/glance/api/authorization.py @@ -723,6 +723,10 @@ class MetadefResourceTypeRepoProxy( return [proxy_meta_resource_type(self.context, meta_resource_type) for meta_resource_type in meta_resource_types] + def get(self, *args, **kwargs): + meta_resource_type = self.meta_resource_type_repo.get(*args, **kwargs) + return proxy_meta_resource_type(self.context, meta_resource_type) + #Metadef namespace properties classes def is_namespace_property_mutable(context, namespace_property): diff --git a/glance/api/policy.py b/glance/api/policy.py index a557290d0..0bc8d5651 100644 --- a/glance/api/policy.py +++ b/glance/api/policy.py @@ -580,6 +580,10 @@ class MetadefResourceTypeRepoProxy( self.policy.enforce(self.context, 'list_metadef_resource_types', {}) return super(MetadefResourceTypeRepoProxy, self).list(*args, **kwargs) + def get(self, *args, **kwargs): + self.policy.enforce(self.context, 'get_metadef_resource_type', {}) + return super(MetadefResourceTypeRepoProxy, self).get(*args, **kwargs) + def add(self, resource_type): self.policy.enforce(self.context, 'add_metadef_resource_type_association', {}) diff --git a/glance/api/v2/metadef_properties.py b/glance/api/v2/metadef_properties.py index 06787e193..65097ea81 100644 --- a/glance/api/v2/metadef_properties.py +++ b/glance/api/v2/metadef_properties.py @@ -79,8 +79,24 @@ class NamespacePropertiesController(object): raise webob.exc.HTTPInternalServerError() return namespace_properties - def show(self, req, namespace, property_name): + def show(self, req, namespace, property_name, filters=None): try: + if filters and filters['resource_type']: + rs_repo = self.gateway.get_metadef_resource_type_repo( + req.context) + db_resource_type = rs_repo.get(filters['resource_type'], + namespace) + prefix = db_resource_type.prefix + if prefix and property_name.startswith(prefix): + property_name = property_name[len(prefix):] + else: + msg = (_("Property %(property_name)s does not start " + "with the expected resource type association " + "prefix of '%(prefix)s'.") + % {'property_name': property_name, + 'prefix': prefix}) + raise exception.NotFound(msg) + prop_repo = self.gateway.get_metadef_property_repo(req.context) db_property = prop_repo.get(namespace, property_name) property = self._to_model(db_property) @@ -185,6 +201,13 @@ class RequestDeserializer(wsgi.JSONRequestDeserializer): property_type = fromjson(PropertyType, body) return dict(property_type=property_type) + def show(self, request): + params = request.params.copy() + query_params = { + 'filters': params + } + return query_params + class ResponseSerializer(wsgi.JSONResponseSerializer): def __init__(self, schema=None): diff --git a/glance/db/__init__.py b/glance/db/__init__.py index fd0b84cfa..1a80044cd 100644 --- a/glance/db/__init__.py +++ b/glance/db/__init__.py @@ -626,6 +626,19 @@ class MetadefResourceTypeRepo(object): self._format_resource_type_to_db(resource_type) ) + def get(self, resource_type, namespace): + namespace_entity = self.meta_namespace_repo.get(namespace) + db_resource_type = ( + self.db_api. + metadef_resource_type_association_get( + self.context, + namespace, + resource_type + ) + ) + return self._format_resource_type_from_db(db_resource_type, + namespace_entity) + def list(self, filters=None): namespace = filters['namespace'] if namespace: diff --git a/glance/domain/proxy.py b/glance/domain/proxy.py index 7a1667bc3..5a91d343d 100644 --- a/glance/domain/proxy.py +++ b/glance/domain/proxy.py @@ -367,6 +367,10 @@ class MetadefResourceTypeRepo(object): self.base.add(self.resource_type_proxy_helper.unproxy( meta_resource_type)) + def get(self, *args, **kwargs): + resource_type = self.base.get(*args, **kwargs) + return self.resource_type_proxy_helper.proxy(resource_type) + def list(self, *args, **kwargs): resource_types = self.base.list(*args, **kwargs) return [self.resource_type_proxy_helper.proxy(resource_type) diff --git a/glance/tests/functional/v2/test_metadef_properties.py b/glance/tests/functional/v2/test_metadef_properties.py index 7983cf253..b5e791b69 100644 --- a/glance/tests/functional/v2/test_metadef_properties.py +++ b/glance/tests/functional/v2/test_metadef_properties.py @@ -55,15 +55,22 @@ class TestNamespaceProperties(functional.FunctionalTest): path = self._url('/v2/metadefs/namespaces') headers = self._headers({'content-type': 'application/json'}) namespace_name = 'MyNamespace' + resource_type_name = 'MyResourceType' + resource_type_prefix = 'MyPrefix' data = jsonutils.dumps({ "namespace": namespace_name, "display_name": "My User Friendly Namespace", "description": "My description", "visibility": "public", "protected": False, - "owner": "The Test Owner" - } - ) + "owner": "The Test Owner", + "resource_type_associations": [ + { + "name": resource_type_name, + "prefix": resource_type_prefix + } + ] + }) response = requests.post(path, headers=headers, data=data) self.assertEqual(201, response.status_code) @@ -105,6 +112,30 @@ class TestNamespaceProperties(functional.FunctionalTest): self.assertEqual(100, property_object['minimum']) self.assertEqual(30000369, property_object['maximum']) + # Get the property with specific resource type association + path = self._url('/v2/metadefs/namespaces/%s/properties/%s%s' % ( + namespace_name, property_name, '='.join(['?resource_type', + resource_type_name]))) + response = requests.get(path, headers=self._headers()) + self.assertEqual(404, response.status_code) + + # Get the property with prefix and specific resource type association + property_name_with_prefix = ''.join([resource_type_prefix, + property_name]) + path = self._url('/v2/metadefs/namespaces/%s/properties/%s%s' % ( + namespace_name, property_name_with_prefix, '='.join([ + '?resource_type', resource_type_name]))) + response = requests.get(path, headers=self._headers()) + self.assertEqual(200, response.status_code) + property_object = jsonutils.loads(response.text) + self.assertEqual("integer", property_object['type']) + self.assertEqual("property1", property_object['title']) + self.assertEqual("property1 description", property_object[ + 'description']) + self.assertEqual('100', property_object['default']) + self.assertEqual(100, property_object['minimum']) + self.assertEqual(30000369, property_object['maximum']) + # Returned property should match the created property property_object = jsonutils.loads(response.text) checked_keys = set([ diff --git a/glance/tests/unit/v2/test_metadef_resources.py b/glance/tests/unit/v2/test_metadef_resources.py index 87aff8a08..9334fe239 100644 --- a/glance/tests/unit/v2/test_metadef_resources.py +++ b/glance/tests/unit/v2/test_metadef_resources.py @@ -38,6 +38,7 @@ NAMESPACE6 = 'Namespace6' PROPERTY1 = 'Property1' PROPERTY2 = 'Property2' PROPERTY3 = 'Property3' +PROPERTY4 = 'Property4' OBJECT1 = 'Object1' OBJECT2 = 'Object2' @@ -46,12 +47,15 @@ OBJECT3 = 'Object3' RESOURCE_TYPE1 = 'ResourceType1' RESOURCE_TYPE2 = 'ResourceType2' RESOURCE_TYPE3 = 'ResourceType3' +RESOURCE_TYPE4 = 'ResourceType4' TENANT1 = '6838eb7b-6ded-434a-882c-b344c77fe8df' TENANT2 = '2c014f32-55eb-467d-8fcb-4bd706012f81' TENANT3 = '5a3e60e8-cfa9-4a9e-a90a-62b42cea92b8' TENANT4 = 'c6c87f25-8a94-47ed-8c83-053c25f42df4' +PREFIX1 = 'pref' + def _db_namespace_fixture(namespace, **kwargs): obj = { @@ -146,6 +150,7 @@ class TestMetadefsControllers(base.IsolatedUnitTest): (NAMESPACE3, _db_property_fixture(PROPERTY1)), (NAMESPACE3, _db_property_fixture(PROPERTY2)), (NAMESPACE1, _db_property_fixture(PROPERTY1)), + (NAMESPACE6, _db_property_fixture(PROPERTY4)), ] [self.db.metadef_property_create(req.context, namespace, property) for namespace, property in self.properties] @@ -165,6 +170,7 @@ class TestMetadefsControllers(base.IsolatedUnitTest): self.resource_types = [ _db_resource_type_fixture(RESOURCE_TYPE1), _db_resource_type_fixture(RESOURCE_TYPE2), + _db_resource_type_fixture(RESOURCE_TYPE4), ] [self.db.metadef_resource_type_create(req.context, resource_type) for resource_type in self.resource_types] @@ -176,6 +182,8 @@ class TestMetadefsControllers(base.IsolatedUnitTest): (NAMESPACE3, _db_namespace_resource_type_fixture(RESOURCE_TYPE1)), (NAMESPACE2, _db_namespace_resource_type_fixture(RESOURCE_TYPE1)), (NAMESPACE2, _db_namespace_resource_type_fixture(RESOURCE_TYPE2)), + (NAMESPACE6, _db_namespace_resource_type_fixture(RESOURCE_TYPE4, + prefix=PREFIX1)), ] [self.db.metadef_resource_type_association_create(req.context, namespace, @@ -526,6 +534,25 @@ class TestMetadefsControllers(base.IsolatedUnitTest): output = self.property_controller.show(request, NAMESPACE3, PROPERTY1) self.assertEqual(output.name, PROPERTY1) + def test_property_show_specific_resource_type(self): + request = unit_test_utils.get_fake_request() + output = self.property_controller.show( + request, NAMESPACE6, ''.join([PREFIX1, PROPERTY4]), + filters={'resource_type': RESOURCE_TYPE4}) + self.assertEqual(output.name, PROPERTY4) + + def test_property_show_prefix_mismatch(self): + request = unit_test_utils.get_fake_request() + self.assertRaises(webob.exc.HTTPNotFound, + self.property_controller.show, request, NAMESPACE6, + PROPERTY4, filters={'resource_type': RESOURCE_TYPE4}) + + def test_property_show_non_existing_resource_type(self): + request = unit_test_utils.get_fake_request() + self.assertRaises(webob.exc.HTTPNotFound, + self.property_controller.show, request, NAMESPACE2, + PROPERTY1, filters={'resource_type': 'test'}) + def test_property_show_non_existing(self): request = unit_test_utils.get_fake_request() self.assertRaises(webob.exc.HTTPNotFound, @@ -958,10 +985,10 @@ class TestMetadefsControllers(base.IsolatedUnitTest): request = unit_test_utils.get_fake_request() output = self.rt_controller.index(request) - self.assertEqual(2, len(output.resource_types)) + self.assertEqual(3, len(output.resource_types)) actual = set([type.name for type in output.resource_types]) - expected = set([RESOURCE_TYPE1, RESOURCE_TYPE2]) + expected = set([RESOURCE_TYPE1, RESOURCE_TYPE2, RESOURCE_TYPE4]) self.assertEqual(actual, expected) def test_resource_type_show(self): |