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-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.
|
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,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-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-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)
|
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
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
from cinderclient import api_versions
|
from cinderclient import api_versions
|
||||||
from osc_lib import exceptions
|
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.tests.unit.volume.v3 import fakes as volume_fakes
|
||||||
from openstackclient.volume.v3 import volume_group
|
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 = self.app.client_manager.volume.volume_types
|
||||||
self.volume_types_mock.reset_mock()
|
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):
|
class TestVolumeGroupCreate(TestVolumeGroup):
|
||||||
|
|
||||||
@ -43,6 +50,8 @@ class TestVolumeGroupCreate(TestVolumeGroup):
|
|||||||
'volume_types': [fake_volume_type.id],
|
'volume_types': [fake_volume_type.id],
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
fake_volume_group_snapshot = \
|
||||||
|
volume_fakes.create_one_volume_group_snapshot()
|
||||||
|
|
||||||
columns = (
|
columns = (
|
||||||
'ID',
|
'ID',
|
||||||
@ -79,6 +88,10 @@ class TestVolumeGroupCreate(TestVolumeGroup):
|
|||||||
self.fake_volume_group_type
|
self.fake_volume_group_type
|
||||||
self.volume_groups_mock.create.return_value = self.fake_volume_group
|
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.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)
|
self.cmd = volume_group.CreateVolumeGroup(self.app, None)
|
||||||
|
|
||||||
@ -115,6 +128,29 @@ class TestVolumeGroupCreate(TestVolumeGroup):
|
|||||||
self.assertEqual(self.columns, columns)
|
self.assertEqual(self.columns, columns)
|
||||||
self.assertCountEqual(self.data, data)
|
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):
|
def test_volume_group_create_with_options(self):
|
||||||
self.app.client_manager.volume.api_version = \
|
self.app.client_manager.volume.api_version = \
|
||||||
api_versions.APIVersion('3.13')
|
api_versions.APIVersion('3.13')
|
||||||
@ -176,6 +212,101 @@ class TestVolumeGroupCreate(TestVolumeGroup):
|
|||||||
'--os-volume-api-version 3.13 or greater is required',
|
'--os-volume-api-version 3.13 or greater is required',
|
||||||
str(exc))
|
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):
|
class TestVolumeGroupDelete(TestVolumeGroup):
|
||||||
|
|
||||||
|
@ -82,15 +82,17 @@ class CreateVolumeGroup(command.ShowOne):
|
|||||||
|
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super().get_parser(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',
|
'volume_group_type',
|
||||||
metavar='<volume_group_type>',
|
metavar='<volume_group_type>',
|
||||||
|
nargs='?',
|
||||||
help=_('Name or ID of volume group type to use.'),
|
help=_('Name or ID of volume group type to use.'),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'volume_types',
|
'volume_types',
|
||||||
metavar='<volume_type>',
|
metavar='<volume_type>',
|
||||||
nargs='+',
|
nargs='*',
|
||||||
default=[],
|
default=[],
|
||||||
help=_('Name or ID of volume type(s) to use.'),
|
help=_('Name or ID of volume type(s) to use.'),
|
||||||
)
|
)
|
||||||
@ -107,44 +109,101 @@ class CreateVolumeGroup(command.ShowOne):
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--availability-zone',
|
'--availability-zone',
|
||||||
metavar='<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
|
return parser
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
volume_client = self.app.client_manager.volume
|
volume_client = self.app.client_manager.volume
|
||||||
|
|
||||||
if volume_client.api_version < api_versions.APIVersion('3.13'):
|
if parsed_args.volume_group_type:
|
||||||
msg = _(
|
if volume_client.api_version < api_versions.APIVersion('3.13'):
|
||||||
"--os-volume-api-version 3.13 or greater is required to "
|
msg = _(
|
||||||
"support the 'volume group create' command"
|
"--os-volume-api-version 3.13 or greater is required to "
|
||||||
)
|
"support the 'volume group create' command"
|
||||||
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(
|
|
||||||
utils.find_resource(
|
|
||||||
volume_client.volume_types,
|
|
||||||
volume_type,
|
|
||||||
)
|
)
|
||||||
|
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(
|
||||||
|
utils.find_resource(
|
||||||
|
volume_client.volume_types,
|
||||||
|
volume_type,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
group = volume_client.groups.create(
|
group = volume_client.groups.create(
|
||||||
volume_group_type.id,
|
volume_group_type.id,
|
||||||
','.join(x.id for x in volume_types),
|
','.join(x.id for x in volume_types),
|
||||||
parsed_args.name,
|
parsed_args.name,
|
||||||
parsed_args.description,
|
parsed_args.description,
|
||||||
availability_zone=parsed_args.availability_zone)
|
availability_zone=parsed_args.availability_zone)
|
||||||
|
|
||||||
group = volume_client.groups.get(group.id)
|
group = volume_client.groups.get(group.id)
|
||||||
|
return _format_group(group)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
|
|
||||||
class DeleteVolumeGroup(command.Command):
|
class DeleteVolumeGroup(command.Command):
|
||||||
|
@ -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