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>
This commit is contained in:
Bartosz Fic 2014-10-08 10:47:31 +02:00
parent 2530cfa81e
commit 8b9f9836f8
8 changed files with 113 additions and 6 deletions

View File

@ -41,6 +41,7 @@
"add_metadef_object":"", "add_metadef_object":"",
"list_metadef_resource_types":"", "list_metadef_resource_types":"",
"get_metadef_resource_type":"",
"add_metadef_resource_type_association":"", "add_metadef_resource_type_association":"",
"get_metadef_property":"", "get_metadef_property":"",

View File

@ -723,6 +723,10 @@ class MetadefResourceTypeRepoProxy(
return [proxy_meta_resource_type(self.context, meta_resource_type) for return [proxy_meta_resource_type(self.context, meta_resource_type) for
meta_resource_type in meta_resource_types] 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 # Metadef namespace properties classes
def is_namespace_property_mutable(context, namespace_property): def is_namespace_property_mutable(context, namespace_property):

View File

@ -580,6 +580,10 @@ class MetadefResourceTypeRepoProxy(
self.policy.enforce(self.context, 'list_metadef_resource_types', {}) self.policy.enforce(self.context, 'list_metadef_resource_types', {})
return super(MetadefResourceTypeRepoProxy, self).list(*args, **kwargs) 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): def add(self, resource_type):
self.policy.enforce(self.context, self.policy.enforce(self.context,
'add_metadef_resource_type_association', {}) 'add_metadef_resource_type_association', {})

View File

@ -79,8 +79,24 @@ class NamespacePropertiesController(object):
raise webob.exc.HTTPInternalServerError() raise webob.exc.HTTPInternalServerError()
return namespace_properties return namespace_properties
def show(self, req, namespace, property_name): def show(self, req, namespace, property_name, filters=None):
try: 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) prop_repo = self.gateway.get_metadef_property_repo(req.context)
db_property = prop_repo.get(namespace, property_name) db_property = prop_repo.get(namespace, property_name)
property = self._to_model(db_property) property = self._to_model(db_property)
@ -185,6 +201,13 @@ class RequestDeserializer(wsgi.JSONRequestDeserializer):
property_type = fromjson(PropertyType, body) property_type = fromjson(PropertyType, body)
return dict(property_type=property_type) 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): class ResponseSerializer(wsgi.JSONResponseSerializer):
def __init__(self, schema=None): def __init__(self, schema=None):

View File

@ -628,6 +628,19 @@ class MetadefResourceTypeRepo(object):
self._format_resource_type_to_db(resource_type) 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): def list(self, filters=None):
namespace = filters['namespace'] namespace = filters['namespace']
if namespace: if namespace:

View File

