Enable volumes metadata update

Cinder currently expose an api to let the users update the volumes
metadata so horizon should expose this functionality.

The metadata is filtered to remove image metadata attributes. There is
work in progress (in Cinder) that will expose the ability to
write-through image metadata to underlying images where appropriate.
Allowing setting of image properties in this UI would be confusing.

Change-Id: If721ac1c908df7651d630f6e7d36f2cc4d69f5da
Implements: blueprint ability-to-add-metadata-to-cinder-volumes-and-snapshots
Co-Authored-By: Santiago Baldassin <santiago.b.baldassin@intel.com>
Co-Authored-By: Pawel Skowron <pawel.skowron@intel.com>
Co-Authored-By: Bartosz Fic <bartosz.fic@intel.com>
Co-Authored-By: Pawel Koniszewski <pawel.koniszewski@intel.com>
Co-Authored-By: Michal Dulko <michal.dulko@intel.com>
Co-Authored-By: David Lyle <david.lyle@intel.com>
Co-Authored-By: Paul Karikh <pkarikh@mirantis.com>
This commit is contained in:
Bartosz Fic 2014-09-05 10:58:41 +02:00 committed by Paul Karikh
parent 7063e2ae9e
commit 7f46e5dc23
16 changed files with 434 additions and 20 deletions

View File

@ -355,6 +355,14 @@ def volume_update(request, volume_id, name, description):
**vol_data)
def volume_set_metadata(request, volume_id, metadata):
return cinderclient(request).volumes.set_metadata(volume_id, metadata)
def volume_delete_metadata(request, volume_id, keys):
return cinderclient(request).volumes.delete_metadata(volume_id, keys)
def volume_reset_state(request, volume_id, state):
return cinderclient(request).volumes.reset_state(volume_id, state)
@ -445,6 +453,16 @@ def volume_snapshot_update(request, snapshot_id, name, description):
**snapshot_data)
def volume_snapshot_set_metadata(request, snapshot_id, metadata):
return cinderclient(request).volume_snapshots.set_metadata(
snapshot_id, metadata)
def volume_snapshot_delete_metadata(request, snapshot_id, keys):
return cinderclient(request).volume_snapshots.delete_metadata(
snapshot_id, keys)
def volume_snapshot_reset_state(request, snapshot_id, state):
return cinderclient(request).volume_snapshots.reset_state(
snapshot_id, state)
@ -792,7 +810,7 @@ def volume_type_extra_set(request, type_id, metadata):
def volume_type_extra_delete(request, type_id, keys):
vol_type = volume_type_get(request, type_id)
return vol_type.unset_keys([keys])
return vol_type.unset_keys(keys)
def qos_spec_list(request):

View File

@ -132,6 +132,34 @@ class VolumeTypes(generic.View):
return {'items': [api.cinder.VolumeType(u).to_dict() for u in result]}
@urls.register
class VolumeMetadata(generic.View):
"""API for volume metadata"""
url_regex = r'cinder/volumes/(?P<volume_id>[^/]+)/metadata$'
@rest_utils.ajax()
def get(self, request, volume_id):
"""Get a specific volume's metadata
http://localhost/api/cinder/volumes/1/metadata
"""
return api.cinder.volume_get(request,
volume_id).to_dict().get('metadata')
@rest_utils.ajax()
def patch(self, request, volume_id):
"""Update metadata items for specific volume
http://localhost/api/cinder/volumes/1/metadata
"""
updated = request.DATA['updated']
removed = request.DATA['removed']
if updated:
api.cinder.volume_set_metadata(request, volume_id, updated)
if removed:
api.cinder.volume_delete_metadata(request, volume_id, removed)
@urls.register
class VolumeType(generic.View):
"""API for getting a volume type.
@ -179,6 +207,74 @@ class VolumeSnapshots(generic.View):
return {'items': [u.to_dict() for u in result]}
@urls.register
class VolumeSnapshotMetadata(generic.View):
"""API for getting snapshots metadata"""
url_regex = r'cinder/volumesnapshots/' \
r'(?P<volume_snapshot_id>[^/]+)/metadata$'
@rest_utils.ajax()
def get(self, request, volume_snapshot_id):
"""Get a specific volumes snapshot metadata
http://localhost/api/cinder/volumesnapshots/1/metadata
"""
result = api.cinder.volume_snapshot_get(request,
volume_snapshot_id).\
to_dict().get('metadata')
return result
@rest_utils.ajax()
def patch(self, request, volume_snapshot_id):
"""Update metadata for specific volume snapshot
http://localhost/api/cinder/volumesnapshots/1/metadata
"""
updated = request.DATA['updated']
removed = request.DATA['removed']
if updated:
api.cinder.volume_snapshot_set_metadata(request,
volume_snapshot_id,
updated)
if removed:
api.cinder.volume_snapshot_delete_metadata(request,
volume_snapshot_id,
removed)
@urls.register
class VolumeTypeMetadata(generic.View):
"""API for getting snapshots metadata"""
url_regex = r'cinder/volumetypes/(?P<volume_type_id>[^/]+)/metadata$'
@rest_utils.ajax()
def get(self, request, volume_type_id):
"""Get a specific volume's metadata
http://localhost/api/cinder/volumetypes/1/metadata
"""
metadata = api.cinder.volume_type_extra_get(request, volume_type_id)
result = {x.key: x.value for x in metadata}
return result
@rest_utils.ajax()
def patch(self, request, volume_type_id):
"""Update metadata for specific volume
http://localhost/api/cinder/volumetypes/1/metadata
"""
updated = request.DATA['updated']
removed = request.DATA['removed']
if updated:
api.cinder.volume_type_extra_set(request,
volume_type_id,
updated)
if removed:
api.cinder.volume_type_extra_delete(request,
volume_type_id,
removed)
@urls.register
class Extensions(generic.View):
"""API for cinder extensions.

