Support properties_target when fetching namespaces

This allows specifying a properties target when fetching metadata
definitions namespaces from glance, and updates the instance
metadata widget to show only "metadata" properties (as opposed to
"scheduler_hints") when creating an instance or updating the
metadata.

Closes-Bug: #1537842
Change-Id: I64dd279139eca2cbd0c0a6e808ade4cbcba8df95
This commit is contained in:
Justin Pomeroy 2016-01-25 16:20:07 -06:00
parent 597dbcecc4
commit e55240d882
10 changed files with 91 additions and 24 deletions

View File

@ -228,6 +228,25 @@ class Namespace(BaseGlanceMetadefAPIResourceWrapper):
return False
def filter_properties_target(namespaces_iter,
resource_types,
properties_target):
"""Filter metadata namespaces based on the given resource types and
properties target.
:param namespaces_iter: Metadata namespaces iterable.
:param resource_types: List of resource type names.
:param properties_target: Name of the properties target.
"""
def filter_namespace(namespace):
for asn in namespace.get('resource_type_associations'):
if (asn.get('name') in resource_types and
asn.get('properties_target') == properties_target):
return True
return False
return filter(filter_namespace, namespaces_iter)
@memoized
def metadefs_namespace_get(request, namespace, resource_type=None, wrap=False):
namespace = glanceclient(request, '2').\
@ -294,6 +313,15 @@ def metadefs_namespace_list(request,
namespaces_iter = glanceclient(request, '2').metadefs_namespace.list(
page_size=request_size, limit=limit, **kwargs)
# Filter the namespaces based on the provided properties_target since this
# is not supported by the metadata namespaces API.
resource_types = filters.get('resource_types')
properties_target = filters.get('properties_target')
if resource_types and properties_target:
namespaces_iter = filter_properties_target(namespaces_iter,
resource_types,
properties_target)
has_prev_data = False
has_more_data = False
if paginate:

View File

@ -734,7 +734,8 @@ class UpdateMetadata(policy.PolicyTargetMixin, tables.LinkAction):
def get_link_url(self, datum):
instance_id = self.table.get_object_id(datum)
self.attrs['ng-click'] = (
"modal.openMetadataModal('instance', '%s', true)" % instance_id)
"modal.openMetadataModal('instance', '%s', true, 'metadata')"
% instance_id)
return "javascript:void(0);"
def allowed(self, request, instance=None):

View File

@ -537,14 +537,14 @@
* rows and are used on the metadata tab for adding metadata to the instance.
*/
function getMetadataDefinitions() {
// Metadata definitions often apply to multiple
// resource types. It is optimal to make a single
// request for all desired resource types.
// Metadata definitions often apply to multiple resource types. It is optimal to make a
// single request for all desired resource types.
// <key>: [<resource_type>, <properties_target>]
var resourceTypes = {
flavor: 'OS::Nova::Flavor',
image: 'OS::Glance::Image',
volume: 'OS::Cinder::Volumes',
instance: 'OS::Nova::Instance'
flavor: ['OS::Nova::Flavor', ''],
image: ['OS::Glance::Image', ''],
volume: ['OS::Cinder::Volumes', ''],
instance: ['OS::Nova::Instance', 'metadata']
};
angular.forEach(resourceTypes, applyForResourceType);
@ -552,16 +552,15 @@
function applyForResourceType(resourceType, key) {
glanceAPI
.getNamespaces({'resource_type': resourceType}, true)
.getNamespaces({ resource_type: resourceType[0],
properties_target: resourceType[1] }, true)
.then(function(data) {
var namespaces = data.data.items;
// This will ensure that the metaDefs model object remains
// unchanged until metadefs are fully loaded. Otherwise,
// partial results are loaded and can result in some odd
// display behavior.
if (namespaces.length) {
model.metadataDefs[key] = namespaces;
}
model.metadataDefs[key] = namespaces;
});
}

View File

@ -77,16 +77,22 @@
* Get available metadata namespaces for specified resource.
*
* @param {string} resource Resource type.
* @param {string} propertiesTarget The properties target, if the resource type has more than
* one type of property.
*/
function getNamespaces(resource) {
return glance.getNamespaces({
function getNamespaces(resource, propertiesTarget) {
var params = {
resource_type: {
aggregate: 'OS::Nova::Aggregate',
flavor: 'OS::Nova::Flavor',
image: 'OS::Glance::Image',
instance: 'OS::Nova::Instance'
}[resource]
}, false);
};
if (propertiesTarget) {
params.properties_target = propertiesTarget;
}
return glance.getNamespaces(params, false);
}
}
})();

