List manageable volumes and snapshots
Cinder currently has the ability to take over the management of existing volumes and snapshots ("manage existing") and to relinquish management of volumes and snapshots ("unmanage"). The API to manage an existing volume takes a reference, which is a driver-specific string that is used to identify the volume on the storage backend. This patch adds the client code for APIs for listing volumes and snapshots available for management to make this flow more user-friendly. Change-Id: Icd81a77294d9190ac6dbaa7e7d35e4dedf45e49f Implements: blueprint list-manage-existing
This commit is contained in:
parent
f7928c4058
commit
d24ba31afa
@ -34,7 +34,7 @@ from cinderclient import utils
|
||||
# Valid sort directions and client sort keys
|
||||
SORT_DIR_VALUES = ('asc', 'desc')
|
||||
SORT_KEY_VALUES = ('id', 'status', 'size', 'availability_zone', 'name',
|
||||
'bootable', 'created_at')
|
||||
'bootable', 'created_at', 'reference')
|
||||
# Mapping of client keys to actual sort keys
|
||||
SORT_KEY_MAPPINGS = {'name': 'display_name'}
|
||||
# Additional sort keys for resources
|
||||
@ -126,7 +126,7 @@ class Manager(common_base.HookableMixin):
|
||||
|
||||
def _build_list_url(self, resource_type, detailed=True, search_opts=None,
|
||||
marker=None, limit=None, sort_key=None, sort_dir=None,
|
||||
sort=None):
|
||||
sort=None, offset=None):
|
||||
|
||||
if search_opts is None:
|
||||
search_opts = {}
|
||||
@ -156,6 +156,9 @@ class Manager(common_base.HookableMixin):
|
||||
query_params['sort_dir'] = self._format_sort_dir_param(
|
||||
sort_dir)
|
||||
|
||||
if offset:
|
||||
query_params['offset'] = offset
|
||||
|
||||
# Transform the dict to a sequence of two-element tuples in fixed
|
||||
# order, then the encoded string will be consistent in Python 2&3.
|
||||
query_string = ""
|
||||
|
@ -1156,11 +1156,58 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
def put_snapshots_1234_metadata(self, **kw):
|
||||
return (200, {}, {"metadata": {"key1": "val1", "key2": "val2"}})
|
||||
|
||||
def get_os_volume_manage(self, **kw):
|
||||
vol_id = "volume-ffffffff-0000-ffff-0000-ffffffffffff"
|
||||
vols = [{"size": 4, "safe_to_manage": False, "actual_size": 4.0,
|
||||
"reference": {"source-name": vol_id}},
|
||||
{"size": 5, "safe_to_manage": True, "actual_size": 4.3,
|
||||
"reference": {"source-name": "myvol"}}]
|
||||
return (200, {}, {"manageable-volumes": vols})
|
||||
|
||||
def get_os_volume_manage_detail(self, **kw):
|
||||
vol_id = "volume-ffffffff-0000-ffff-0000-ffffffffffff"
|
||||
vols = [{"size": 4, "reason_not_safe": "volume in use",
|
||||
"safe_to_manage": False, "extra_info": "qos_setting:high",
|
||||
"reference": {"source-name": vol_id},
|
||||
"actual_size": 4.0},
|
||||
{"size": 5, "reason_not_safe": None, "safe_to_manage": True,
|
||||
"extra_info": "qos_setting:low", "actual_size": 4.3,
|
||||
"reference": {"source-name": "myvol"}}]
|
||||
return (200, {}, {"manageable-volumes": vols})
|
||||
|
||||
def post_os_volume_manage(self, **kw):
|
||||
volume = _stub_volume(id='1234')
|
||||
volume.update(kw['body']['volume'])
|
||||
return (202, {}, {'volume': volume})
|
||||
|
||||
def get_os_snapshot_manage(self, **kw):
|
||||
snap_id = "snapshot-ffffffff-0000-ffff-0000-ffffffffffff"
|
||||
snaps = [{"actual_size": 4.0, "size": 4,
|
||||
"safe_to_manage": False, "source_id_type": "source-name",
|
||||
"source_cinder_id": "00000000-ffff-0000-ffff-00000000",
|
||||
"reference": {"source-name": snap_id},
|
||||
"source_identifier": "volume-00000000-ffff-0000-ffff-000000"},
|
||||
{"actual_size": 4.3, "reference": {"source-name": "mysnap"},
|
||||
"source_id_type": "source-name", "source_identifier": "myvol",
|
||||
"safe_to_manage": True, "source_cinder_id": None, "size": 5}]
|
||||
return (200, {}, {"manageable-snapshots": snaps})
|
||||
|
||||
def get_os_snapshot_manage_detail(self, **kw):
|
||||
snap_id = "snapshot-ffffffff-0000-ffff-0000-ffffffffffff"
|
||||
snaps = [{"actual_size": 4.0, "size": 4,
|
||||
"safe_to_manage": False, "source_id_type": "source-name",
|
||||
"source_cinder_id": "00000000-ffff-0000-ffff-00000000",
|
||||
"reference": {"source-name": snap_id},
|
||||
"source_identifier": "volume-00000000-ffff-0000-ffff-000000",
|
||||
"extra_info": "qos_setting:high",
|
||||
"reason_not_safe": "snapshot in use"},
|
||||
{"actual_size": 4.3, "reference": {"source-name": "mysnap"},
|
||||
"safe_to_manage": True, "source_cinder_id": None,
|
||||
"source_id_type": "source-name", "identifier": "mysnap",
|
||||
"source_identifier": "myvol", "size": 5,
|
||||
"extra_info": "qos_setting:low", "reason_not_safe": None}]
|
||||
return (200, {}, {"manageable-snapshots": snaps})
|
||||
|
||||
def post_os_snapshot_manage(self, **kw):
|
||||
snapshot = _stub_snapshot(id='1234', volume_id='volume_id1')
|
||||
snapshot.update(kw['body']['snapshot'])
|
||||
|
@ -1115,6 +1115,18 @@ class ShellTest(utils.TestCase):
|
||||
'bootable': False}}
|
||||
self.assert_called_anytime('POST', '/os-volume-manage', body=expected)
|
||||
|
||||
def test_volume_manageable_list(self):
|
||||
self.run_command('manageable-list fakehost')
|
||||
self.assert_called('GET', '/os-volume-manage/detail?host=fakehost')
|
||||
|
||||
def test_volume_manageable_list_details(self):
|
||||
self.run_command('manageable-list fakehost --detailed True')
|
||||
self.assert_called('GET', '/os-volume-manage/detail?host=fakehost')
|
||||
|
||||
def test_volume_manageable_list_no_details(self):
|
||||
self.run_command('manageable-list fakehost --detailed False')
|
||||
self.assert_called('GET', '/os-volume-manage?host=fakehost')
|
||||
|
||||
def test_volume_unmanage(self):
|
||||
self.run_command('unmanage 1234')
|
||||
self.assert_called('POST', '/volumes/1234/action',
|
||||
@ -1327,6 +1339,18 @@ class ShellTest(utils.TestCase):
|
||||
self.assert_called_anytime('POST', '/os-snapshot-manage',
|
||||
body=expected)
|
||||
|
||||
def test_snapshot_manageable_list(self):
|
||||
self.run_command('snapshot-manageable-list fakehost')
|
||||
self.assert_called('GET', '/os-snapshot-manage/detail?host=fakehost')
|
||||
|
||||
def test_snapshot_manageable_list_details(self):
|
||||
self.run_command('snapshot-manageable-list fakehost --detailed True')
|
||||
self.assert_called('GET', '/os-snapshot-manage/detail?host=fakehost')
|
||||
|
||||
def test_snapshot_manageable_list_no_details(self):
|
||||
self.run_command('snapshot-manageable-list fakehost --detailed False')
|
||||
self.assert_called('GET', '/os-snapshot-manage?host=fakehost')
|
||||
|
||||
def test_snapshot_unmanage(self):
|
||||
self.run_command('snapshot-unmanage 1234')
|
||||
self.assert_called('POST', '/snapshots/1234/action',
|
||||
|
@ -274,6 +274,14 @@ class VolumesTest(utils.TestCase):
|
||||
cs.assert_called('POST', '/os-volume-manage', {'volume': expected})
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_volume_list_manageable(self):
|
||||
cs.volumes.list_manageable('host1', detailed=False)
|
||||
cs.assert_called('GET', '/os-volume-manage?host=host1')
|
||||
|
||||
def test_volume_list_manageable_detailed(self):
|
||||
cs.volumes.list_manageable('host1', detailed=True)
|
||||
cs.assert_called('GET', '/os-volume-manage/detail?host=host1')
|
||||
|
||||
def test_volume_unmanage(self):
|
||||
v = cs.volumes.get('1234')
|
||||
self._assert_request_id(v)
|
||||
@ -288,6 +296,14 @@ class VolumesTest(utils.TestCase):
|
||||
cs.assert_called('POST', '/os-snapshot-manage', {'snapshot': expected})
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_snapshot_list_manageable(self):
|
||||
cs.volume_snapshots.list_manageable('host1', detailed=False)
|
||||
cs.assert_called('GET', '/os-snapshot-manage?host=host1')
|
||||
|
||||
def test_snapshot_list_manageable_detailed(self):
|
||||
cs.volume_snapshots.list_manageable('host1', detailed=True)
|
||||
cs.assert_called('GET', '/os-snapshot-manage/detail?host=host1')
|
||||
|
||||
def test_replication_promote(self):
|
||||
v = cs.volumes.get('1234')
|
||||
self._assert_request_id(v)
|
||||
|
@ -364,3 +364,53 @@ class FakeHTTPClient(fake_v2.FakeHTTPClient):
|
||||
|
||||
def delete_group_snapshots_1234(self, **kw):
|
||||
return (202, {}, {})
|
||||
|
||||
#
|
||||
# Manageable volumes/snapshots
|
||||
#
|
||||
def get_manageable_volumes(self, **kw):
|
||||
vol_id = "volume-ffffffff-0000-ffff-0000-ffffffffffff"
|
||||
vols = [{"size": 4, "safe_to_manage": False, "actual_size": 4.0,
|
||||
"reference": {"source-name": vol_id}},
|
||||
{"size": 5, "safe_to_manage": True, "actual_size": 4.3,
|
||||
"reference": {"source-name": "myvol"}}]
|
||||
return (200, {}, {"manageable-volumes": vols})
|
||||
|
||||
def get_manageable_volumes_detail(self, **kw):
|
||||
vol_id = "volume-ffffffff-0000-ffff-0000-ffffffffffff"
|
||||
vols = [{"size": 4, "reason_not_safe": "volume in use",
|
||||
"safe_to_manage": False, "extra_info": "qos_setting:high",
|
||||
"reference": {"source-name": vol_id},
|
||||
"actual_size": 4.0},
|
||||
{"size": 5, "reason_not_safe": None, "safe_to_manage": True,
|
||||
"extra_info": "qos_setting:low", "actual_size": 4.3,
|
||||
"reference": {"source-name": "myvol"}}]
|
||||
return (200, {}, {"manageable-volumes": vols})
|
||||
|
||||
def get_manageable_snapshots(self, **kw):
|
||||
snap_id = "snapshot-ffffffff-0000-ffff-0000-ffffffffffff"
|
||||
snaps = [{"actual_size": 4.0, "size": 4,
|
||||
"safe_to_manage": False, "source_id_type": "source-name",
|
||||
"source_cinder_id": "00000000-ffff-0000-ffff-00000000",
|
||||
"reference": {"source-name": snap_id},
|
||||
"source_identifier": "volume-00000000-ffff-0000-ffff-000000"},
|
||||
{"actual_size": 4.3, "reference": {"source-name": "mysnap"},
|
||||
"source_id_type": "source-name", "source_identifier": "myvol",
|
||||
"safe_to_manage": True, "source_cinder_id": None, "size": 5}]
|
||||
return (200, {}, {"manageable-snapshots": snaps})
|
||||
|
||||
def get_manageable_snapshots_detail(self, **kw):
|
||||
snap_id = "snapshot-ffffffff-0000-ffff-0000-ffffffffffff"
|
||||
snaps = [{"actual_size": 4.0, "size": 4,
|
||||
"safe_to_manage": False, "source_id_type": "source-name",
|
||||
"source_cinder_id": "00000000-ffff-0000-ffff-00000000",
|
||||
"reference": {"source-name": snap_id},
|
||||
"source_identifier": "volume-00000000-ffff-0000-ffff-000000",
|
||||
"extra_info": "qos_setting:high",
|
||||
"reason_not_safe": "snapshot in use"},
|
||||
{"actual_size": 4.3, "reference": {"source-name": "mysnap"},
|
||||
"safe_to_manage": True, "source_cinder_id": None,
|
||||
"source_id_type": "source-name", "identifier": "mysnap",
|
||||
"source_identifier": "myvol", "size": 5,
|
||||
"extra_info": "qos_setting:low", "reason_not_safe": None}]
|
||||
return (200, {}, {"manageable-snapshots": snaps})
|
||||
|
@ -309,3 +309,33 @@ class ShellTest(utils.TestCase):
|
||||
cmd += src
|
||||
self.run_command(cmd)
|
||||
self.assert_called_anytime('POST', '/groups/action', body=expected)
|
||||
|
||||
def test_volume_manageable_list(self):
|
||||
self.run_command('--os-volume-api-version 3.8 '
|
||||
'manageable-list fakehost')
|
||||
self.assert_called('GET', '/manageable_volumes/detail?host=fakehost')
|
||||
|
||||
def test_volume_manageable_list_details(self):
|
||||
self.run_command('--os-volume-api-version 3.8 '
|
||||
'manageable-list fakehost --detailed True')
|
||||
self.assert_called('GET', '/manageable_volumes/detail?host=fakehost')
|
||||
|
||||
def test_volume_manageable_list_no_details(self):
|
||||
self.run_command('--os-volume-api-version 3.8 '
|
||||
'manageable-list fakehost --detailed False')
|
||||
self.assert_called('GET', '/manageable_volumes?host=fakehost')
|
||||
|
||||
def test_snapshot_manageable_list(self):
|
||||
self.run_command('--os-volume-api-version 3.8 '
|
||||
'snapshot-manageable-list fakehost')
|
||||
self.assert_called('GET', '/manageable_snapshots/detail?host=fakehost')
|
||||
|
||||
def test_snapshot_manageable_list_details(self):
|
||||
self.run_command('--os-volume-api-version 3.8 '
|
||||
'snapshot-manageable-list fakehost --detailed True')
|
||||
self.assert_called('GET', '/manageable_snapshots/detail?host=fakehost')
|
||||
|
||||
def test_snapshot_manageable_list_no_details(self):
|
||||
self.run_command('--os-volume-api-version 3.8 '
|
||||
'snapshot-manageable-list fakehost --detailed False')
|
||||
self.assert_called('GET', '/manageable_snapshots?host=fakehost')
|
||||
|
@ -65,3 +65,23 @@ class VolumesTest(utils.TestCase):
|
||||
'group_id': '1234'}}
|
||||
cs.assert_called('POST', '/volumes', body=expected)
|
||||
self._assert_request_id(vol)
|
||||
|
||||
def test_volume_list_manageable(self):
|
||||
cs = fakes.FakeClient(api_versions.APIVersion('3.8'))
|
||||
cs.volumes.list_manageable('host1', detailed=False)
|
||||
cs.assert_called('GET', '/manageable_volumes?host=host1')
|
||||
|
||||
def test_volume_list_manageable_detailed(self):
|
||||
cs = fakes.FakeClient(api_versions.APIVersion('3.8'))
|
||||
cs.volumes.list_manageable('host1', detailed=True)
|
||||
cs.assert_called('GET', '/manageable_volumes/detail?host=host1')
|
||||
|
||||
def test_snapshot_list_manageable(self):
|
||||
cs = fakes.FakeClient(api_versions.APIVersion('3.8'))
|
||||
cs.volume_snapshots.list_manageable('host1', detailed=False)
|
||||
cs.assert_called('GET', '/manageable_snapshots?host=host1')
|
||||
|
||||
def test_snapshot_list_manageable_detailed(self):
|
||||
cs = fakes.FakeClient(api_versions.APIVersion('3.8'))
|
||||
cs.volume_snapshots.list_manageable('host1', detailed=True)
|
||||
cs.assert_called('GET', '/manageable_snapshots/detail?host=host1')
|
||||
|
@ -108,3 +108,89 @@ def do_upload_to_image(cs, args):
|
||||
args.image_name,
|
||||
args.container_format,
|
||||
args.disk_format))
|
||||
|
||||
@utils.arg('host',
|
||||
metavar='<host>',
|
||||
help='Cinder host on which to list manageable volumes; '
|
||||
'takes the form: host@backend-name#pool')
|
||||
@utils.arg('--detailed',
|
||||
metavar='<detailed>',
|
||||
default=True,
|
||||
help='Returned detailed information (default true).')
|
||||
@utils.arg('--marker',
|
||||
metavar='<marker>',
|
||||
default=None,
|
||||
help='Begin returning volumes that appear later in the volume '
|
||||
'list than that represented by this volume id. '
|
||||
'Default=None.')
|
||||
@utils.arg('--limit',
|
||||
metavar='<limit>',
|
||||
default=None,
|
||||
help='Maximum number of volumes to return. Default=None.')
|
||||
@utils.arg('--offset',
|
||||
metavar='<offset>',
|
||||
default=None,
|
||||
help='Number of volumes to skip after marker. Default=None.')
|
||||
@utils.arg('--sort',
|
||||
metavar='<key>[:<direction>]',
|
||||
default=None,
|
||||
help=(('Comma-separated list of sort keys and directions in the '
|
||||
'form of <key>[:<asc|desc>]. '
|
||||
'Valid keys: %s. '
|
||||
'Default=None.') % ', '.join(base.SORT_KEY_VALUES)))
|
||||
@utils.service_type('volumev2')
|
||||
def do_manageable_list(cs, args):
|
||||
"""Lists all manageable volumes."""
|
||||
detailed = strutils.bool_from_string(args.detailed)
|
||||
volumes = cs.volumes.list_manageable(host=args.host, detailed=detailed,
|
||||
marker=args.marker, limit=args.limit,
|
||||
offset=args.offset, sort=args.sort)
|
||||
columns = ['reference', 'size', 'safe_to_manage']
|
||||
if detailed:
|
||||
columns.extend(['reason_not_safe', 'cinder_id', 'extra_info'])
|
||||
utils.print_list(volumes, columns, sortby_index=None)
|
||||
|
||||
|
||||
@utils.arg('host',
|
||||
metavar='<host>',
|
||||
help='Cinder host on which to list manageable snapshots; '
|
||||
'takes the form: host@backend-name#pool')
|
||||
@utils.arg('--detailed',
|
||||
metavar='<detailed>',
|
||||
default=True,
|
||||
help='Returned detailed information (default true).')
|
||||
@utils.arg('--marker',
|
||||
metavar='<marker>',
|
||||
default=None,
|
||||
help='Begin returning volumes that appear later in the volume '
|
||||
'list than that represented by this volume id. '
|
||||
'Default=None.')
|
||||
@utils.arg('--limit',
|
||||
metavar='<limit>',
|
||||
default=None,
|
||||
help='Maximum number of volumes to return. Default=None.')
|
||||
@utils.arg('--offset',
|
||||
metavar='<offset>',
|
||||
default=None,
|
||||
help='Number of volumes to skip after marker. Default=None.')
|
||||
@utils.arg('--sort',
|
||||
metavar='<key>[:<direction>]',
|
||||
default=None,
|
||||
help=(('Comma-separated list of sort keys and directions in the '
|
||||
'form of <key>[:<asc|desc>]. '
|
||||
'Valid keys: %s. '
|
||||
'Default=None.') % ', '.join(base.SORT_KEY_VALUES)))
|
||||
@utils.service_type('volumev2')
|
||||
def do_snapshot_manageable_list(cs, args):
|
||||
"""Lists all manageable snapshots."""
|
||||
detailed = strutils.bool_from_string(args.detailed)
|
||||
snapshots = cs.volume_snapshots.list_manageable(host=args.host,
|
||||
detailed=detailed,
|
||||
marker=args.marker,
|
||||
limit=args.limit,
|
||||
offset=args.offset,
|
||||
sort=args.sort)
|
||||
columns = ['reference', 'size', 'safe_to_manage', 'source_reference']
|
||||
if detailed:
|
||||
columns.extend(['reason_not_safe', 'cinder_id', 'extra_info'])
|
||||
utils.print_list(snapshots, columns, sortby_index=None)
|
||||
|
@ -15,5 +15,25 @@
|
||||
|
||||
"""Volume snapshot interface (v2 extension)."""
|
||||
|
||||
from cinderclient.v3.volume_snapshots import * # flake8: noqa
|
||||
from cinderclient import api_versions
|
||||
from cinderclient.v3 import volume_snapshots
|
||||
|
||||
|
||||
class Snapshot(volume_snapshots.Snapshot):
|
||||
def list_manageable(self, host, detailed=True, marker=None, limit=None,
|
||||
offset=None, sort=None):
|
||||
return self.manager.list_manageable(host, detailed=detailed,
|
||||
marker=marker, limit=limit,
|
||||
offset=offset, sort=sort)
|
||||
|
||||
|
||||
class SnapshotManager(volume_snapshots.SnapshotManager):
|
||||
resource_class = Snapshot
|
||||
|
||||
@api_versions.wraps("2.0")
|
||||
def list_manageable(self, host, detailed=True, marker=None, limit=None,
|
||||
offset=None, sort=None):
|
||||
url = self._build_list_url("os-snapshot-manage", detailed=detailed,
|
||||
search_opts={'host': host}, marker=marker,
|
||||
limit=limit, offset=offset, sort=sort)
|
||||
return self._list(url, "manageable-snapshots")
|
||||
|
@ -43,3 +43,11 @@ class VolumeManager(volumes.VolumeManager):
|
||||
'image_name': image_name,
|
||||
'container_format': container_format,
|
||||
'disk_format': disk_format})
|
||||
|
||||
@api_versions.wraps("2.0")
|
||||
def list_manageable(self, host, detailed=True, marker=None, limit=None,
|
||||
offset=None, sort=None):
|
||||
url = self._build_list_url("os-volume-manage", detailed=detailed,
|
||||
search_opts={'host': host}, marker=marker,
|
||||
limit=limit, offset=offset, sort=sort)
|
||||
return self._list(url, "manageable-volumes")
|
||||
|
@ -2577,6 +2577,49 @@ def do_manage(cs, args):
|
||||
utils.print_dict(info)
|
||||
|
||||
|
||||
@utils.service_type('volumev3')
|
||||
@api_versions.wraps('3.8')
|
||||
@utils.arg('host',
|
||||
metavar='<host>',
|
||||
help='Cinder host on which to list manageable volumes; '
|
||||
'takes the form: host@backend-name#pool')
|
||||
@utils.arg('--detailed',
|
||||
metavar='<detailed>',
|
||||
default=True,
|
||||
help='Returned detailed information (default true).')
|
||||
@utils.arg('--marker',
|
||||
metavar='<marker>',
|
||||
default=None,
|
||||
help='Begin returning volumes that appear later in the volume '
|
||||
'list than that represented by this volume id. '
|
||||
'Default=None.')
|
||||
@utils.arg('--limit',
|
||||
metavar='<limit>',
|
||||
default=None,
|
||||
help='Maximum number of volumes to return. Default=None.')
|
||||
@utils.arg('--offset',
|
||||
metavar='<offset>',
|
||||
default=None,
|
||||
help='Number of volumes to skip after marker. Default=None.')
|
||||
@utils.arg('--sort',
|
||||
metavar='<key>[:<direction>]',
|
||||
default=None,
|
||||
help=(('Comma-separated list of sort keys and directions in the '
|
||||
'form of <key>[:<asc|desc>]. '
|
||||
'Valid keys: %s. '
|
||||
'Default=None.') % ', '.join(base.SORT_KEY_VALUES)))
|
||||
def do_manageable_list(cs, args):
|
||||
"""Lists all manageable volumes."""
|
||||
detailed = strutils.bool_from_string(args.detailed)
|
||||
volumes = cs.volumes.list_manageable(host=args.host, detailed=detailed,
|
||||
marker=args.marker, limit=args.limit,
|
||||
offset=args.offset, sort=args.sort)
|
||||
columns = ['reference', 'size', 'safe_to_manage']
|
||||
if detailed:
|
||||
columns.extend(['reason_not_safe', 'cinder_id', 'extra_info'])
|
||||
utils.print_list(volumes, columns, sortby_index=None)
|
||||
|
||||
|
||||
@utils.arg('volume', metavar='<volume>',
|
||||
help='Name or ID of the volume to unmanage.')
|
||||
@utils.service_type('volumev3')
|
||||
@ -3240,6 +3283,52 @@ def do_snapshot_manage(cs, args):
|
||||
utils.print_dict(info)
|
||||
|
||||
|
||||
@utils.service_type('volumev3')
|
||||
@api_versions.wraps('3.8')
|
||||
@utils.arg('host',
|
||||
metavar='<host>',
|
||||
help='Cinder host on which to list manageable snapshots; '
|
||||
'takes the form: host@backend-name#pool')
|
||||
@utils.arg('--detailed',
|
||||
metavar='<detailed>',
|
||||
default=True,
|
||||
help='Returned detailed information (default true).')
|
||||
@utils.arg('--marker',
|
||||
metavar='<marker>',
|
||||
default=None,
|
||||
help='Begin returning volumes that appear later in the volume '
|
||||
'list than that represented by this volume id. '
|
||||
'Default=None.')
|
||||
@utils.arg('--limit',
|
||||
metavar='<limit>',
|
||||
default=None,
|
||||
help='Maximum number of volumes to return. Default=None.')
|
||||
@utils.arg('--offset',
|
||||
metavar='<offset>',
|
||||
default=None,
|
||||
help='Number of volumes to skip after marker. Default=None.')
|
||||
@utils.arg('--sort',
|
||||
metavar='<key>[:<direction>]',
|
||||
default=None,
|
||||
help=(('Comma-separated list of sort keys and directions in the '
|
||||
'form of <key>[:<asc|desc>]. '
|
||||
'Valid keys: %s. '
|
||||
'Default=None.') % ', '.join(base.SORT_KEY_VALUES)))
|
||||
def do_snapshot_manageable_list(cs, args):
|
||||
"""Lists all manageable snapshots."""
|
||||
detailed = strutils.bool_from_string(args.detailed)
|
||||
snapshots = cs.volume_snapshots.list_manageable(host=args.host,
|
||||
detailed=detailed,
|
||||
marker=args.marker,
|
||||
limit=args.limit,
|
||||
offset=args.offset,
|
||||
sort=args.sort)
|
||||
columns = ['reference', 'size', 'safe_to_manage', 'source_reference']
|
||||
if detailed:
|
||||
columns.extend(['reason_not_safe', 'cinder_id', 'extra_info'])
|
||||
utils.print_list(snapshots, columns, sortby_index=None)
|
||||
|
||||
|
||||
@utils.arg('snapshot', metavar='<snapshot>',
|
||||
help='Name or ID of the snapshot to unmanage.')
|
||||
@utils.service_type('volumev3')
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
"""Volume snapshot interface (v3 extension)."""
|
||||
|
||||
from cinderclient import api_versions
|
||||
from cinderclient import base
|
||||
from cinderclient.openstack.common.apiclient import base as common_base
|
||||
|
||||
@ -63,6 +64,12 @@ class Snapshot(base.Resource):
|
||||
self.manager.manage(volume_id=volume_id, ref=ref, name=name,
|
||||
description=description, metadata=metadata)
|
||||
|
||||
def list_manageable(self, host, detailed=True, marker=None, limit=None,
|
||||
offset=None, sort=None):
|
||||
return self.manager.list_manageable(host, detailed=detailed,
|
||||
marker=marker, limit=limit,
|
||||
offset=offset, sort=sort)
|
||||
|
||||
def unmanage(self, snapshot):
|
||||
"""Unmanage a snapshot."""
|
||||
self.manager.unmanage(snapshot)
|
||||
@ -204,6 +211,14 @@ class SnapshotManager(base.ManagerWithFind):
|
||||
}
|
||||
return self._create('/os-snapshot-manage', body, 'snapshot')
|
||||
|
||||
@api_versions.wraps("3.8")
|
||||
def list_manageable(self, host, detailed=True, marker=None, limit=None,
|
||||
offset=None, sort=None):
|
||||
url = self._build_list_url("manageable_snapshots", detailed=detailed,
|
||||
search_opts={'host': host}, marker=marker,
|
||||
limit=limit, offset=offset, sort=sort)
|
||||
return self._list(url, "manageable-snapshots")
|
||||
|
||||
def unmanage(self, snapshot):
|
||||
"""Unmanage a snapshot."""
|
||||
return self._action('os-unmanage', snapshot, None)
|
||||
|
@ -193,6 +193,12 @@ class Volume(base.Resource):
|
||||
availability_zone=availability_zone,
|
||||
metadata=metadata, bootable=bootable)
|
||||
|
||||
def list_manageable(self, host, detailed=True, marker=None, limit=None,
|
||||
offset=None, sort=None):
|
||||
return self.manager.list_manageable(host, detailed=detailed,
|
||||
marker=marker, limit=limit,
|
||||
offset=offset, sort=sort)
|
||||
|
||||
def unmanage(self, volume):
|
||||
"""Unmanage a volume."""
|
||||
return self.manager.unmanage(volume)
|
||||
@ -624,6 +630,14 @@ class VolumeManager(base.ManagerWithFind):
|
||||
}}
|
||||
return self._create('/os-volume-manage', body, 'volume')
|
||||
|
||||
@api_versions.wraps("3.8")
|
||||
def list_manageable(self, host, detailed=True, marker=None, limit=None,
|
||||
offset=None, sort=None):
|
||||
url = self._build_list_url("manageable_volumes", detailed=detailed,
|
||||
search_opts={'host': host}, marker=marker,
|
||||
limit=limit, offset=offset, sort=sort)
|
||||
return self._list(url, "manageable-volumes")
|
||||
|
||||
def unmanage(self, volume):
|
||||
"""Unmanage a volume."""
|
||||
return self._action('os-unmanage', volume, None)
|
||||
|
Loading…
Reference in New Issue
Block a user