View File

@ -72,7 +72,8 @@ class VolumeSnapshotsTable(volumes_tables.VolumesTableBase):
table_actions = (snapshots_tables.VolumeSnapshotsFilterAction,
snapshots_tables.DeleteVolumeSnapshot,)
row_actions = (snapshots_tables.DeleteVolumeSnapshot,
UpdateVolumeSnapshotStatus,)
UpdateVolumeSnapshotStatus,
snapshots_tables.UpdateMetadata)
row_class = UpdateRow
status_columns = ("status",)
columns = ('tenant', 'host', 'name', 'description', 'size', 'status',

View File

@ -19,7 +19,7 @@ from openstack_dashboard.test import helpers as test
from openstack_dashboard.dashboards.admin.volumes.snapshots import forms
INDEX_URL = reverse('horizon:admin:volumes:index')
INDEX_URL = 'horizon:admin:volumes:index'
class VolumeSnapshotsViewTests(test.BaseAdminViewTests):
@ -79,7 +79,7 @@ class VolumeSnapshotsViewTests(test.BaseAdminViewTests):
self.assertNoFormErrors(res)
self.assertMessageCount(error=1)
self.assertRedirectsNoFollow(res, INDEX_URL)
self.assertRedirectsNoFollow(res, reverse(INDEX_URL))
@test.create_stubs({cinder: ('volume_snapshot_get',
'volume_get')})
@ -101,7 +101,7 @@ class VolumeSnapshotsViewTests(test.BaseAdminViewTests):
self.assertNoFormErrors(res)
self.assertMessageCount(error=1)
self.assertRedirectsNoFollow(res, INDEX_URL)
self.assertRedirectsNoFollow(res, reverse(INDEX_URL))
def test_get_snapshot_status_choices_without_current(self):
current_status = {'status': 'available'}

View File

@ -195,6 +195,23 @@ class UpdateRow(tables.Row):
return volume_type
class UpdateMetadata(tables.LinkAction):
name = "update_metadata"
verbose_name = _("Update Metadata")
ajax = False
attrs = {"ng-controller": "MetadataModalHelperController as modal"}
def __init__(self, **kwargs):
kwargs['preempt'] = True
super(UpdateMetadata, self).__init__(**kwargs)
def get_link_url(self, datum):
obj_id = self.table.get_object_id(datum)
self.attrs['ng-click'] = (
"modal.openMetadataModal('volume_type', '%s', true)" % obj_id)
return "javascript:void(0);"
class VolumeTypesTable(tables.DataTable):
name = tables.WrappingColumn("name", verbose_name=_("Name"),
form_field=forms.CharField(max_length=64))
@ -233,7 +250,8 @@ class VolumeTypesTable(tables.DataTable):
EditVolumeType,
UpdateVolumeTypeEncryption,
DeleteVolumeTypeEncryption,
DeleteVolumeType,)
DeleteVolumeType,
UpdateMetadata)
row_class = UpdateRow

