Add options to create volume group from source
This patch adds ``--source-group`` and ``--group-snapshot`` options to the ``volume group create`` command to allow creating group from a source group or a group snapshot. Change-Id: I87482a5dd43c519dfdcf981635aa879914a70a5c
This commit is contained in:
parent
73b4ce88eb
commit
ec01268ea9
@ -45,7 +45,7 @@ freeze-host,volume host set --disable,Freeze and disable the specified cinder-vo
|
||||
get-capabilities,volume backend capability show,Show capabilities of a volume backend. Admin only.
|
||||
get-pools,volume backend pool list,Show pool information for backends. Admin only.
|
||||
group-create,volume group create,Creates a group. (Supported by API versions 3.13 - 3.latest)
|
||||
group-create-from-src,,Creates a group from a group snapshot or a source group. (Supported by API versions 3.14 - 3.latest)
|
||||
group-create-from-src,volume group create [--source-group|--group-snapshot],Creates a group from a group snapshot or a source group. (Supported by API versions 3.14 - 3.latest)
|
||||
group-delete,volume group delete,Removes one or more groups. (Supported by API versions 3.13 - 3.latest)
|
||||
group-disable-replication,volume group set --disable-replication,Disables replication for group. (Supported by API versions 3.38 - 3.latest)
|
||||
group-enable-replication,volume group set --enable-replication,Enables replication for group. (Supported by API versions 3.38 - 3.latest)
|
||||
|
|
@ -10,9 +10,12 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from cinderclient import api_versions
|
||||
from osc_lib import exceptions
|
||||
|
||||
from openstackclient.tests.unit import utils as tests_utils
|
||||
from openstackclient.tests.unit.volume.v3 import fakes as volume_fakes
|
||||
from openstackclient.volume.v3 import volume_group
|
||||
|
||||
@ -32,6 +35,10 @@ class TestVolumeGroup(volume_fakes.TestVolume):
|
||||
self.volume_types_mock = self.app.client_manager.volume.volume_types
|
||||
self.volume_types_mock.reset_mock()
|
||||
|
||||
self.volume_group_snapshots_mock = \
|
||||
self.app.client_manager.volume.group_snapshots
|
||||
self.volume_group_snapshots_mock.reset_mock()
|
||||
|
||||
|
||||
class TestVolumeGroupCreate(TestVolumeGroup):
|
||||
|
||||
@ -43,6 +50,8 @@ class TestVolumeGroupCreate(TestVolumeGroup):
|
||||
'volume_types': [fake_volume_type.id],
|
||||
},
|
||||
)
|
||||
fake_volume_group_snapshot = \
|
||||
volume_fakes.create_one_volume_group_snapshot()
|
||||
|
||||
columns = (
|
||||
'ID',
|
||||
@ -79,6 +88,10 @@ class TestVolumeGroupCreate(TestVolumeGroup):
|
||||
self.fake_volume_group_type
|
||||
self.volume_groups_mock.create.return_value = self.fake_volume_group
|
||||
self.volume_groups_mock.get.return_value = self.fake_volume_group
|
||||
self.volume_groups_mock.create_from_src.return_value = \
|
||||
self.fake_volume_group
|
||||
self.volume_group_snapshots_mock.get.return_value = \
|
||||
self.fake_volume_group_snapshot
|
||||
|
||||
self.cmd = volume_group.CreateVolumeGroup(self.app, None)
|
||||
|
||||
@ -115,6 +128,29 @@ class TestVolumeGroupCreate(TestVolumeGroup):
|
||||
self.assertEqual(self.columns, columns)
|
||||
self.assertCountEqual(self.data, data)
|
||||
|
||||
def test_volume_group_create_no_volume_type(self):
|
||||
self.app.client_manager.volume.api_version = \
|
||||
api_versions.APIVersion('3.13')
|
||||
|
||||
arglist = [
|
||||
self.fake_volume_group_type.id
|
||||
]
|
||||
verifylist = [
|
||||
('volume_group_type', self.fake_volume_group_type.id),
|
||||
('name', None),
|
||||
('description', None),
|
||||
('availability_zone', None),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
exc = self.assertRaises(
|
||||
exceptions.CommandError,
|
||||
self.cmd.take_action,
|
||||
parsed_args)
|
||||
self.assertIn(
|
||||
'<volume_types> is a required argument',
|
||||
str(exc))
|
||||
|
||||
def test_volume_group_create_with_options(self):
|
||||
self.app.client_manager.volume.api_version = \
|
||||
api_versions.APIVersion('3.13')
|
||||
@ -176,6 +212,101 @@ class TestVolumeGroupCreate(TestVolumeGroup):
|
||||
'--os-volume-api-version 3.13 or greater is required',
|
||||
str(exc))
|
||||
|
||||
def test_volume_group_create_from_source_group(self):
|
||||
self.app.client_manager.volume.api_version = \
|
||||
api_versions.APIVersion('3.14')
|
||||
|
||||
arglist = [
|
||||
'--source-group', self.fake_volume_group.id,
|
||||
]
|
||||
verifylist = [
|
||||
('source_group', self.fake_volume_group.id),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
self.volume_groups_mock.get.assert_has_calls(
|
||||
[mock.call(self.fake_volume_group.id),
|
||||
mock.call(self.fake_volume_group.id)])
|
||||
self.volume_groups_mock.create_from_src.assert_called_once_with(
|
||||
None,
|
||||
self.fake_volume_group.id,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
self.assertEqual(self.columns, columns)
|
||||
self.assertCountEqual(self.data, data)
|
||||
|
||||
def test_volume_group_create_from_group_snapshot(self):
|
||||
self.app.client_manager.volume.api_version = \
|
||||
api_versions.APIVersion('3.14')
|
||||
|
||||
arglist = [
|
||||
'--group-snapshot', self.fake_volume_group_snapshot.id,
|
||||
]
|
||||
verifylist = [
|
||||
('group_snapshot', self.fake_volume_group_snapshot.id),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
self.volume_group_snapshots_mock.get.assert_called_once_with(
|
||||
self.fake_volume_group_snapshot.id)
|
||||
self.volume_groups_mock.get.assert_called_once_with(
|
||||
self.fake_volume_group.id)
|
||||
self.volume_groups_mock.create_from_src.assert_called_once_with(
|
||||
self.fake_volume_group_snapshot.id,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
self.assertEqual(self.columns, columns)
|
||||
self.assertCountEqual(self.data, data)
|
||||
|
||||
def test_volume_group_create_from_src_pre_v314(self):
|
||||
self.app.client_manager.volume.api_version = \
|
||||
api_versions.APIVersion('3.13')
|
||||
|
||||
arglist = [
|
||||
'--source-group', self.fake_volume_group.id,
|
||||
]
|
||||
verifylist = [
|
||||
('source_group', self.fake_volume_group.id),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
exc = self.assertRaises(
|
||||
exceptions.CommandError,
|
||||
self.cmd.take_action,
|
||||
parsed_args)
|
||||
self.assertIn(
|
||||
'--os-volume-api-version 3.14 or greater is required',
|
||||
str(exc))
|
||||
|
||||
def test_volume_group_create_from_src_source_group_group_snapshot(self):
|
||||
self.app.client_manager.volume.api_version = \
|
||||
api_versions.APIVersion('3.14')
|
||||
|
||||
arglist = [
|
||||
'--source-group', self.fake_volume_group.id,
|
||||
'--group-snapshot', self.fake_volume_group_snapshot.id,
|
||||
]
|
||||
verifylist = [
|
||||
('source_group', self.fake_volume_group.id),
|
||||
('group_snapshot', self.fake_volume_group_snapshot.id),
|
||||
]
|
||||
|
||||
exc = self.assertRaises(tests_utils.ParserException,
|
||||
self.check_parser,
|
||||
self.cmd,
|
||||
arglist,
|
||||
verifylist)
|
||||
self.assertIn(
|
||||
'--group-snapshot: not allowed with argument --source-group',
|
||||
str(exc))
|
||||
|
||||
|
||||
class TestVolumeGroupDelete(TestVolumeGroup):
|
||||
|
||||
|
@ -82,15 +82,17 @@ class CreateVolumeGroup(command.ShowOne):
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super().get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
source_parser = parser.add_mutually_exclusive_group()
|
||||
source_parser.add_argument(
|
||||
'volume_group_type',
|
||||
metavar='<volume_group_type>',
|
||||
nargs='?',
|
||||
help=_('Name or ID of volume group type to use.'),
|
||||
)
|
||||
parser.add_argument(
|
||||
'volume_types',
|
||||
metavar='<volume_type>',
|
||||
nargs='+',
|
||||
nargs='*',
|
||||
default=[],
|
||||
help=_('Name or ID of volume type(s) to use.'),
|
||||
)
|
||||
@ -107,25 +109,44 @@ class CreateVolumeGroup(command.ShowOne):
|
||||
parser.add_argument(
|
||||
'--availability-zone',
|
||||
metavar='<availability-zone>',
|
||||
help=_('Availability zone for volume group.'),
|
||||
help=_('Availability zone for volume group. '
|
||||
'(not available if creating group from source)'),
|
||||
)
|
||||
source_parser.add_argument(
|
||||
'--source-group',
|
||||
metavar='<source-group>',
|
||||
help=_('Existing volume group (name or ID) '
|
||||
'(supported by --os-volume-api-version 3.14 or later)'),
|
||||
)
|
||||
source_parser.add_argument(
|
||||
'--group-snapshot',
|
||||
metavar='<group-snapshot>',
|
||||
help=_('Existing group snapshot (name or ID) '
|
||||
'(supported by --os-volume-api-version 3.14 or later)'),
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
volume_client = self.app.client_manager.volume
|
||||
|
||||
if parsed_args.volume_group_type:
|
||||
if volume_client.api_version < api_versions.APIVersion('3.13'):
|
||||
msg = _(
|
||||
"--os-volume-api-version 3.13 or greater is required to "
|
||||
"support the 'volume group create' command"
|
||||
)
|
||||
raise exceptions.CommandError(msg)
|
||||
if not parsed_args.volume_types:
|
||||
msg = _(
|
||||
"<volume_types> is a required argument when creating a "
|
||||
"group from group type."
|
||||
)
|
||||
raise exceptions.CommandError(msg)
|
||||
|
||||
volume_group_type = utils.find_resource(
|
||||
volume_client.group_types,
|
||||
parsed_args.volume_group_type,
|
||||
)
|
||||
|
||||
volume_types = []
|
||||
for volume_type in parsed_args.volume_types:
|
||||
volume_types.append(
|
||||
@ -143,7 +164,45 @@ class CreateVolumeGroup(command.ShowOne):
|
||||
availability_zone=parsed_args.availability_zone)
|
||||
|
||||
group = volume_client.groups.get(group.id)
|
||||
return _format_group(group)
|
||||
|
||||
else:
|
||||
if volume_client.api_version < api_versions.APIVersion('3.14'):
|
||||
msg = _(
|
||||
"--os-volume-api-version 3.14 or greater is required to "
|
||||
"support the 'volume group create "
|
||||
"[--source-group|--group-snapshot]' command"
|
||||
)
|
||||
raise exceptions.CommandError(msg)
|
||||
if (parsed_args.source_group is None and
|
||||
parsed_args.group_snapshot is None):
|
||||
msg = _(
|
||||
"Either --source-group <source_group> or "
|
||||
"'--group-snapshot <group_snapshot>' needs to be "
|
||||
"provided to run the 'volume group create "
|
||||
"[--source-group|--group-snapshot]' command"
|
||||
)
|
||||
raise exceptions.CommandError(msg)
|
||||
if parsed_args.availability_zone:
|
||||
msg = _("'--availability-zone' option will not work "
|
||||
"if creating group from source.")
|
||||
LOG.warning(msg)
|
||||
|
||||
source_group = None
|
||||
if parsed_args.source_group:
|
||||
source_group = utils.find_resource(volume_client.groups,
|
||||
parsed_args.source_group)
|
||||
group_snapshot = None
|
||||
if parsed_args.group_snapshot:
|
||||
group_snapshot = utils.find_resource(
|
||||
volume_client.group_snapshots,
|
||||
parsed_args.group_snapshot)
|
||||
group = volume_client.groups.create_from_src(
|
||||
group_snapshot.id if group_snapshot else None,
|
||||
source_group.id if source_group else None,
|
||||
parsed_args.name,
|
||||
parsed_args.description)
|
||||
group = volume_client.groups.get(group.id)
|
||||
return _format_group(group)
|
||||
|
||||
|
||||
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Added ``--source-group`` and ``--group-snapshot`` options to the
|
||||
``volume group create`` command to allow creating group from
|
||||
a source group or a group snapshot.
|
Loading…
x
Reference in New Issue
Block a user