diff --git a/openstack_dashboard/api/glance.py b/openstack_dashboard/api/glance.py index ac45a0d17b..7a4083f236 100644 --- a/openstack_dashboard/api/glance.py +++ b/openstack_dashboard/api/glance.py @@ -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: diff --git a/openstack_dashboard/dashboards/project/instances/tables.py b/openstack_dashboard/dashboards/project/instances/tables.py index b0455a679a..66ab876b74 100644 --- a/openstack_dashboard/dashboards/project/instances/tables.py +++ b/openstack_dashboard/dashboards/project/instances/tables.py @@ -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): diff --git a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-model.service.js b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-model.service.js index 74a920b235..753d3560c5 100644 --- a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-model.service.js +++ b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-model.service.js @@ -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. + // : [, ] 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; }); } diff --git a/openstack_dashboard/static/app/core/metadata/metadata.service.js b/openstack_dashboard/static/app/core/metadata/metadata.service.js index 6b295d86d5..56522a4eee 100644 --- a/openstack_dashboard/static/app/core/metadata/metadata.service.js +++ b/openstack_dashboard/static/app/core/metadata/metadata.service.js @@ -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); } } })(); diff --git a/openstack_dashboard/static/app/core/metadata/metadata.service.spec.js b/openstack_dashboard/static/app/core/metadata/metadata.service.spec.js index 27ba8d1eb0..fa29a9cb66 100644 --- a/openstack_dashboard/static/app/core/metadata/metadata.service.spec.js +++ b/openstack_dashboard/static/app/core/metadata/metadata.service.spec.js @@ -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); }); }); diff --git a/openstack_dashboard/static/app/core/metadata/modal/modal-helper.controller.js b/openstack_dashboard/static/app/core/metadata/modal/modal-helper.controller.js index 8355dba79e..a4a298f343 100644 --- a/openstack_dashboard/static/app/core/metadata/modal/modal-helper.controller.js +++ b/openstack_dashboard/static/app/core/metadata/modal/modal-helper.controller.js @@ -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); diff --git a/openstack_dashboard/static/app/core/metadata/modal/modal.service.js b/openstack_dashboard/static/app/core/metadata/modal/modal.service.js index 396eaddca8..928228a2fa 100644 --- a/openstack_dashboard/static/app/core/metadata/modal/modal.service.js +++ b/openstack_dashboard/static/app/core/metadata/modal/modal.service.js @@ -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); diff --git a/openstack_dashboard/static/app/core/openstack-service-api/glance.service.js b/openstack_dashboard/static/app/core/openstack-service-api/glance.service.js index 5c8816e6ec..3ce29ca2c5 100644 --- a/openstack_dashboard/static/app/core/openstack-service-api/glance.service.js +++ b/openstack_dashboard/static/app/core/openstack-service-api/glance.service.js @@ -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. * diff --git a/openstack_dashboard/test/api_tests/glance_tests.py b/openstack_dashboard/test/api_tests/glance_tests.py index b345eaf922..c3662378bc 100644 --- a/openstack_dashboard/test/api_tests/glance_tests.py +++ b/openstack_dashboard/test/api_tests/glance_tests.py @@ -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() diff --git a/openstack_dashboard/test/test_data/glance_data.py b/openstack_dashboard/test/test_data/glance_data.py index 190e27c35b..2e3277ccd9 100644 --- a/openstack_dashboard/test/test_data/glance_data.py +++ b/openstack_dashboard/test/test_data/glance_data.py @@ -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',