View File

@ -111,6 +111,7 @@ class VolumesTable(volumes_tables.VolumesTable):
row_actions = (volumes_tables.DeleteVolume,
UpdateVolumeStatusAction,
UnmanageVolumeAction,
MigrateVolume)
MigrateVolume,
volumes_tables.UpdateMetadata)
columns = ('tenant', 'host', 'name', 'size', 'status', 'volume_type',
'attachments', 'bootable', 'encryption',)

View File

@ -132,6 +132,24 @@ class CreateVolumeFromSnapshot(tables.LinkAction):
return False
class UpdateMetadata(tables.LinkAction):
name = "update_metadata"
verbose_name = _("Update Metadata")
ajax = False
attrs = {"ng-controller": "MetadataModalHelperController as modal"}
def __init__(self, **kwargs):
kwargs['preempt'] = True
super(UpdateMetadata, self).__init__(**kwargs)
def get_link_url(self, datum):
obj_id = self.table.get_object_id(datum)
self.attrs['ng-click'] = (
"modal.openMetadataModal('volume_snapshot', '%s', true)" % obj_id)
return "javascript:void(0);"
class UpdateRow(tables.Row):
ajax = True
@ -191,7 +209,8 @@ class VolumeSnapshotsTable(volume_tables.VolumesTableBase):
launch_actions = (LaunchSnapshotNG,) + launch_actions
row_actions = ((CreateVolumeFromSnapshot,) + launch_actions +
(EditVolumeSnapshot, DeleteVolumeSnapshot))
(EditVolumeSnapshot, DeleteVolumeSnapshot,
UpdateMetadata))
row_class = UpdateRow
status_columns = ("status",)
permissions = [(

View File

@ -469,6 +469,23 @@ class VolumesFilterAction(tables.FilterAction):
if q in volume.name.lower()]
class UpdateMetadata(tables.LinkAction):
name = "update_metadata"
verbose_name = _("Update Metadata")
ajax = False
attrs = {"ng-controller": "MetadataModalHelperController as modal"}
def __init__(self, **kwargs):
kwargs['preempt'] = True
super(UpdateMetadata, self).__init__(**kwargs)
def get_link_url(self, datum):
obj_id = self.table.get_object_id(datum)
self.attrs['ng-click'] = (
"modal.openMetadataModal('volume', '%s', true)" % obj_id)
return "javascript:void(0);"
class VolumesTable(VolumesTableBase):
name = tables.WrappingColumn("name",
verbose_name=_("Name"),
@ -504,7 +521,7 @@ class VolumesTable(VolumesTableBase):
launch_actions +
(EditAttachments, CreateSnapshot, CreateBackup,
RetypeVolume, UploadToImage, CreateTransfer,
DeleteTransfer, DeleteVolume))
DeleteTransfer, DeleteVolume, UpdateMetadata))
class DetachVolume(tables.BatchAction):

View File