View File

@ -119,9 +119,10 @@
it('should get instance namespace', function() {
spyOn(glance, 'getNamespaces');
metadataService.getNamespaces('instance');
metadataService.getNamespaces('instance', 'metadata');
expect(glance.getNamespaces)
.toHaveBeenCalledWith({ resource_type: 'OS::Nova::Instance' }, false);
.toHaveBeenCalledWith({ resource_type: 'OS::Nova::Instance',
properties_target: 'metadata' }, false);
});
});

View File

@ -44,9 +44,11 @@
* @param {string} resource Metadata resource type
* @param {string} id Object identifier to retrieve metadata from
* @param {boolean=} requireReload Whether to reload page when metadata successfully updated
* @param {string} propertiesTarget The properties target, if the resource type has more than
* one type of property.
*/
function openMetadataModal(resource, id, requireReload) {
metadataModalService.open(resource, id)
function openMetadataModal(resource, id, requireReload, propertiesTarget) {
metadataModalService.open(resource, id, propertiesTarget)
.result
.then(onOpened);

View File

@ -43,10 +43,12 @@
*
* @param {string} resource Metadata resource type
* @param {string} id Object identifier to retrieve metadata from
* @param {string} propertiesTarget The properties target, if the resource type has more than
* one type of property.
*/
function open(resource, id) {
function open(resource, id, propertiesTarget) {
function resolveAvailable() {
return metadataService.getNamespaces(resource);
return metadataService.getNamespaces(resource, propertiesTarget);
}
function resolveExisting() {
return metadataService.getMetadata(resource, id);

View File

@ -305,6 +305,11 @@
* @param {string} params.resource_type
* Namespace resource type.
*
* @param {string} params.properties_target
* The properties target, if the resource type has more than one type
* of property. For example, the OS::Nova::Instance resource type has
* "metadata" and "scheduler_hints" properties targets.
*
* @param {boolean} params.paginate
* True to paginate automatically.
*

View File

@ -270,8 +270,30 @@ class GlanceApiTests(test.APITestCase):
self.assertFalse(more)
self.assertFalse(prev)
def test_metadefs_namespace_list_with_properties_target(self):
metadata_defs = self.metadata_defs.list()
limit = getattr(settings, 'API_RESULT_LIMIT', 1000)
filters = {'resource_types': ['mock name'],
'properties_target': 'mock properties target'}
glanceclient = self.stub_glanceclient()
glanceclient.metadefs_namespace = self.mox.CreateMockAnything()
glanceclient.metadefs_namespace.list(page_size=limit,
limit=limit,
filters=filters,
sort_dir='asc',
sort_key='namespace',) \
.AndReturn(metadata_defs)
self.mox.ReplayAll()
defs = api.glance.metadefs_namespace_list(self.request,
filters=filters)[0]
self.assertEqual(1, len(defs))
self.assertEqual('namespace_4', defs[0].namespace)
@test.create_stubs({api.glance: ('get_version',)})
def test_metadefs_namespace_list_v1(self):
api.glance.get_version = self.mox.CreateMockAnything()
api.glance.get_version().AndReturn(1)
self.mox.ReplayAll()
@ -281,8 +303,8 @@ class GlanceApiTests(test.APITestCase):
self.assertFalse(more)
self.assertFalse(prev)
@test.create_stubs({api.glance: ('get_version',)})
def test_metadefs_resource_types_list_v1(self):
api.glance.get_version = self.mox.CreateMockAnything()
api.glance.get_version().AndReturn(1)
self.mox.ReplayAll()

View File

@ -302,7 +302,8 @@ def data(TEST):
{
'created_at': '2014-08-21T08:39:43Z',
'prefix': 'mock',
'name': 'mock name'
'name': 'mock name',
'properties_target': 'mock properties target'
}
],
'visibility': 'public',