Add request_ids attribute to resource objects
Added request_ids attribute to resource object for all the volume, volume_types, volume_type_access and volume_snapshots APIs by updating following APIs: volumes: delete, update, force_delete, reset_state, extend, migrate_volume, retype, update_readonly_flag, manage, unmanage, promote, reenable, get_pools, initialize_connection, terminate_connection, get_encryption_metadata volume_types: delete volume_type_access: add_project_access remove_project_access volume_snapshots: delete and update Returning list with request_ids as attribute in case of 'delete_metadata' and 'delete_image_metadata' APIs. These changes are required to return 'request_id' from client to log request_id mappings of cross projects. For more details on how request_id will be returned to the caller, please refer to the approved blueprint [1] discussed with the cross-project team. [1] http://specs.openstack.org/openstack/openstack-specs/specs/return-request-id.html DocImpact 'request-ids' will be returned as an attribute with response object. User can access it using 'res.request_ids' where 'res' is a response object. Change-Id: Icc4565291220278a65e6910a840fba623b750cc4 Partial-Implements: blueprint return-request-id-to-caller
This commit is contained in:
parent
b2fc77f731
commit
b560b1777c
@ -15,6 +15,9 @@ import json
|
||||
from cinderclient.tests.unit.fixture_data import base
|
||||
|
||||
|
||||
REQUEST_ID = 'req-test-request-id'
|
||||
|
||||
|
||||
def _stub_snapshot(**kwargs):
|
||||
snapshot = {
|
||||
"created_at": "2012-08-28T16:30:31.000000",
|
||||
@ -37,8 +40,11 @@ class Fixture(base.Fixture):
|
||||
super(Fixture, self).setUp()
|
||||
|
||||
snapshot_1234 = _stub_snapshot(id='1234')
|
||||
self.requests.register_uri('GET', self.url('1234'),
|
||||
json={'snapshot': snapshot_1234})
|
||||
self.requests.register_uri(
|
||||
'GET', self.url('1234'),
|
||||
json={'snapshot': snapshot_1234},
|
||||
headers={'x-openstack-request-id': REQUEST_ID}
|
||||
)
|
||||
|
||||
def action_1234(request, context):
|
||||
return ''
|
||||
@ -53,13 +59,20 @@ class Fixture(base.Fixture):
|
||||
raise AssertionError("Unexpected action: %s" % action)
|
||||
return ''
|
||||
|
||||
self.requests.register_uri('POST', self.url('1234', 'action'),
|
||||
text=action_1234, status_code=202)
|
||||
self.requests.register_uri(
|
||||
'POST', self.url('1234', 'action'),
|
||||
text=action_1234, status_code=202,
|
||||
headers={'x-openstack-request-id': REQUEST_ID}
|
||||
)
|
||||
|
||||
self.requests.register_uri('GET',
|
||||
self.url('detail?limit=2&marker=1234'),
|
||||
status_code=200, json={'snapshots': []})
|
||||
self.requests.register_uri(
|
||||
'GET', self.url('detail?limit=2&marker=1234'),
|
||||
status_code=200, json={'snapshots': []},
|
||||
headers={'x-openstack-request-id': REQUEST_ID}
|
||||
)
|
||||
|
||||
self.requests.register_uri('GET',
|
||||
self.url('detail?sort=id'),
|
||||
status_code=200, json={'snapshots': []})
|
||||
self.requests.register_uri(
|
||||
'GET', self.url('detail?sort=id'),
|
||||
status_code=200, json={'snapshots': []},
|
||||
headers={'x-openstack-request-id': REQUEST_ID}
|
||||
)
|
||||
|
@ -433,7 +433,7 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
assert body[action] is None
|
||||
elif action == 'os-initialize_connection':
|
||||
assert list(body[action]) == ['connector']
|
||||
return (202, {}, {'connection_info': 'foos'})
|
||||
return (202, {}, {'connection_info': {'foos': 'bars'}})
|
||||
elif action == 'os-terminate_connection':
|
||||
assert list(body[action]) == ['connector']
|
||||
elif action == 'os-begin_detaching':
|
||||
|
@ -24,27 +24,35 @@ class SnapshotActionsTest(utils.FixturedTestCase):
|
||||
data_fixture_class = snapshots.Fixture
|
||||
|
||||
def test_update_snapshot_status(self):
|
||||
s = self.cs.volume_snapshots.get('1234')
|
||||
snap = self.cs.volume_snapshots.get('1234')
|
||||
self._assert_request_id(snap)
|
||||
stat = {'status': 'available'}
|
||||
self.cs.volume_snapshots.update_snapshot_status(s, stat)
|
||||
stats = self.cs.volume_snapshots.update_snapshot_status(snap, stat)
|
||||
self.assert_called('POST', '/snapshots/1234/action')
|
||||
self._assert_request_id(stats)
|
||||
|
||||
def test_update_snapshot_status_with_progress(self):
|
||||
s = self.cs.volume_snapshots.get('1234')
|
||||
self._assert_request_id(s)
|
||||
stat = {'status': 'available', 'progress': '73%'}
|
||||
self.cs.volume_snapshots.update_snapshot_status(s, stat)
|
||||
stats = self.cs.volume_snapshots.update_snapshot_status(s, stat)
|
||||
self.assert_called('POST', '/snapshots/1234/action')
|
||||
self._assert_request_id(stats)
|
||||
|
||||
def test_list_snapshots_with_marker_limit(self):
|
||||
self.cs.volume_snapshots.list(marker=1234, limit=2)
|
||||
lst = self.cs.volume_snapshots.list(marker=1234, limit=2)
|
||||
self.assert_called('GET', '/snapshots/detail?limit=2&marker=1234')
|
||||
self._assert_request_id(lst)
|
||||
|
||||
def test_list_snapshots_with_sort(self):
|
||||
self.cs.volume_snapshots.list(sort="id")
|
||||
lst = self.cs.volume_snapshots.list(sort="id")
|
||||
self.assert_called('GET', '/snapshots/detail?sort=id')
|
||||
self._assert_request_id(lst)
|
||||
|
||||
def test_snapshot_unmanage(self):
|
||||
s = self.cs.volume_snapshots.get('1234')
|
||||
self.cs.volume_snapshots.unmanage(s)
|
||||
self._assert_request_id(s)
|
||||
snap = self.cs.volume_snapshots.unmanage(s)
|
||||
self.assert_called('POST', '/snapshots/1234/action',
|
||||
{'os-unmanage': None})
|
||||
self._assert_request_id(snap)
|
||||
|
@ -28,15 +28,18 @@ class TypeAccessTest(utils.TestCase):
|
||||
def test_list(self):
|
||||
access = cs.volume_type_access.list(volume_type='3')
|
||||
cs.assert_called('GET', '/types/3/os-volume-type-access')
|
||||
self._assert_request_id(access)
|
||||
for a in access:
|
||||
self.assertTrue(isinstance(a, volume_type_access.VolumeTypeAccess))
|
||||
|
||||
def test_add_project_access(self):
|
||||
cs.volume_type_access.add_project_access('3', PROJECT_UUID)
|
||||
access = cs.volume_type_access.add_project_access('3', PROJECT_UUID)
|
||||
cs.assert_called('POST', '/types/3/action',
|
||||
{'addProjectAccess': {'project': PROJECT_UUID}})
|
||||
self._assert_request_id(access)
|
||||
|
||||
def test_remove_project_access(self):
|
||||
cs.volume_type_access.remove_project_access('3', PROJECT_UUID)
|
||||
access = cs.volume_type_access.remove_project_access('3', PROJECT_UUID)
|
||||
cs.assert_called('POST', '/types/3/action',
|
||||
{'removeProjectAccess': {'project': PROJECT_UUID}})
|
||||
self._assert_request_id(access)
|
||||
|
@ -26,12 +26,14 @@ class TypesTest(utils.TestCase):
|
||||
def test_list_types(self):
|
||||
tl = cs.volume_types.list()
|
||||
cs.assert_called('GET', '/types?is_public=None')
|
||||
self._assert_request_id(tl)
|
||||
for t in tl:
|
||||
self.assertIsInstance(t, volume_types.VolumeType)
|
||||
|
||||
def test_list_types_not_public(self):
|
||||
cs.volume_types.list(is_public=None)
|
||||
t1 = cs.volume_types.list(is_public=None)
|
||||
cs.assert_called('GET', '/types?is_public=None')
|
||||
self._assert_request_id(t1)
|
||||
|
||||
def test_create(self):
|
||||
t = cs.volume_types.create('test-type-3', 'test-type-3-desc')
|
||||
@ -42,6 +44,7 @@ class TypesTest(utils.TestCase):
|
||||
'os-volume-type-access:is_public': True
|
||||
}})
|
||||
self.assertIsInstance(t, volume_types.VolumeType)
|
||||
self._assert_request_id(t)
|
||||
|
||||
def test_create_non_public(self):
|
||||
t = cs.volume_types.create('test-type-3', 'test-type-3-desc', False)
|
||||
@ -52,6 +55,7 @@ class TypesTest(utils.TestCase):
|
||||
'os-volume-type-access:is_public': False
|
||||
}})
|
||||
self.assertIsInstance(t, volume_types.VolumeType)
|
||||
self._assert_request_id(t)
|
||||
|
||||
def test_update(self):
|
||||
t = cs.volume_types.update('1', 'test_type_1', 'test_desc_1', False)
|
||||
@ -61,16 +65,19 @@ class TypesTest(utils.TestCase):
|
||||
'description': 'test_desc_1',
|
||||
'is_public': False}})
|
||||
self.assertIsInstance(t, volume_types.VolumeType)
|
||||
self._assert_request_id(t)
|
||||
|
||||
def test_get(self):
|
||||
t = cs.volume_types.get('1')
|
||||
cs.assert_called('GET', '/types/1')
|
||||
self.assertIsInstance(t, volume_types.VolumeType)
|
||||
self._assert_request_id(t)
|
||||
|
||||
def test_default(self):
|
||||
t = cs.volume_types.default()
|
||||
cs.assert_called('GET', '/types/default')
|
||||
self.assertIsInstance(t, volume_types.VolumeType)
|
||||
self._assert_request_id(t)
|
||||
|
||||
def test_set_key(self):
|
||||
t = cs.volume_types.get(1)
|
||||
@ -78,12 +85,15 @@ class TypesTest(utils.TestCase):
|
||||
cs.assert_called('POST',
|
||||
'/types/1/extra_specs',
|
||||
{'extra_specs': {'k': 'v'}})
|
||||
self._assert_request_id(t)
|
||||
|
||||
def test_unsset_keys(self):
|
||||
t = cs.volume_types.get(1)
|
||||
t.unset_keys(['k'])
|
||||
cs.assert_called('DELETE', '/types/1/extra_specs/k')
|
||||
self._assert_request_id(t)
|
||||
|
||||
def test_delete(self):
|
||||
cs.volume_types.delete(1)
|
||||
t = cs.volume_types.delete(1)
|
||||
cs.assert_called('DELETE', '/types/1')
|
||||
self._assert_request_id(t)
|
||||
|
@ -24,12 +24,14 @@ cs = fakes.FakeClient()
|
||||
class VolumesTest(utils.TestCase):
|
||||
|
||||
def test_list_volumes_with_marker_limit(self):
|
||||
cs.volumes.list(marker=1234, limit=2)
|
||||
lst = cs.volumes.list(marker=1234, limit=2)
|
||||
cs.assert_called('GET', '/volumes/detail?limit=2&marker=1234')
|
||||
self._assert_request_id(lst)
|
||||
|
||||
def test_list_volumes_with_sort_key_dir(self):
|
||||
cs.volumes.list(sort_key='id', sort_dir='asc')
|
||||
lst = cs.volumes.list(sort_key='id', sort_dir='asc')
|
||||
cs.assert_called('GET', '/volumes/detail?sort_dir=asc&sort_key=id')
|
||||
self._assert_request_id(lst)
|
||||
|
||||
def test_list_volumes_with_invalid_sort_key(self):
|
||||
self.assertRaises(ValueError,
|
||||
@ -54,6 +56,7 @@ class VolumesTest(utils.TestCase):
|
||||
# osapi_max_limit is 1000 by default. If limit is less than
|
||||
# osapi_max_limit, we can get 2 volumes back.
|
||||
volumes = cs.volumes._list(url, response_key, limit=limit)
|
||||
self._assert_request_id(volumes)
|
||||
cs.assert_called('GET', url)
|
||||
self.assertEqual(fake_volumes, volumes)
|
||||
|
||||
@ -64,23 +67,28 @@ class VolumesTest(utils.TestCase):
|
||||
cs.client.osapi_max_limit = 1
|
||||
volumes = cs.volumes._list(url, response_key, limit=limit)
|
||||
self.assertEqual(fake_volumes, volumes)
|
||||
self._assert_request_id(volumes)
|
||||
cs.client.osapi_max_limit = 1000
|
||||
|
||||
def test_delete_volume(self):
|
||||
v = cs.volumes.list()[0]
|
||||
v.delete()
|
||||
del_v = v.delete()
|
||||
cs.assert_called('DELETE', '/volumes/1234')
|
||||
cs.volumes.delete('1234')
|
||||
self._assert_request_id(del_v)
|
||||
del_v = cs.volumes.delete('1234')
|
||||
cs.assert_called('DELETE', '/volumes/1234')
|
||||
cs.volumes.delete(v)
|
||||
self._assert_request_id(del_v)
|
||||
del_v = cs.volumes.delete(v)
|
||||
cs.assert_called('DELETE', '/volumes/1234')
|
||||
self._assert_request_id(del_v)
|
||||
|
||||
def test_create_volume(self):
|
||||
cs.volumes.create(1)
|
||||
vol = cs.volumes.create(1)
|
||||
cs.assert_called('POST', '/volumes')
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_create_volume_with_hint(self):
|
||||
cs.volumes.create(1, scheduler_hints='uuid')
|
||||
vol = cs.volumes.create(1, scheduler_hints='uuid')
|
||||
expected = {'volume': {'status': 'creating',
|
||||
'description': None,
|
||||
'availability_zone': None,
|
||||
@ -99,31 +107,42 @@ class VolumesTest(utils.TestCase):
|
||||
'multiattach': False},
|
||||
'OS-SCH-HNT:scheduler_hints': 'uuid'}
|
||||
cs.assert_called('POST', '/volumes', body=expected)
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_attach(self):
|
||||
v = cs.volumes.get('1234')
|
||||
cs.volumes.attach(v, 1, '/dev/vdc', mode='ro')
|
||||
self._assert_request_id(v)
|
||||
vol = cs.volumes.attach(v, 1, '/dev/vdc', mode='ro')
|
||||
cs.assert_called('POST', '/volumes/1234/action')
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_attach_to_host(self):
|
||||
v = cs.volumes.get('1234')
|
||||
cs.volumes.attach(v, None, None, host_name='test', mode='rw')
|
||||
self._assert_request_id(v)
|
||||
vol = cs.volumes.attach(v, None, None, host_name='test', mode='rw')
|
||||
cs.assert_called('POST', '/volumes/1234/action')
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_detach(self):
|
||||
v = cs.volumes.get('1234')
|
||||
cs.volumes.detach(v, 'abc123')
|
||||
self._assert_request_id(v)
|
||||
vol = cs.volumes.detach(v, 'abc123')
|
||||
cs.assert_called('POST', '/volumes/1234/action')
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_reserve(self):
|
||||
v = cs.volumes.get('1234')
|
||||
cs.volumes.reserve(v)
|
||||
self._assert_request_id(v)
|
||||
vol = cs.volumes.reserve(v)
|
||||
cs.assert_called('POST', '/volumes/1234/action')
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_unreserve(self):
|
||||
v = cs.volumes.get('1234')
|
||||
cs.volumes.unreserve(v)
|
||||
self._assert_request_id(v)
|
||||
vol = cs.volumes.unreserve(v)
|
||||
cs.assert_called('POST', '/volumes/1234/action')
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_begin_detaching(self):
|
||||
v = cs.volumes.get('1234')
|
||||
@ -132,126 +151,161 @@ class VolumesTest(utils.TestCase):
|
||||
|
||||
def test_roll_detaching(self):
|
||||
v = cs.volumes.get('1234')
|
||||
cs.volumes.roll_detaching(v)
|
||||
self._assert_request_id(v)
|
||||
vol = cs.volumes.roll_detaching(v)
|
||||
cs.assert_called('POST', '/volumes/1234/action')
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_initialize_connection(self):
|
||||
v = cs.volumes.get('1234')
|
||||
cs.volumes.initialize_connection(v, {})
|
||||
self._assert_request_id(v)
|
||||
vol = cs.volumes.initialize_connection(v, {})
|
||||
cs.assert_called('POST', '/volumes/1234/action')
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_terminate_connection(self):
|
||||
v = cs.volumes.get('1234')
|
||||
cs.volumes.terminate_connection(v, {})
|
||||
self._assert_request_id(v)
|
||||
vol = cs.volumes.terminate_connection(v, {})
|
||||
cs.assert_called('POST', '/volumes/1234/action')
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_set_metadata(self):
|
||||
cs.volumes.set_metadata(1234, {'k1': 'v2'})
|
||||
vol = cs.volumes.set_metadata(1234, {'k1': 'v2'})
|
||||
cs.assert_called('POST', '/volumes/1234/metadata',
|
||||
{'metadata': {'k1': 'v2'}})
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_delete_metadata(self):
|
||||
keys = ['key1']
|
||||
cs.volumes.delete_metadata(1234, keys)
|
||||
vol = cs.volumes.delete_metadata(1234, keys)
|
||||
cs.assert_called('DELETE', '/volumes/1234/metadata/key1')
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_extend(self):
|
||||
v = cs.volumes.get('1234')
|
||||
cs.volumes.extend(v, 2)
|
||||
self._assert_request_id(v)
|
||||
vol = cs.volumes.extend(v, 2)
|
||||
cs.assert_called('POST', '/volumes/1234/action')
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_reset_state(self):
|
||||
v = cs.volumes.get('1234')
|
||||
cs.volumes.reset_state(v, 'in-use', attach_status='detached',
|
||||
migration_status='none')
|
||||
self._assert_request_id(v)
|
||||
vol = cs.volumes.reset_state(v, 'in-use', attach_status='detached',
|
||||
migration_status='none')
|
||||
cs.assert_called('POST', '/volumes/1234/action')
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_get_encryption_metadata(self):
|
||||
cs.volumes.get_encryption_metadata('1234')
|
||||
vol = cs.volumes.get_encryption_metadata('1234')
|
||||
cs.assert_called('GET', '/volumes/1234/encryption')
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_migrate(self):
|
||||
v = cs.volumes.get('1234')
|
||||
cs.volumes.migrate_volume(v, 'dest', False, False)
|
||||
self._assert_request_id(v)
|
||||
vol = cs.volumes.migrate_volume(v, 'dest', False, False)
|
||||
cs.assert_called('POST', '/volumes/1234/action',
|
||||
{'os-migrate_volume': {'host': 'dest',
|
||||
'force_host_copy': False,
|
||||
'lock_volume': False}})
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_migrate_with_lock_volume(self):
|
||||
v = cs.volumes.get('1234')
|
||||
cs.volumes.migrate_volume(v, 'dest', False, True)
|
||||
self._assert_request_id(v)
|
||||
vol = cs.volumes.migrate_volume(v, 'dest', False, True)
|
||||
cs.assert_called('POST', '/volumes/1234/action',
|
||||
{'os-migrate_volume': {'host': 'dest',
|
||||
'force_host_copy': False,
|
||||
'lock_volume': True}})
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_metadata_update_all(self):
|
||||
cs.volumes.update_all_metadata(1234, {'k1': 'v1'})
|
||||
vol = cs.volumes.update_all_metadata(1234, {'k1': 'v1'})
|
||||
cs.assert_called('PUT', '/volumes/1234/metadata',
|
||||
{'metadata': {'k1': 'v1'}})
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_readonly_mode_update(self):
|
||||
v = cs.volumes.get('1234')
|
||||
cs.volumes.update_readonly_flag(v, True)
|
||||
self._assert_request_id(v)
|
||||
vol = cs.volumes.update_readonly_flag(v, True)
|
||||
cs.assert_called('POST', '/volumes/1234/action')
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_retype(self):
|
||||
v = cs.volumes.get('1234')
|
||||
cs.volumes.retype(v, 'foo', 'on-demand')
|
||||
self._assert_request_id(v)
|
||||
vol = cs.volumes.retype(v, 'foo', 'on-demand')
|
||||
cs.assert_called('POST', '/volumes/1234/action',
|
||||
{'os-retype': {'new_type': 'foo',
|
||||
'migration_policy': 'on-demand'}})
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_set_bootable(self):
|
||||
v = cs.volumes.get('1234')
|
||||
cs.volumes.set_bootable(v, True)
|
||||
self._assert_request_id(v)
|
||||
vol = cs.volumes.set_bootable(v, True)
|
||||
cs.assert_called('POST', '/volumes/1234/action')
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_volume_manage(self):
|
||||
cs.volumes.manage('host1', {'k': 'v'})
|
||||
vol = cs.volumes.manage('host1', {'k': 'v'})
|
||||
expected = {'host': 'host1', 'name': None, 'availability_zone': None,
|
||||
'description': None, 'metadata': None, 'ref': {'k': 'v'},
|
||||
'volume_type': None, 'bootable': False}
|
||||
cs.assert_called('POST', '/os-volume-manage', {'volume': expected})
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_volume_manage_bootable(self):
|
||||
cs.volumes.manage('host1', {'k': 'v'}, bootable=True)
|
||||
vol = cs.volumes.manage('host1', {'k': 'v'}, bootable=True)
|
||||
expected = {'host': 'host1', 'name': None, 'availability_zone': None,
|
||||
'description': None, 'metadata': None, 'ref': {'k': 'v'},
|
||||
'volume_type': None, 'bootable': True}
|
||||
cs.assert_called('POST', '/os-volume-manage', {'volume': expected})
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_volume_unmanage(self):
|
||||
v = cs.volumes.get('1234')
|
||||
cs.volumes.unmanage(v)
|
||||
self._assert_request_id(v)
|
||||
vol = cs.volumes.unmanage(v)
|
||||
cs.assert_called('POST', '/volumes/1234/action', {'os-unmanage': None})
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_snapshot_manage(self):
|
||||
cs.volume_snapshots.manage('volume_id1', {'k': 'v'})
|
||||
vol = cs.volume_snapshots.manage('volume_id1', {'k': 'v'})
|
||||
expected = {'volume_id': 'volume_id1', 'name': None,
|
||||
'description': None, 'metadata': None, 'ref': {'k': 'v'}}
|
||||
cs.assert_called('POST', '/os-snapshot-manage', {'snapshot': expected})
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_replication_promote(self):
|
||||
v = cs.volumes.get('1234')
|
||||
cs.volumes.promote(v)
|
||||
self._assert_request_id(v)
|
||||
vol = cs.volumes.promote(v)
|
||||
cs.assert_called('POST', '/volumes/1234/action',
|
||||
{'os-promote-replica': None})
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_replication_reenable(self):
|
||||
v = cs.volumes.get('1234')
|
||||
cs.volumes.reenable(v)
|
||||
self._assert_request_id(v)
|
||||
vol = cs.volumes.reenable(v)
|
||||
cs.assert_called('POST', '/volumes/1234/action',
|
||||
{'os-reenable-replica': None})
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_get_pools(self):
|
||||
cs.volumes.get_pools('')
|
||||
vol = cs.volumes.get_pools('')
|
||||
cs.assert_called('GET', '/scheduler-stats/get_pools')
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_get_pools_detail(self):
|
||||
cs.volumes.get_pools('--detail')
|
||||
vol = cs.volumes.get_pools('--detail')
|
||||
cs.assert_called('GET', '/scheduler-stats/get_pools?detail=True')
|
||||
self._assert_request_id(vol)
|
||||
|
||||
|
||||
class FormatSortParamTestCase(utils.TestCase):
|
||||
|
@ -16,6 +16,7 @@
|
||||
"""Volume snapshot interface (1.1 extension)."""
|
||||
|
||||
from cinderclient import base
|
||||
from cinderclient.openstack.common.apiclient import base as common_base
|
||||
|
||||
|
||||
class Snapshot(base.Resource):
|
||||
@ -26,11 +27,11 @@ class Snapshot(base.Resource):
|
||||
|
||||
def delete(self):
|
||||
"""Delete this snapshot."""
|
||||
self.manager.delete(self)
|
||||
return self.manager.delete(self)
|
||||
|
||||
def update(self, **kwargs):
|
||||
"""Update the name or description for this snapshot."""
|
||||
self.manager.update(self, **kwargs)
|
||||
return self.manager.update(self, **kwargs)
|
||||
|
||||
@property
|
||||
def progress(self):
|
||||
@ -42,7 +43,7 @@ class Snapshot(base.Resource):
|
||||
|
||||
def reset_state(self, state):
|
||||
"""Update the snapshot with the provided state."""
|
||||
self.manager.reset_state(self, state)
|
||||
return self.manager.reset_state(self, state)
|
||||
|
||||
def set_metadata(self, metadata):
|
||||
"""Set metadata of this snapshot."""
|
||||
@ -122,7 +123,7 @@ class SnapshotManager(base.ManagerWithFind):
|
||||
|
||||
:param snapshot: The :class:`Snapshot` to delete.
|
||||
"""
|
||||
self._delete("/snapshots/%s" % base.getid(snapshot))
|
||||
return self._delete("/snapshots/%s" % base.getid(snapshot))
|
||||
|
||||
def update(self, snapshot, **kwargs):
|
||||
"""Update the name or description for a snapshot.
|
||||
@ -134,7 +135,7 @@ class SnapshotManager(base.ManagerWithFind):
|
||||
|
||||
body = {"snapshot": kwargs}
|
||||
|
||||
self._update("/snapshots/%s" % base.getid(snapshot), body)
|
||||
return self._update("/snapshots/%s" % base.getid(snapshot), body)
|
||||
|
||||
def reset_state(self, snapshot, state):
|
||||
"""Update the specified snapshot with the provided state."""
|
||||
@ -145,7 +146,8 @@ class SnapshotManager(base.ManagerWithFind):
|
||||
body = {action: info}
|
||||
self.run_hooks('modify_body_for_action', body, **kwargs)
|
||||
url = '/snapshots/%s/action' % base.getid(snapshot)
|
||||
return self.api.client.post(url, body=body)
|
||||
resp, body = self.api.client.post(url, body=body)
|
||||
return common_base.TupleWithMeta((resp, body), resp)
|
||||
|
||||
def update_snapshot_status(self, snapshot, update_dict):
|
||||
return self._action('os-update_snapshot_status',
|
||||
@ -167,9 +169,14 @@ class SnapshotManager(base.ManagerWithFind):
|
||||
:param snapshot: The :class:`Snapshot`.
|
||||
:param keys: A list of keys to be removed.
|
||||
"""
|
||||
response_list = []
|
||||
snapshot_id = base.getid(snapshot)
|
||||
for k in keys:
|
||||
self._delete("/snapshots/%s/metadata/%s" % (snapshot_id, k))
|
||||
resp, body = self._delete("/snapshots/%s/metadata/%s" %
|
||||
(snapshot_id, k))
|
||||
response_list.append(resp)
|
||||
|
||||
return common_base.ListWithMeta([], response_list)
|
||||
|
||||
def update_all_metadata(self, snapshot, metadata):
|
||||
"""Update_all snapshot metadata.
|
||||
|
@ -15,6 +15,7 @@
|
||||
"""Volume type access interface."""
|
||||
|
||||
from cinderclient import base
|
||||
from cinderclient.openstack.common.apiclient import base as common_base
|
||||
|
||||
|
||||
class VolumeTypeAccess(base.Resource):
|
||||
@ -36,16 +37,17 @@ class VolumeTypeAccessManager(base.ManagerWithFind):
|
||||
def add_project_access(self, volume_type, project):
|
||||
"""Add a project to the given volume type access list."""
|
||||
info = {'project': project}
|
||||
self._action('addProjectAccess', volume_type, info)
|
||||
return self._action('addProjectAccess', volume_type, info)
|
||||
|
||||
def remove_project_access(self, volume_type, project):
|
||||
"""Remove a project from the given volume type access list."""
|
||||
info = {'project': project}
|
||||
self._action('removeProjectAccess', volume_type, info)
|
||||
return self._action('removeProjectAccess', volume_type, info)
|
||||
|
||||
def _action(self, action, volume_type, info, **kwargs):
|
||||
"""Perform a volume type action."""
|
||||
body = {action: info}
|
||||
self.run_hooks('modify_body_for_action', body, **kwargs)
|
||||
url = '/types/%s/action' % base.getid(volume_type)
|
||||
return self.api.client.post(url, body=body)
|
||||
resp, body = self.api.client.post(url, body=body)
|
||||
return common_base.TupleWithMeta((resp, body), resp)
|
||||
|
@ -108,7 +108,7 @@ class VolumeTypeManager(base.ManagerWithFind):
|
||||
|
||||
:param volume_type: The name or ID of the :class:`VolumeType` to get.
|
||||
"""
|
||||
self._delete("/types/%s" % base.getid(volume_type))
|
||||
return self._delete("/types/%s" % base.getid(volume_type))
|
||||
|
||||
def create(self, name, description=None, is_public=True):
|
||||
"""Creates a volume type.
|
||||
|
@ -16,6 +16,7 @@
|
||||
"""Volume interface (v2 extension)."""
|
||||
|
||||
from cinderclient import base
|
||||
from cinderclient.openstack.common.apiclient import base as common_base
|
||||
|
||||
|
||||
class Volume(base.Resource):
|
||||
@ -25,11 +26,11 @@ class Volume(base.Resource):
|
||||
|
||||
def delete(self):
|
||||
"""Delete this volume."""
|
||||
self.manager.delete(self)
|
||||
return self.manager.delete(self)
|
||||
|
||||
def update(self, **kwargs):
|
||||
"""Update the name or description for this volume."""
|
||||
self.manager.update(self, **kwargs)
|
||||
return self.manager.update(self, **kwargs)
|
||||
|
||||
def attach(self, instance_uuid, mountpoint, mode='rw', host_name=None):
|
||||
"""Set attachment metadata.
|
||||
@ -119,7 +120,7 @@ class Volume(base.Resource):
|
||||
|
||||
:param volume: The UUID of the volume to force-delete.
|
||||
"""
|
||||
self.manager.force_delete(self)
|
||||
return self.manager.force_delete(self)
|
||||
|
||||
def reset_state(self, state, attach_status=None, migration_status=None):
|
||||
"""Update the volume with the provided state.
|
||||
@ -130,7 +131,8 @@ class Volume(base.Resource):
|
||||
:param migration_status: The migration_status of the volume to be set,
|
||||
or None to keep the current status.
|
||||
"""
|
||||
self.manager.reset_state(self, state, attach_status, migration_status)
|
||||
return self.manager.reset_state(self, state, attach_status,
|
||||
migration_status)
|
||||
|
||||
def extend(self, volume, new_size):
|
||||
"""Extend the size of the specified volume.
|
||||
@ -138,11 +140,12 @@ class Volume(base.Resource):
|
||||
:param volume: The UUID of the volume to extend
|
||||
:param new_size: The desired size to extend volume to.
|
||||
"""
|
||||
self.manager.extend(self, new_size)
|
||||
return self.manager.extend(self, new_size)
|
||||
|
||||
def migrate_volume(self, host, force_host_copy, lock_volume):
|
||||
"""Migrate the volume to a new host."""
|
||||
self.manager.migrate_volume(self, host, force_host_copy, lock_volume)
|
||||
return self.manager.migrate_volume(self, host, force_host_copy,
|
||||
lock_volume)
|
||||
|
||||
def replication_enable(self, volume):
|
||||
"""Enables volume replication on a given volume."""
|
||||
@ -162,7 +165,7 @@ class Volume(base.Resource):
|
||||
|
||||
def retype(self, volume_type, policy):
|
||||
"""Change a volume's type."""
|
||||
self.manager.retype(self, volume_type, policy)
|
||||
return self.manager.retype(self, volume_type, policy)
|
||||
|
||||
def update_all_metadata(self, metadata):
|
||||
"""Update all metadata of this volume."""
|
||||
@ -175,32 +178,33 @@ class Volume(base.Resource):
|
||||
:param read_only: The value to indicate whether to update volume to
|
||||
read-only access mode.
|
||||
"""
|
||||
self.manager.update_readonly_flag(self, read_only)
|
||||
return self.manager.update_readonly_flag(self, read_only)
|
||||
|
||||
def manage(self, host, ref, name=None, description=None,
|
||||
volume_type=None, availability_zone=None, metadata=None,
|
||||
bootable=False):
|
||||
"""Manage an existing volume."""
|
||||
self.manager.manage(host=host, ref=ref, name=name,
|
||||
description=description, volume_type=volume_type,
|
||||
availability_zone=availability_zone,
|
||||
metadata=metadata, bootable=bootable)
|
||||
return self.manager.manage(host=host, ref=ref, name=name,
|
||||
description=description,
|
||||
volume_type=volume_type,
|
||||
availability_zone=availability_zone,
|
||||
metadata=metadata, bootable=bootable)
|
||||
|
||||
def unmanage(self, volume):
|
||||
"""Unmanage a volume."""
|
||||
self.manager.unmanage(volume)
|
||||
return self.manager.unmanage(volume)
|
||||
|
||||
def promote(self, volume):
|
||||
"""Promote secondary to be primary in relationship."""
|
||||
self.manager.promote(volume)
|
||||
return self.manager.promote(volume)
|
||||
|
||||
def reenable(self, volume):
|
||||
"""Sync the secondary volume with primary for a relationship."""
|
||||
self.manager.reenable(volume)
|
||||
return self.manager.reenable(volume)
|
||||
|
||||
def get_pools(self, detail):
|
||||
"""Show pool information for backends."""
|
||||
self.manager.get_pools(detail)
|
||||
return self.manager.get_pools(detail)
|
||||
|
||||
|
||||
class VolumeManager(base.ManagerWithFind):
|
||||
@ -298,7 +302,7 @@ class VolumeManager(base.ManagerWithFind):
|
||||
|
||||
:param volume: The :class:`Volume` to delete.
|
||||
"""
|
||||
self._delete("/volumes/%s" % base.getid(volume))
|
||||
return self._delete("/volumes/%s" % base.getid(volume))
|
||||
|
||||
def update(self, volume, **kwargs):
|
||||
"""Update the name or description for a volume.
|
||||
@ -310,7 +314,7 @@ class VolumeManager(base.ManagerWithFind):
|
||||
|
||||
body = {"volume": kwargs}
|
||||
|
||||
self._update("/volumes/%s" % base.getid(volume), body)
|
||||
return self._update("/volumes/%s" % base.getid(volume), body)
|
||||
|
||||
def _action(self, action, volume, info=None, **kwargs):
|
||||
"""Perform a volume "action."
|
||||
@ -318,7 +322,8 @@ class VolumeManager(base.ManagerWithFind):
|
||||
body = {action: info}
|
||||
self.run_hooks('modify_body_for_action', body, **kwargs)
|
||||
url = '/volumes/%s/action' % base.getid(volume)
|
||||
return self.api.client.post(url, body=body)
|
||||
resp, body = self.api.client.post(url, body=body)
|
||||
return common_base.TupleWithMeta((resp, body), resp)
|
||||
|
||||
def attach(self, volume, instance_uuid, mountpoint, mode='rw',
|
||||
host_name=None):
|
||||
@ -386,8 +391,9 @@ class VolumeManager(base.ManagerWithFind):
|
||||
:param volume: The :class:`Volume` (or its ID).
|
||||
:param connector: connector dict from nova.
|
||||
"""
|
||||
return self._action('os-initialize_connection', volume,
|
||||
{'connector': connector})[1]['connection_info']
|
||||
resp, body = self._action('os-initialize_connection', volume,
|
||||
{'connector': connector})
|
||||
return common_base.DictWithMeta(body['connection_info'], resp)
|
||||
|
||||
def terminate_connection(self, volume, connector):
|
||||
"""Terminate a volume connection.
|
||||
@ -395,8 +401,8 @@ class VolumeManager(base.ManagerWithFind):
|
||||
:param volume: The :class:`Volume` (or its ID).
|
||||
:param connector: connector dict from nova.
|
||||
"""
|
||||
self._action('os-terminate_connection', volume,
|
||||
{'connector': connector})
|
||||
return self._action('os-terminate_connection', volume,
|
||||
{'connector': connector})
|
||||
|
||||
def set_metadata(self, volume, metadata):
|
||||
"""Update/Set a volumes metadata.
|
||||
@ -414,8 +420,13 @@ class VolumeManager(base.ManagerWithFind):
|
||||
:param volume: The :class:`Volume`.
|
||||
:param keys: A list of keys to be removed.
|
||||
"""
|
||||
response_list = []
|
||||
for k in keys:
|
||||
self._delete("/volumes/%s/metadata/%s" % (base.getid(volume), k))
|
||||
resp, body = self._delete("/volumes/%s/metadata/%s" %
|
||||
(base.getid(volume), k))
|
||||
response_list.append(resp)
|
||||
|
||||
return common_base.ListWithMeta([], response_list)
|
||||
|
||||
def set_image_metadata(self, volume, metadata):
|
||||
"""Set a volume's image metadata.
|
||||
@ -433,9 +444,13 @@ class VolumeManager(base.ManagerWithFind):
|
||||
:param volume: The :class:`Volume`.
|
||||
:param keys: A list of keys to be removed.
|
||||
"""
|
||||
response_list = []
|
||||
for key in keys:
|
||||
self._action("os-unset_image_metadata", volume,
|
||||
{'key': key})
|
||||
resp, body = self._action("os-unset_image_metadata", volume,
|
||||
{'key': key})
|
||||
response_list.append(resp)
|
||||
|
||||
return common_base.ListWithMeta([], response_list)
|
||||
|
||||
def show_image_metadata(self, volume):
|
||||
"""Show a volume's image metadata.
|
||||
@ -500,7 +515,8 @@ class VolumeManager(base.ManagerWithFind):
|
||||
:param volume_id: the id of the volume to query
|
||||
:return: a dictionary of volume encryption metadata
|
||||
"""
|
||||
return self._get("/volumes/%s/encryption" % volume_id)._info
|
||||
metadata = self._get("/volumes/%s/encryption" % volume_id)
|
||||
return common_base.DictWithMeta(metadata._info, metadata.request_ids)
|
||||
|
||||
def migrate_volume(self, volume, host, force_host_copy, lock_volume):
|
||||
"""Migrate volume to new host.
|
||||
@ -524,9 +540,10 @@ class VolumeManager(base.ManagerWithFind):
|
||||
:param error: Inform of an error to cause migration cleanup
|
||||
"""
|
||||
new_volume_id = base.getid(new_volume)
|
||||
return self._action('os-migrate_volume_completion',
|
||||
old_volume,
|
||||
{'new_volume': new_volume_id, 'error': error})[1]
|
||||
resp, body = self._action('os-migrate_volume_completion', old_volume,
|
||||
{'new_volume': new_volume_id,
|
||||
'error': error})
|
||||
return common_base.DictWithMeta(body, resp)
|
||||
|
||||
def replication_enable(self, volume_id):
|
||||
"""
|
||||
|
Loading…
x
Reference in New Issue
Block a user