@ -22,7 +22,8 @@
metadataService.$inject = [
'horizon.app.core.openstack-service-api.nova',
'horizon.app.core.openstack-service-api.glance'
'horizon.app.core.openstack-service-api.glance',
'horizon.app.core.openstack-service-api.cinder'
];
/**
@ -32,7 +33,7 @@
*
* Unified acquisition and modification of metadata.
*/
function metadataService(nova, glance) {
function metadataService(nova, glance, cinder) {
var service = {
getMetadata: getMetadata,
editMetadata: editMetadata,
@ -52,7 +53,10 @@
aggregate: nova.getAggregateExtraSpecs,
flavor: nova.getFlavorExtraSpecs,
image: glance.getImageProps,
instance: nova.getInstanceMetadata
instance: nova.getInstanceMetadata,
volume: cinder.getVolumeMetadata,
volume_snapshot: cinder.getVolumeSnapshotMetadata,
volume_type: cinder.getVolumeTypeMetadata
}[resource](id);
}
@ -69,7 +73,10 @@
aggregate: nova.editAggregateExtraSpecs,
flavor: nova.editFlavorExtraSpecs,
image: glance.editImageProps,
instance: nova.editInstanceMetadata
instance: nova.editInstanceMetadata,
volume: cinder.editVolumeMetadata,
volume_snapshot: cinder.editVolumeSnapshotMetadata,
volume_type: cinder.editVolumeTypeMetadata
}[resource](id, updated, removed);
}
@ -86,7 +93,10 @@
aggregate: 'OS::Nova::Aggregate',
flavor: 'OS::Nova::Flavor',
image: 'OS::Glance::Image',
instance: 'OS::Nova::Server'
instance: 'OS::Nova::Server',
volume: 'OS::Cinder::Volume',
volume_snapshot: 'OS::Cinder::Snapshot',
volume_type: 'OS:Cinder::VolumeType'
}[resource]
};
if (propertiesTarget) {

View File

@ -31,10 +31,17 @@
editImageProps: function() {},
getNamespaces: function() {}};
var cinder = {getVolumeMetadata:function() {},
getVolumeSnapshotMetadata:function() {},
getVolumeTypeMetadata:function() {},
editVolumeMetadata: function() {},
editVolumeSnapshotMetadata: function() {}};
beforeEach(function() {
module(function($provide) {
$provide.value('horizon.app.core.openstack-service-api.nova', nova);
$provide.value('horizon.app.core.openstack-service-api.glance', glance);
$provide.value('horizon.app.core.openstack-service-api.cinder', cinder);
});
});
@ -97,6 +104,18 @@
expect(glance.editImageProps).toHaveBeenCalledWith('1', 'updated', ['removed']);
});
it('should edit volume metadata', function() {
spyOn(cinder, 'editVolumeMetadata');
metadataService.editMetadata('volume', '1', 'updated', ['removed']);
expect(cinder.editVolumeMetadata).toHaveBeenCalledWith('1', 'updated', ['removed']);
});
it('should edit volume snapshot metadata', function() {
spyOn(cinder, 'editVolumeSnapshotMetadata');
metadataService.editMetadata('volume_snapshot', '1', 'updated', ['removed']);
expect(cinder.editVolumeSnapshotMetadata).toHaveBeenCalledWith('1', 'updated', ['removed']);
});
it('should get image namespace', function() {
spyOn(glance, 'getNamespaces');
metadataService.getNamespaces('image');
@ -111,6 +130,13 @@
expect(actual).toBe(expected);
});
it('should get volume metadata', function() {
var expected = 'volume metadata';
spyOn(cinder, 'getVolumeMetadata').and.returnValue(expected);
var actual = metadataService.getMetadata('volume', '1');
expect(actual).toBe(expected);
});
it('should edit instance metadata', function() {
spyOn(nova, 'editInstanceMetadata');
metadataService.editMetadata('instance', '1', 'updated', ['removed']);

View File

@ -7,6 +7,9 @@
<span translate ng-if="modal.resourceType==='flavor'">Update Flavor Metadata</span>
<span translate ng-if="modal.resourceType==='image'">Update Image Metadata</span>
<span translate ng-if="modal.resourceType==='instance'">Update Instance Metadata</span>
<span translate ng-if="modal.resourceType==='volume'">Update Volume Metadata</span>
<span translate ng-if="modal.resourceType==='volume_snapshot'">Update Volume Snapshot Metadata</span>
<span translate ng-if="modal.resourceType==='volume_type'">Update Volume Type Metadata</span>
</h3>
</div>
<div class="modal-body">

View File

@ -38,6 +38,9 @@
getVolumes: getVolumes,
getVolume: getVolume,
getVolumeTypes: getVolumeTypes,
getVolumeMetadata: getVolumeMetadata,
getVolumeSnapshotMetadata: getVolumeSnapshotMetadata,
getVolumeTypeMetadata: getVolumeTypeMetadata,
getVolumeType: getVolumeType,
getDefaultVolumeType: getDefaultVolumeType,
getVolumeSnapshots: getVolumeSnapshots,
@ -48,7 +51,10 @@
getServices: getServices,
getDefaultQuotaSets: getDefaultQuotaSets,
setDefaultQuotaSets: setDefaultQuotaSets,
updateProjectQuota: updateProjectQuota
updateProjectQuota: updateProjectQuota,
editVolumeMetadata: editVolumeMetadata,
editVolumeSnapshotMetadata: editVolumeSnapshotMetadata,
editVolumeTypeMetadata:editVolumeTypeMetadata
};
return service;
@ -146,6 +152,63 @@
});
}
function getVolumeMetadata(id) {
return apiService.get('/api/cinder/volumes/' + id + '/metadata')
.error(function () {
toastService.add('error', gettext('Unable to retrieve the volume metadata.'));
});
}
function getVolumeSnapshotMetadata(id) {
return apiService.get('/api/cinder/volumesnapshots/' + id + '/metadata')
.error(function () {
toastService.add('error', gettext('Unable to retrieve the snapshot metadata.'));
});
}
function getVolumeTypeMetadata(id) {
return apiService.get('/api/cinder/volumetypes/' + id + '/metadata')
.error(function () {
toastService.add('error', gettext('Unable to retrieve the volume type metadata.'));
});
}
function editVolumeMetadata(id, updated, removed) {
return apiService.patch(
'/api/cinder/volumes/' + id + '/metadata',
{
updated: updated,
removed: removed
}
).error(function () {
toastService.add('error', gettext('Unable to edit volume metadata.'));
});
}
function editVolumeSnapshotMetadata(id, updated, removed) {
return apiService.patch(
'/api/cinder/volumesnapshots/' + id + '/metadata',
{
updated: updated,
removed: removed
}
).error(function () {
toastService.add('error', gettext('Unable to edit snapshot metadata.'));
});
}
function editVolumeTypeMetadata(id, updated, removed) {
return apiService.patch(
'/api/cinder/volumetypes/' + id + '/metadata',
{
updated: updated,
removed: removed
}
).error(function () {
toastService.add('error', gettext('Unable to edit volume type metadata.'));
});
}
/**
* @name getVolumeType
* @description

View File

@ -62,6 +62,13 @@
error: 'Unable to retrieve the volume.',
testInput: [1]
},
{
func: 'getVolumeMetadata',
method: 'get',
path: '/api/cinder/volumes/1/metadata',
error: 'Unable to retrieve the volume metadata.',
testInput: [1]
},
{
func: 'getVolumeTypes',
method: 'get',
@ -76,6 +83,13 @@
error: 'Unable to retrieve the volume type.',
testInput: [1]
},
{
func: 'getVolumeTypeMetadata',
method: 'get',
path: '/api/cinder/volumetypes/1/metadata',
error: 'Unable to retrieve the volume type metadata.',
testInput: [1]
},
{
func: 'getDefaultVolumeType',
method: 'get',
@ -112,6 +126,13 @@
error: 'Unable to retrieve the volume snapshots.',
testInput: [ 'config' ]
},
{
func: 'getVolumeSnapshotMetadata',
method: 'get',
path: '/api/cinder/volumesnapshots/1/metadata',
error: 'Unable to retrieve the snapshot metadata.',
testInput: [1]
},
{
func: 'createVolume',
method: 'post',
@ -165,6 +186,42 @@
data: {'volumes': 42},
error: 'Unable to update project quota data.',
testInput: [{'volumes': 42}, 42]
},
{ func: 'editVolumeMetadata',
method: 'patch',
path: '/api/cinder/volumes/42/metadata',
data: {
"updated": {a: '1', b: '2'},
"removed": ['c', 'd']
},
error: "Unable to edit volume metadata.",
testInput: [
42, {a: '1', b: '2'}, ['c', 'd']
]
},
{ func: 'editVolumeSnapshotMetadata',
method: 'patch',
path: '/api/cinder/volumesnapshots/42/metadata',
data: {
"updated": {a: '1', b: '2'},
"removed": ['c', 'd']
},
error: "Unable to edit snapshot metadata.",
testInput: [
42, {a: '1', b: '2'}, ['c', 'd']
]
},
{ func: 'editVolumeTypeMetadata',
method: 'patch',
path: '/api/cinder/volumetypes/42/metadata',
data: {
"updated": {a: '1', b: '2'},
"removed": ['c', 'd']
},
error: "Unable to edit volume type metadata.",
testInput: [
42, {a: '1', b: '2'}, ['c', 'd']
]
}
];

View File

@ -18,6 +18,7 @@ from django.conf import settings
from openstack_dashboard import api
from openstack_dashboard.api.base import Quota
from openstack_dashboard.api.cinder import VolTypeExtraSpec
from openstack_dashboard.api.rest import cinder
from openstack_dashboard.test import helpers as test
@ -99,6 +100,33 @@ class CinderRestTestCase(test.TestCase):
self.assertStatusCode(response, 201)
self.assertEqual(response.content.decode("utf-8"), mock_post_response)
@mock.patch.object(cinder.api, 'cinder')
def test_volume_get_metadata(self, cc):
request = self.mock_rest_request(**{'GET': {}})
cc.volume_get.return_value = mock.Mock(
**{'to_dict.return_value': {'id': 'one',
'metadata': {'foo': 'bar'}}})
response = cinder.VolumeMetadata().get(request, '1')
self.assertStatusCode(response, 200)
self.assertEqual(response.json, {'foo': 'bar'})
cc.volume_get.assert_called_once_with(request, '1')
@mock.patch.object(cinder.api, 'cinder')
def test_volume_update_metadata(self, cc):
request = self.mock_rest_request(
body='{"updated": {"a": "1", "b": "2"}, '
'"removed": ["c", "d"]}'
)
response = cinder.VolumeMetadata().patch(request, '1')
self.assertStatusCode(response, 204)
self.assertEqual(b'', response.content)
cc.volume_set_metadata.assert_called_once_with(
request, '1', {'a': '1', 'b': '2'}
)
cc.volume_delete_metadata.assert_called_once_with(
request, '1', ['c', 'd']
)
#
# Volume Types
#
@ -138,6 +166,35 @@ class CinderRestTestCase(test.TestCase):
cc.volume_type_default.assert_called_once_with(request)
cc.VolumeType.assert_called_once_with({'name': 'one'})
@mock.patch.object(cinder.api, 'cinder')
def test_volume_type_get_metadata(self, cc):
request = self.mock_rest_request(**{'GET': {}})
cc.volume_type_extra_get = mock.Mock()
cc.volume_type_extra_get.return_value = \
[VolTypeExtraSpec(1, 'foo', 'bar')]
# cc.volume_type_extra_get.side_effect = [{'foo': 'bar'}]
response = cinder.VolumeTypeMetadata().get(request, '1')
self.assertStatusCode(response, 200)
self.assertEqual(response.json, {'foo': 'bar'})
cc.volume_type_extra_get.assert_called_once_with(request, '1')
@mock.patch.object(cinder.api, 'cinder')
def test_volume_type_update_metadata(self, cc):
request = self.mock_rest_request(
body='{"updated": {"a": "1", "b": "2"}, '
'"removed": ["c", "d"]}'
)
response = cinder.VolumeTypeMetadata().patch(request, '1')
self.assertStatusCode(response, 204)
self.assertEqual(b'', response.content)
cc.volume_type_extra_set.assert_called_once_with(
request, '1', {'a': '1', 'b': '2'}
)
cc.volume_type_extra_delete.assert_called_once_with(
request, '1', ['c', 'd']
)
#
# Volume Snapshots
#
@ -170,6 +227,33 @@ class CinderRestTestCase(test.TestCase):
cc.volume_snapshot_list.assert_called_once_with(request,
search_opts=filters)
@mock.patch.object(cinder.api, 'cinder')
def test_volume_snapshot_get_metadata(self, cc):
request = self.mock_rest_request(**{'GET': {}})
cc.volume_snapshot_get.return_value = mock.Mock(
**{'to_dict.return_value': {'id': 'one',
'metadata': {'foo': 'bar'}}})
response = cinder.VolumeSnapshotMetadata().get(request, '1')
self.assertStatusCode(response, 200)
self.assertEqual(response.json, {'foo': 'bar'})
cc.volume_snapshot_get.assert_called_once_with(request, '1')
@mock.patch.object(cinder.api, 'cinder')
def test_volume_snapshot_update_metadata(self, cc):
request = self.mock_rest_request(
body='{"updated": {"a": "1", "b": "2"}, '
'"removed": ["c", "d"]}'
)
response = cinder.VolumeSnapshotMetadata().patch(request, '1')
self.assertStatusCode(response, 204)
self.assertEqual(b'', response.content)
cc.volume_snapshot_set_metadata.assert_called_once_with(
request, '1', {'a': '1', 'b': '2'}
)
cc.volume_snapshot_delete_metadata.assert_called_once_with(
request, '1', ['c', 'd']
)
#
# Extensions
#

View File

@ -274,8 +274,8 @@ class GlanceApiTests(test.APITestCase):
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'}
filters = {'resource_types': ['OS::Cinder::Volume'],
'properties_target': 'user'}
glanceclient = self.stub_glanceclient()
glanceclient.metadefs_namespace = self.mox.CreateMockAnything()
@ -283,7 +283,7 @@ class GlanceApiTests(test.APITestCase):
limit=limit,
filters=filters,
sort_dir='asc',
sort_key='namespace',) \
sort_key='namespace', ) \
.AndReturn(metadata_defs)
self.mox.ReplayAll()

View File

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