@ -367,6 +367,10 @@ class MetadefResourceTypeRepo(object):
self.base.add(self.resource_type_proxy_helper.unproxy( self.base.add(self.resource_type_proxy_helper.unproxy(
meta_resource_type)) 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): def list(self, *args, **kwargs):
resource_types = self.base.list(*args, **kwargs) resource_types = self.base.list(*args, **kwargs)
return [self.resource_type_proxy_helper.proxy(resource_type) return [self.resource_type_proxy_helper.proxy(resource_type)

View File

@ -55,15 +55,22 @@ class TestNamespaceProperties(functional.FunctionalTest):
path = self._url('/v2/metadefs/namespaces') path = self._url('/v2/metadefs/namespaces')
headers = self._headers({'content-type': 'application/json'}) headers = self._headers({'content-type': 'application/json'})
namespace_name = 'MyNamespace' namespace_name = 'MyNamespace'
resource_type_name = 'MyResourceType'
resource_type_prefix = 'MyPrefix'
data = jsonutils.dumps({ data = jsonutils.dumps({
"namespace": namespace_name, "namespace": namespace_name,
"display_name": "My User Friendly Namespace", "display_name": "My User Friendly Namespace",
"description": "My description", "description": "My description",
"visibility": "public", "visibility": "public",
"protected": False, "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) response = requests.post(path, headers=headers, data=data)
self.assertEqual(201, response.status_code) self.assertEqual(201, response.status_code)
@ -105,6 +112,30 @@ class TestNamespaceProperties(functional.FunctionalTest):
self.assertEqual(100, property_object['minimum']) self.assertEqual(100, property_object['minimum'])
self.assertEqual(30000369, property_object['maximum']) 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 # Returned property should match the created property
property_object = jsonutils.loads(response.text) property_object = jsonutils.loads(response.text)
checked_keys = set([ checked_keys = set([

View File

@ -38,6 +38,7 @@ NAMESPACE6 = 'Namespace6'
PROPERTY1 = 'Property1' PROPERTY1 = 'Property1'
PROPERTY2 = 'Property2' PROPERTY2 = 'Property2'
PROPERTY3 = 'Property3' PROPERTY3 = 'Property3'
PROPERTY4 = 'Property4'
OBJECT1 = 'Object1' OBJECT1 = 'Object1'
OBJECT2 = 'Object2' OBJECT2 = 'Object2'
@ -46,12 +47,15 @@ OBJECT3 = 'Object3'
RESOURCE_TYPE1 = 'ResourceType1' RESOURCE_TYPE1 = 'ResourceType1'
RESOURCE_TYPE2 = 'ResourceType2' RESOURCE_TYPE2 = 'ResourceType2'
RESOURCE_TYPE3 = 'ResourceType3' RESOURCE_TYPE3 = 'ResourceType3'
RESOURCE_TYPE4 = 'ResourceType4'
TENANT1 = '6838eb7b-6ded-434a-882c-b344c77fe8df' TENANT1 = '6838eb7b-6ded-434a-882c-b344c77fe8df'
TENANT2 = '2c014f32-55eb-467d-8fcb-4bd706012f81' TENANT2 = '2c014f32-55eb-467d-8fcb-4bd706012f81'
TENANT3 = '5a3e60e8-cfa9-4a9e-a90a-62b42cea92b8' TENANT3 = '5a3e60e8-cfa9-4a9e-a90a-62b42cea92b8'
TENANT4 = 'c6c87f25-8a94-47ed-8c83-053c25f42df4' TENANT4 = 'c6c87f25-8a94-47ed-8c83-053c25f42df4'
PREFIX1 = 'pref'
def _db_namespace_fixture(namespace, **kwargs): def _db_namespace_fixture(namespace, **kwargs):
obj = { obj = {
@ -146,6 +150,7 @@ class TestMetadefsControllers(base.IsolatedUnitTest):
(NAMESPACE3, _db_property_fixture(PROPERTY1)), (NAMESPACE3, _db_property_fixture(PROPERTY1)),
(NAMESPACE3, _db_property_fixture(PROPERTY2)), (NAMESPACE3, _db_property_fixture(PROPERTY2)),
(NAMESPACE1, _db_property_fixture(PROPERTY1)), (NAMESPACE1, _db_property_fixture(PROPERTY1)),
(NAMESPACE6, _db_property_fixture(PROPERTY4)),
] ]
[self.db.metadef_property_create(req.context, namespace, property) [self.db.metadef_property_create(req.context, namespace, property)
for namespace, property in self.properties] for namespace, property in self.properties]
@ -165,6 +170,7 @@ class TestMetadefsControllers(base.IsolatedUnitTest):
self.resource_types = [ self.resource_types = [
_db_resource_type_fixture(RESOURCE_TYPE1), _db_resource_type_fixture(RESOURCE_TYPE1),
_db_resource_type_fixture(RESOURCE_TYPE2), _db_resource_type_fixture(RESOURCE_TYPE2),
_db_resource_type_fixture(RESOURCE_TYPE4),
] ]
[self.db.metadef_resource_type_create(req.context, resource_type) [self.db.metadef_resource_type_create(req.context, resource_type)
for resource_type in self.resource_types] for resource_type in self.resource_types]
@ -176,6 +182,8 @@ class TestMetadefsControllers(base.IsolatedUnitTest):
(NAMESPACE3, _db_namespace_resource_type_fixture(RESOURCE_TYPE1)), (NAMESPACE3, _db_namespace_resource_type_fixture(RESOURCE_TYPE1)),
(NAMESPACE2, _db_namespace_resource_type_fixture(RESOURCE_TYPE1)), (NAMESPACE2, _db_namespace_resource_type_fixture(RESOURCE_TYPE1)),
(NAMESPACE2, _db_namespace_resource_type_fixture(RESOURCE_TYPE2)), (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, [self.db.metadef_resource_type_association_create(req.context,
namespace, namespace,
@ -526,6 +534,25 @@ class TestMetadefsControllers(base.IsolatedUnitTest):
output = self.property_controller.show(request, NAMESPACE3, PROPERTY1) output = self.property_controller.show(request, NAMESPACE3, PROPERTY1)
self.assertEqual(output.name, 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): def test_property_show_non_existing(self):
request = unit_test_utils.get_fake_request() request = unit_test_utils.get_fake_request()
self.assertRaises(webob.exc.HTTPNotFound, self.assertRaises(webob.exc.HTTPNotFound,
@ -958,10 +985,10 @@ class TestMetadefsControllers(base.IsolatedUnitTest):
request = unit_test_utils.get_fake_request() request = unit_test_utils.get_fake_request()
output = self.rt_controller.index(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 actual = set([type.name for type in
output.resource_types]) output.resource_types])
expected = set([RESOURCE_TYPE1, RESOURCE_TYPE2]) expected = set([RESOURCE_TYPE1, RESOURCE_TYPE2, RESOURCE_TYPE4])
self.assertEqual(actual, expected) self.assertEqual(actual, expected)
def test_resource_type_show(self): def test_resource_type_show(self):