Add support for group snapshots
This patch adds support for group snapshots. Server side API patch was merged: https://review.openstack.org/#/c/361369/ Current microversion is 3.14. The following CLI's are supported: cinder --os-volume-api-version 3.14 group-create-from-src --name my_group --group-snapshot <group snapshot uuid> cinder --os-volume-api-version 3.14 group-create-from-src --name my_group --source-group <source group uuid> cinder --os-volume-api-version 3.14 group-snapshot-create --name <name> <group uuid> cinder --os-volume-api-version 3.14 group-snapshot-list cinder --os-volume-api-version 3.14 group-snapshot-show <group snapshot uuid> cinder --os-volume-api-version 3.14 group-snapshot-delete <group snapshot uuid> Depends-on: I2e628968afcf058113e1f1aeb851570c7f0f3a08 Partial-Implements: blueprint generic-volume-group Change-Id: I5c311fe5a6aeadd1d4fca60493f4295dc368944c
This commit is contained in:
parent
6c5a764c77
commit
f7928c4058
@ -32,7 +32,7 @@ if not LOG.handlers:
|
||||
|
||||
# key is a deprecated version and value is an alternative version.
|
||||
DEPRECATED_VERSIONS = {"1": "2"}
|
||||
MAX_VERSION = "3.13"
|
||||
MAX_VERSION = "3.14"
|
||||
|
||||
_SUBSTITUTIONS = {}
|
||||
|
||||
|
@ -37,6 +37,25 @@ def _stub_group(detailed=True, **kwargs):
|
||||
return group
|
||||
|
||||
|
||||
def _stub_group_snapshot(detailed=True, **kwargs):
|
||||
group_snapshot = {
|
||||
"name": None,
|
||||
"id": "5678",
|
||||
}
|
||||
if detailed:
|
||||
details = {
|
||||
"created_at": "2012-08-28T16:30:31.000000",
|
||||
"description": None,
|
||||
"name": None,
|
||||
"id": "5678",
|
||||
"status": "available",
|
||||
"group_id": "1234",
|
||||
}
|
||||
group_snapshot.update(details)
|
||||
group_snapshot.update(kwargs)
|
||||
return group_snapshot
|
||||
|
||||
|
||||
class FakeClient(fakes.FakeClient, client.Client):
|
||||
|
||||
def __init__(self, api_version=None, *args, **kwargs):
|
||||
@ -302,3 +321,46 @@ class FakeHTTPClient(fake_v2.FakeHTTPClient):
|
||||
else:
|
||||
raise AssertionError("Unexpected action: %s" % action)
|
||||
return (resp, {}, {})
|
||||
|
||||
def post_groups_action(self, body, **kw):
|
||||
group = _stub_group(id='1234', group_type='my_group_type',
|
||||
volume_types=['type1', 'type2'])
|
||||
resp = 202
|
||||
assert len(list(body)) == 1
|
||||
action = list(body)[0]
|
||||
if action == 'create-from-src':
|
||||
assert ('group_snapshot_id' in body[action] or
|
||||
'source_group_id' in body[action])
|
||||
else:
|
||||
raise AssertionError("Unexpected action: %s" % action)
|
||||
return (resp, {}, {'group': group})
|
||||
|
||||
#
|
||||
# group_snapshots
|
||||
#
|
||||
|
||||
def get_group_snapshots_detail(self, **kw):
|
||||
return (200, {}, {"group_snapshots": [
|
||||
_stub_group_snapshot(id='1234'),
|
||||
_stub_group_snapshot(id='4567')]})
|
||||
|
||||
def get_group_snapshots(self, **kw):
|
||||
return (200, {}, {"group_snapshots": [
|
||||
_stub_group_snapshot(detailed=False, id='1234'),
|
||||
_stub_group_snapshot(detailed=False, id='4567')]})
|
||||
|
||||
def get_group_snapshots_1234(self, **kw):
|
||||
return (200, {}, {'group_snapshot': _stub_group_snapshot(id='1234')})
|
||||
|
||||
def get_group_snapshots_5678(self, **kw):
|
||||
return (200, {}, {'group_snapshot': _stub_group_snapshot(id='5678')})
|
||||
|
||||
def post_group_snapshots(self, **kw):
|
||||
group_snap = _stub_group_snapshot()
|
||||
return (202, {}, {'group_snapshot': group_snap})
|
||||
|
||||
def put_group_snapshots_1234(self, **kw):
|
||||
return (200, {}, {'group_snapshot': {}})
|
||||
|
||||
def delete_group_snapshots_1234(self, **kw):
|
||||
return (202, {}, {})
|
||||
|
102
cinderclient/tests/unit/v3/test_group_snapshots.py
Normal file
102
cinderclient/tests/unit/v3/test_group_snapshots.py
Normal file
@ -0,0 +1,102 @@
|
||||
# Copyright (C) 2016 EMC Corporation.
|
||||
#
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import ddt
|
||||
|
||||
from cinderclient.tests.unit import utils
|
||||
from cinderclient.tests.unit.v3 import fakes
|
||||
|
||||
|
||||
cs = fakes.FakeClient()
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class GroupSnapshotsTest(utils.TestCase):
|
||||
|
||||
def test_delete_group_snapshot(self):
|
||||
s1 = cs.group_snapshots.list()[0]
|
||||
snap = s1.delete()
|
||||
self._assert_request_id(snap)
|
||||
cs.assert_called('DELETE', '/group_snapshots/1234')
|
||||
snap = cs.group_snapshots.delete('1234')
|
||||
cs.assert_called('DELETE', '/group_snapshots/1234')
|
||||
self._assert_request_id(snap)
|
||||
snap = cs.group_snapshots.delete(s1)
|
||||
cs.assert_called('DELETE', '/group_snapshots/1234')
|
||||
self._assert_request_id(snap)
|
||||
|
||||
def test_create_group_snapshot(self):
|
||||
snap = cs.group_snapshots.create('group_snap')
|
||||
cs.assert_called('POST', '/group_snapshots')
|
||||
self._assert_request_id(snap)
|
||||
|
||||
def test_create_group_snapshot_with_group_id(self):
|
||||
snap = cs.group_snapshots.create('1234')
|
||||
expected = {'group_snapshot': {'status': 'creating',
|
||||
'description': None,
|
||||
'user_id': None,
|
||||
'name': None,
|
||||
'group_id': '1234',
|
||||
'project_id': None}}
|
||||
cs.assert_called('POST', '/group_snapshots', body=expected)
|
||||
self._assert_request_id(snap)
|
||||
|
||||
def test_update_group_snapshot(self):
|
||||
s1 = cs.group_snapshots.list()[0]
|
||||
expected = {'group_snapshot': {'name': 'grp_snap2'}}
|
||||
snap = s1.update(name='grp_snap2')
|
||||
cs.assert_called('PUT', '/group_snapshots/1234', body=expected)
|
||||
self._assert_request_id(snap)
|
||||
snap = cs.group_snapshots.update('1234', name='grp_snap2')
|
||||
cs.assert_called('PUT', '/group_snapshots/1234', body=expected)
|
||||
self._assert_request_id(snap)
|
||||
snap = cs.group_snapshots.update(s1, name='grp_snap2')
|
||||
cs.assert_called('PUT', '/group_snapshots/1234', body=expected)
|
||||
self._assert_request_id(snap)
|
||||
|
||||
def test_update_group_snapshot_no_props(self):
|
||||
ret = cs.group_snapshots.update('1234')
|
||||
self.assertIsNone(ret)
|
||||
|
||||
def test_list_group_snapshot(self):
|
||||
lst = cs.group_snapshots.list()
|
||||
cs.assert_called('GET', '/group_snapshots/detail')
|
||||
self._assert_request_id(lst)
|
||||
|
||||
@ddt.data(
|
||||
{'detailed': True, 'url': '/group_snapshots/detail'},
|
||||
{'detailed': False, 'url': '/group_snapshots'}
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_list_group_snapshot_detailed(self, detailed, url):
|
||||
lst = cs.group_snapshots.list(detailed=detailed)
|
||||
cs.assert_called('GET', url)
|
||||
self._assert_request_id(lst)
|
||||
|
||||
@ddt.data(
|
||||
{'foo': 'bar'},
|
||||
{'foo': 'bar', '123': None}
|
||||
)
|
||||
def test_list_group_snapshot_with_search_opts(self, opts):
|
||||
lst = cs.group_snapshots.list(search_opts=opts)
|
||||
cs.assert_called('GET', '/group_snapshots/detail?foo=bar')
|
||||
self._assert_request_id(lst)
|
||||
|
||||
def test_get_group_snapshot(self):
|
||||
group_snapshot_id = '1234'
|
||||
snap = cs.group_snapshots.get(group_snapshot_id)
|
||||
cs.assert_called('GET', '/group_snapshots/%s' % group_snapshot_id)
|
||||
self._assert_request_id(snap)
|
@ -113,3 +113,37 @@ class GroupsTest(utils.TestCase):
|
||||
grp = cs.groups.get(group_id)
|
||||
cs.assert_called('GET', '/groups/%s' % group_id)
|
||||
self._assert_request_id(grp)
|
||||
|
||||
def test_create_group_from_src_snap(self):
|
||||
grp = cs.groups.create_from_src('5678', None, name='group')
|
||||
expected = {
|
||||
'create-from-src': {
|
||||
'status': 'creating',
|
||||
'description': None,
|
||||
'user_id': None,
|
||||
'name': 'group',
|
||||
'group_snapshot_id': '5678',
|
||||
'project_id': None,
|
||||
'source_group_id': None
|
||||
}
|
||||
}
|
||||
cs.assert_called('POST', '/groups/action',
|
||||
body=expected)
|
||||
self._assert_request_id(grp)
|
||||
|
||||
def test_create_group_from_src_group_(self):
|
||||
grp = cs.groups.create_from_src(None, '5678', name='group')
|
||||
expected = {
|
||||
'create-from-src': {
|
||||
'status': 'creating',
|
||||
'description': None,
|
||||
'user_id': None,
|
||||
'name': 'group',
|
||||
'source_group_id': '5678',
|
||||
'project_id': None,
|
||||
'group_snapshot_id': None
|
||||
}
|
||||
}
|
||||
cs.assert_called('POST', '/groups/action',
|
||||
body=expected)
|
||||
self._assert_request_id(grp)
|
||||
|
@ -261,3 +261,51 @@ class ShellTest(utils.TestCase):
|
||||
self.assertRaises(exceptions.ClientException,
|
||||
self.run_command,
|
||||
'--os-volume-api-version 3.13 group-update 1234')
|
||||
|
||||
def test_group_snapshot_list(self):
|
||||
self.run_command('--os-volume-api-version 3.14 group-snapshot-list')
|
||||
self.assert_called_anytime('GET', '/group_snapshots/detail')
|
||||
|
||||
def test_group_snapshot_show(self):
|
||||
self.run_command('--os-volume-api-version 3.14 '
|
||||
'group-snapshot-show 1234')
|
||||
self.assert_called('GET', '/group_snapshots/1234')
|
||||
|
||||
def test_group_snapshot_delete(self):
|
||||
cmd = '--os-volume-api-version 3.14 group-snapshot-delete 1234'
|
||||
self.run_command(cmd)
|
||||
self.assert_called('DELETE', '/group_snapshots/1234')
|
||||
|
||||
def test_group_snapshot_create(self):
|
||||
expected = {'group_snapshot': {'name': 'test-1',
|
||||
'description': 'test-1-desc',
|
||||
'user_id': None,
|
||||
'project_id': None,
|
||||
'group_id': '1234',
|
||||
'status': 'creating'}}
|
||||
self.run_command('--os-volume-api-version 3.14 '
|
||||
'group-snapshot-create --name test-1 '
|
||||
'--description test-1-desc 1234')
|
||||
self.assert_called_anytime('POST', '/group_snapshots', body=expected)
|
||||
|
||||
@ddt.data(
|
||||
{'grp_snap_id': '1234', 'src_grp_id': None,
|
||||
'src': '--group-snapshot 1234'},
|
||||
{'grp_snap_id': None, 'src_grp_id': '1234',
|
||||
'src': '--source-group 1234'},
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_group_create_from_src(self, grp_snap_id, src_grp_id, src):
|
||||
expected = {'create-from-src': {'name': 'test-1',
|
||||
'description': 'test-1-desc',
|
||||
'user_id': None,
|
||||
'project_id': None,
|
||||
'status': 'creating',
|
||||
'group_snapshot_id': grp_snap_id,
|
||||
'source_group_id': src_grp_id}}
|
||||
cmd = ('--os-volume-api-version 3.14 '
|
||||
'group-create-from-src --name test-1 '
|
||||
'--description test-1-desc ')
|
||||
cmd += src
|
||||
self.run_command(cmd)
|
||||
self.assert_called_anytime('POST', '/groups/action', body=expected)
|
||||
|
@ -23,6 +23,7 @@ from cinderclient.v3 import clusters
|
||||
from cinderclient.v3 import consistencygroups
|
||||
from cinderclient.v3 import capabilities
|
||||
from cinderclient.v3 import groups
|
||||
from cinderclient.v3 import group_snapshots
|
||||
from cinderclient.v3 import group_types
|
||||
from cinderclient.v3 import limits
|
||||
from cinderclient.v3 import pools
|
||||
@ -89,6 +90,7 @@ class Client(object):
|
||||
ConsistencygroupManager(self)
|
||||
self.groups = groups.GroupManager(self)
|
||||
self.cgsnapshots = cgsnapshots.CgsnapshotManager(self)
|
||||
self.group_snapshots = group_snapshots.GroupSnapshotManager(self)
|
||||
self.availability_zones = \
|
||||
availability_zones.AvailabilityZoneManager(self)
|
||||
self.pools = pools.PoolManager(self)
|
||||
|
129
cinderclient/v3/group_snapshots.py
Normal file
129
cinderclient/v3/group_snapshots.py
Normal file
@ -0,0 +1,129 @@
|
||||
# Copyright (C) 2016 EMC Corporation.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""group snapshot interface (v3)."""
|
||||
|
||||
import six
|
||||
from six.moves.urllib.parse import urlencode
|
||||
|
||||
from cinderclient import base
|
||||
from cinderclient.openstack.common.apiclient import base as common_base
|
||||
|
||||
|
||||
class GroupSnapshot(base.Resource):
|
||||
"""A group snapshot is a snapshot of a group."""
|
||||
def __repr__(self):
|
||||
return "<group_snapshot: %s>" % self.id
|
||||
|
||||
def delete(self):
|
||||
"""Delete this group snapshot."""
|
||||
return self.manager.delete(self)
|
||||
|
||||
def update(self, **kwargs):
|
||||
"""Update the name or description for this group snapshot."""
|
||||
return self.manager.update(self, **kwargs)
|
||||
|
||||
|
||||
class GroupSnapshotManager(base.ManagerWithFind):
|
||||
"""Manage :class:`GroupSnapshot` resources."""
|
||||
resource_class = GroupSnapshot
|
||||
|
||||
def create(self, group_id, name=None, description=None,
|
||||
user_id=None,
|
||||
project_id=None):
|
||||
"""Creates a group snapshot.
|
||||
|
||||
:param group_id: Name or uuid of a group
|
||||
:param name: Name of the group snapshot
|
||||
:param description: Description of the group snapshot
|
||||
:param user_id: User id derived from context
|
||||
:param project_id: Project id derived from context
|
||||
:rtype: :class:`GroupSnapshot`
|
||||
"""
|
||||
|
||||
body = {
|
||||
'group_snapshot': {
|
||||
'group_id': group_id,
|
||||
'name': name,
|
||||
'description': description,
|
||||
'user_id': user_id,
|
||||
'project_id': project_id,
|
||||
'status': "creating",
|
||||
}
|
||||
}
|
||||
|
||||
return self._create('/group_snapshots', body, 'group_snapshot')
|
||||
|
||||
def get(self, group_snapshot_id):
|
||||
"""Get a group snapshot.
|
||||
|
||||
:param group_snapshot_id: The ID of the group snapshot to get.
|
||||
:rtype: :class:`GroupSnapshot`
|
||||
"""
|
||||
return self._get("/group_snapshots/%s" % group_snapshot_id,
|
||||
"group_snapshot")
|
||||
|
||||
def list(self, detailed=True, search_opts=None):
|
||||
"""Lists all group snapshots.
|
||||
|
||||
:param detailed: list detailed info or not
|
||||
:param search_opts: search options
|
||||
:rtype: list of :class:`GroupSnapshot`
|
||||
"""
|
||||
if search_opts is None:
|
||||
search_opts = {}
|
||||
|
||||
qparams = {}
|
||||
|
||||
for opt, val in six.iteritems(search_opts):
|
||||
if val:
|
||||
qparams[opt] = val
|
||||
|
||||
query_string = "?%s" % urlencode(qparams) if qparams else ""
|
||||
|
||||
detail = ""
|
||||
if detailed:
|
||||
detail = "/detail"
|
||||
|
||||
return self._list("/group_snapshots%s%s" % (detail, query_string),
|
||||
"group_snapshots")
|
||||
|
||||
def delete(self, group_snapshot):
|
||||
"""Delete a group_snapshot.
|
||||
|
||||
:param group_snapshot: The :class:`GroupSnapshot` to delete.
|
||||
"""
|
||||
return self._delete("/group_snapshots/%s" % base.getid(group_snapshot))
|
||||
|
||||
def update(self, group_snapshot, **kwargs):
|
||||
"""Update the name or description for a group_snapshot.
|
||||
|
||||
:param group_snapshot: The :class:`GroupSnapshot` to update.
|
||||
"""
|
||||
if not kwargs:
|
||||
return
|
||||
|
||||
body = {"group_snapshot": kwargs}
|
||||
|
||||
return self._update("/group_snapshots/%s" % base.getid(group_snapshot),
|
||||
body)
|
||||
|
||||
def _action(self, action, group_snapshot, info=None, **kwargs):
|
||||
"""Perform a group_snapshot action."""
|
||||
body = {action: info}
|
||||
self.run_hooks('modify_body_for_action', body, **kwargs)
|
||||
url = '/group_snapshots/%s/action' % base.getid(group_snapshot)
|
||||
resp, body = self.api.client.post(url, body=body)
|
||||
return common_base.TupleWithMeta((resp, body), resp)
|
@ -66,6 +66,33 @@ class GroupManager(base.ManagerWithFind):
|
||||
|
||||
return self._create('/groups', body, 'group')
|
||||
|
||||
def create_from_src(self, group_snapshot_id, source_group_id,
|
||||
name=None, description=None, user_id=None,
|
||||
project_id=None):
|
||||
"""Creates a group from a group snapshot or a source group.
|
||||
|
||||
:param group_snapshot_id: UUID of a GroupSnapshot
|
||||
:param source_group_id: UUID of a source Group
|
||||
:param name: Name of the Group
|
||||
:param description: Description of the Group
|
||||
:param user_id: User id derived from context
|
||||
:param project_id: Project id derived from context
|
||||
:rtype: A dictionary containing Group metadata
|
||||
"""
|
||||
body = {'create-from-src': {'name': name,
|
||||
'description': description,
|
||||
'group_snapshot_id': group_snapshot_id,
|
||||
'source_group_id': source_group_id,
|
||||
'user_id': user_id,
|
||||
'project_id': project_id,
|
||||
'status': "creating", }}
|
||||
|
||||
self.run_hooks('modify_body_for_action', body,
|
||||
'create-from-src')
|
||||
resp, body = self.api.client.post(
|
||||
"/groups/action", body=body)
|
||||
return common_base.DictWithMeta(body['group'], resp)
|
||||
|
||||
def get(self, group_id):
|
||||
"""Get a group.
|
||||
|
||||
|
@ -98,6 +98,11 @@ def _find_cgsnapshot(cs, cgsnapshot):
|
||||
return utils.find_resource(cs.cgsnapshots, cgsnapshot)
|
||||
|
||||
|
||||
def _find_group_snapshot(cs, group_snapshot):
|
||||
"""Gets a group_snapshot by name or ID."""
|
||||
return utils.find_resource(cs.group_snapshots, group_snapshot)
|
||||
|
||||
|
||||
def _find_transfer(cs, transfer):
|
||||
"""Gets a transfer by name or ID."""
|
||||
return utils.find_resource(cs.transfers, transfer)
|
||||
@ -2773,6 +2778,46 @@ def do_consisgroup_create_from_src(cs, args):
|
||||
utils.print_dict(info)
|
||||
|
||||
|
||||
@utils.service_type('volumev3')
|
||||
@api_versions.wraps('3.14')
|
||||
@utils.arg('--group-snapshot',
|
||||
metavar='<group-snapshot>',
|
||||
help='Name or ID of a group snapshot. Default=None.')
|
||||
@utils.arg('--source-group',
|
||||
metavar='<source-group>',
|
||||
help='Name or ID of a source group. Default=None.')
|
||||
@utils.arg('--name',
|
||||
metavar='<name>',
|
||||
help='Name of a group. Default=None.')
|
||||
@utils.arg('--description',
|
||||
metavar='<description>',
|
||||
help='Description of a group. Default=None.')
|
||||
def do_group_create_from_src(cs, args):
|
||||
"""Creates a group from a group snapshot or a source group."""
|
||||
if not args.group_snapshot and not args.source_group:
|
||||
msg = ('Cannot create group because neither '
|
||||
'group snapshot nor source group is provided.')
|
||||
raise exceptions.ClientException(code=1, message=msg)
|
||||
if args.group_snapshot and args.source_group:
|
||||
msg = ('Cannot create group because both '
|
||||
'group snapshot and source group are provided.')
|
||||
raise exceptions.ClientException(code=1, message=msg)
|
||||
group_snapshot = None
|
||||
if args.group_snapshot:
|
||||
group_snapshot = _find_group_snapshot(cs, args.group_snapshot)
|
||||
source_group = None
|
||||
if args.source_group:
|
||||
source_group = _find_group(cs, args.source_group)
|
||||
info = cs.groups.create_from_src(
|
||||
group_snapshot.id if group_snapshot else None,
|
||||
source_group.id if source_group else None,
|
||||
args.name,
|
||||
args.description)
|
||||
|
||||
info.pop('links', None)
|
||||
utils.print_dict(info)
|
||||
|
||||
|
||||
@utils.arg('consistencygroup',
|
||||
metavar='<consistencygroup>', nargs='+',
|
||||
help='Name or ID of one or more consistency groups '
|
||||
@ -2950,6 +2995,41 @@ def do_cgsnapshot_list(cs, args):
|
||||
utils.print_list(cgsnapshots, columns)
|
||||
|
||||
|
||||
@utils.service_type('volumev3')
|
||||
@api_versions.wraps('3.14')
|
||||
@utils.arg('--all-tenants',
|
||||
dest='all_tenants',
|
||||
metavar='<0|1>',
|
||||
nargs='?',
|
||||
type=int,
|
||||
const=1,
|
||||
default=0,
|
||||
help='Shows details for all tenants. Admin only.')
|
||||
@utils.arg('--status',
|
||||
metavar='<status>',
|
||||
default=None,
|
||||
help='Filters results by a status. Default=None.')
|
||||
@utils.arg('--group-id',
|
||||
metavar='<group_id>',
|
||||
default=None,
|
||||
help='Filters results by a group ID. Default=None.')
|
||||
def do_group_snapshot_list(cs, args):
|
||||
"""Lists all group snapshots."""
|
||||
|
||||
all_tenants = int(os.environ.get("ALL_TENANTS", args.all_tenants))
|
||||
|
||||
search_opts = {
|
||||
'all_tenants': all_tenants,
|
||||
'status': args.status,
|
||||
'group_id': args.group_id,
|
||||
}
|
||||
|
||||
group_snapshots = cs.group_snapshots.list(search_opts=search_opts)
|
||||
|
||||
columns = ['ID', 'Status', 'Name']
|
||||
utils.print_list(group_snapshots, columns)
|
||||
|
||||
|
||||
@utils.arg('cgsnapshot',
|
||||
metavar='<cgsnapshot>',
|
||||
help='Name or ID of cgsnapshot.')
|
||||
@ -2964,6 +3044,21 @@ def do_cgsnapshot_show(cs, args):
|
||||
utils.print_dict(info)
|
||||
|
||||
|
||||
@utils.service_type('volumev3')
|
||||
@api_versions.wraps('3.14')
|
||||
@utils.arg('group_snapshot',
|
||||
metavar='<group_snapshot>',
|
||||
help='Name or ID of group snapshot.')
|
||||
def do_group_snapshot_show(cs, args):
|
||||
"""Shows group snapshot details."""
|
||||
info = dict()
|
||||
group_snapshot = _find_group_snapshot(cs, args.group_snapshot)
|
||||
info.update(group_snapshot._info)
|
||||
|
||||
info.pop('links', None)
|
||||
utils.print_dict(info)
|
||||
|
||||
|
||||
@utils.arg('consistencygroup',
|
||||
metavar='<consistencygroup>',
|
||||
help='Name or ID of a consistency group.')
|
||||
@ -2992,6 +3087,35 @@ def do_cgsnapshot_create(cs, args):
|
||||
utils.print_dict(info)
|
||||
|
||||
|
||||
@utils.service_type('volumev3')
|
||||
@api_versions.wraps('3.14')
|
||||
@utils.arg('group',
|
||||
metavar='<group>',
|
||||
help='Name or ID of a group.')
|
||||
@utils.arg('--name',
|
||||
metavar='<name>',
|
||||
default=None,
|
||||
help='Group snapshot name. Default=None.')
|
||||
@utils.arg('--description',
|
||||
metavar='<description>',
|
||||
default=None,
|
||||
help='Group snapshot description. Default=None.')
|
||||
def do_group_snapshot_create(cs, args):
|
||||
"""Creates a group snapshot."""
|
||||
group = _find_group(cs, args.group)
|
||||
group_snapshot = cs.group_snapshots.create(
|
||||
group.id,
|
||||
args.name,
|
||||
args.description)
|
||||
|
||||
info = dict()
|
||||
group_snapshot = cs.group_snapshots.get(group_snapshot.id)
|
||||
info.update(group_snapshot._info)
|
||||
|
||||
info.pop('links', None)
|
||||
utils.print_dict(info)
|
||||
|
||||
|
||||
@utils.arg('cgsnapshot',
|
||||
metavar='<cgsnapshot>', nargs='+',
|
||||
help='Name or ID of one or more cgsnapshots to be deleted.')
|
||||
@ -3010,6 +3134,26 @@ def do_cgsnapshot_delete(cs, args):
|
||||
"cgsnapshots.")
|
||||
|
||||
|
||||
@utils.service_type('volumev3')
|
||||
@api_versions.wraps('3.14')
|
||||
@utils.arg('group_snapshot',
|
||||
metavar='<group_snapshot>', nargs='+',
|
||||
help='Name or ID of one or more group snapshots to be deleted.')
|
||||
def do_group_snapshot_delete(cs, args):
|
||||
"""Removes one or more group snapshots."""
|
||||
failure_count = 0
|
||||
for group_snapshot in args.group_snapshot:
|
||||
try:
|
||||
_find_group_snapshot(cs, group_snapshot).delete()
|
||||
except Exception as e:
|
||||
failure_count += 1
|
||||
print("Delete for group snapshot %s failed: %s" %
|
||||
(group_snapshot, e))
|
||||
if failure_count == len(args.group_snapshot):
|
||||
raise exceptions.CommandError("Unable to delete any of the specified "
|
||||
"group snapshots.")
|
||||
|
||||
|
||||
@utils.arg('--detail',
|
||||
action='store_true',
|
||||
help='Show detailed information about pools.')
|
||||
|
Loading…
x
Reference in New Issue
Block a user