Add 'share-network' option for share replica create.
Partial-Bug: #1925486 Depends-On: I9049dcd418fbb16d663ab8ed27b90c765fafc5d3 Change-Id: Ie1ace4aca5d5384feb311421afa13bf51e24aebe
This commit is contained in:
parent
3d052e9859
commit
db1bba7cde
@ -27,7 +27,7 @@ from manilaclient import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
MAX_VERSION = '2.69'
|
||||
MAX_VERSION = '2.72'
|
||||
MIN_VERSION = '2.0'
|
||||
DEPRECATED_VERSION = '1.0'
|
||||
_VERSIONED_METHOD_MAP = {}
|
||||
|
@ -56,6 +56,13 @@ class CreateShareReplica(command.ShowOne):
|
||||
"Supported key is only_host. Available for microversion "
|
||||
">= 2.67."),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--share-network',
|
||||
metavar='<share-network-name-or-id>',
|
||||
default=None,
|
||||
help=_('Optional network info ID or name. Available for '
|
||||
'microversion >= 2.72')
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
@ -84,6 +91,17 @@ class CreateShareReplica(command.ShowOne):
|
||||
if scheduler_hints:
|
||||
body['scheduler_hints'] = scheduler_hints
|
||||
|
||||
share_network_id = None
|
||||
if parsed_args.share_network:
|
||||
if share_client.api_version < api_versions.APIVersion("2.72"):
|
||||
raise exceptions.CommandError(
|
||||
"'share-network' option is available only starting "
|
||||
"with '2.72' API microversion.")
|
||||
share_network_id = osc_utils.find_resource(
|
||||
share_client.share_networks,
|
||||
parsed_args.share_network).id
|
||||
body['share_network'] = share_network_id
|
||||
|
||||
share_replica = share_client.share_replicas.create(**body)
|
||||
if parsed_args.wait:
|
||||
if not osc_utils.wait_for_status(
|
||||
|
@ -480,11 +480,15 @@ class BaseTestCase(base.ClientTestBase):
|
||||
@classmethod
|
||||
def create_share_replica(cls, share_id, client=None,
|
||||
wait_for_creation=True, cleanup_in_class=False,
|
||||
availability_zone=None, share_network=None,
|
||||
microversion=None):
|
||||
client = client or cls.get_user_client()
|
||||
|
||||
share_replica = client.create_share_replica(
|
||||
share_id, microversion=microversion)
|
||||
share_id,
|
||||
availability_zone=availability_zone,
|
||||
share_network=share_network,
|
||||
microversion=microversion)
|
||||
if wait_for_creation:
|
||||
share_replica = client.wait_for_share_replica_status(
|
||||
share_replica['id'])
|
||||
|
@ -1907,12 +1907,18 @@ class ManilaCLIClient(base.CLIClient):
|
||||
|
||||
# Share replicas
|
||||
|
||||
def create_share_replica(self, share, microversion=None):
|
||||
def create_share_replica(self, share, availability_zone=None,
|
||||
share_network=None, microversion=None):
|
||||
"""Create a share replica.
|
||||
|
||||
:param share: str -- Name or ID of a share to create a replica of
|
||||
"""
|
||||
cmd = "share-replica-create %s" % share
|
||||
if availability_zone is not None:
|
||||
cmd += " --availability_zone " + availability_zone
|
||||
if share_network is not None:
|
||||
cmd += " --share_network " + share_network
|
||||
|
||||
replica = self.manila(cmd, microversion=microversion)
|
||||
return output_parser.details(replica)
|
||||
|
||||
|
@ -326,13 +326,16 @@ class OSCClientTestBase(base.ClientTestBase):
|
||||
return share_network_obj
|
||||
|
||||
def create_share_replica(self, share, availability_zone=None,
|
||||
wait=None, add_cleanup=True):
|
||||
share_network=None, wait=None,
|
||||
add_cleanup=True):
|
||||
cmd = (f'replica create {share}')
|
||||
|
||||
if availability_zone:
|
||||
cmd = cmd + f' --availability-zone {availability_zone}'
|
||||
if wait:
|
||||
cmd = cmd + ' --wait'
|
||||
if share_network:
|
||||
cmd = cmd + ' --share-network %s' % share_network
|
||||
|
||||
replica_object = self.dict_result('share', cmd)
|
||||
self._wait_for_object_status(
|
||||
|
53
manilaclient/tests/functional/osc/test_share_replicas.py
Normal file
53
manilaclient/tests/functional/osc/test_share_replicas.py
Normal file
@ -0,0 +1,53 @@
|
||||
# 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.
|
||||
|
||||
from manilaclient import config
|
||||
from manilaclient.tests.functional.osc import base
|
||||
from tempest.lib.common.utils import data_utils
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
class ShareReplicasCLITest(base.OSCClientTestBase):
|
||||
|
||||
def _create_share_and_replica(self, add_cleanup=True):
|
||||
replication_type = CONF.replication_type
|
||||
share_type = self.create_share_type(
|
||||
data_utils.rand_name('test_share_type'),
|
||||
dhss=True,
|
||||
extra_specs={'replication_type': replication_type})
|
||||
share_network = self.create_share_network(name='test_share_network')
|
||||
share = self.create_share(share_type=share_type['name'],
|
||||
share_network=share_network['id'])
|
||||
replica = self.create_share_replica(share['id'],
|
||||
share_network=share_network['id'],
|
||||
wait=True,
|
||||
add_cleanup=add_cleanup)
|
||||
return replica
|
||||
|
||||
def test_share_replica_create(self):
|
||||
share_replica = self._create_share_and_replica()
|
||||
share_replica_list = self.listing_result('share replica', 'list')
|
||||
self.assertTableStruct(share_replica_list, [
|
||||
'ID',
|
||||
'Status',
|
||||
'Share ID',
|
||||
])
|
||||
self.assertIn(share_replica['id'],
|
||||
[item['ID'] for item in share_replica_list])
|
||||
|
||||
def test_share_replica_delete(self):
|
||||
share_replica = self._create_share_and_replica(add_cleanup=False)
|
||||
self.openstack(
|
||||
f'share replica delete {share_replica["id"]}'
|
||||
)
|
||||
self.check_object_deleted('share replica', share_replica["id"])
|
49
manilaclient/tests/functional/test_share_replicas.py
Normal file
49
manilaclient/tests/functional/test_share_replicas.py
Normal file
@ -0,0 +1,49 @@
|
||||
# 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.
|
||||
|
||||
from manilaclient import config
|
||||
from manilaclient.tests.functional import base
|
||||
from manilaclient.tests.functional import utils
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@utils.skip_if_microversion_not_supported('2.72')
|
||||
class ShareReplicasTest(base.BaseTestCase):
|
||||
|
||||
def _create_share_and_replica(self):
|
||||
replication_type = CONF.replication_type
|
||||
share_type = self.create_share_type(
|
||||
driver_handles_share_servers=True,
|
||||
extra_specs={'replication_type': replication_type})
|
||||
share_network = self.create_share_network()
|
||||
share = self.create_share(
|
||||
share_type=share_type['ID'],
|
||||
share_network=share_network['id'],
|
||||
client=self.get_user_client())
|
||||
share_replica = self.create_share_replica(
|
||||
share['id'],
|
||||
share_network=share_network['id'],
|
||||
wait_for_creation=True,
|
||||
client=self.get_user_client())
|
||||
return share, share_replica
|
||||
|
||||
def test_share_replica_create(self):
|
||||
share, share_replica = self._create_share_and_replica()
|
||||
self.assertEqual(share['id'], share_replica['share_id'])
|
||||
|
||||
def test_share_replica_delete(self):
|
||||
share, share_replica = self._create_share_and_replica()
|
||||
self.user_client.delete_share_replica(share_replica['id'])
|
||||
self.user_client.wait_for_share_replica_deletion(share_replica['id'])
|
@ -16,7 +16,6 @@ from osc_lib import exceptions
|
||||
from osc_lib import utils as oscutils
|
||||
|
||||
from manilaclient import api_versions
|
||||
from manilaclient.api_versions import MAX_VERSION
|
||||
from manilaclient.common import cliutils
|
||||
|
||||
from manilaclient.osc import utils
|
||||
@ -37,7 +36,7 @@ class TestShareReplica(manila_fakes.TestShare):
|
||||
self.replicas_mock = self.app.client_manager.share.share_replicas
|
||||
self.replicas_mock.reset_mock()
|
||||
self.app.client_manager.share.api_version = api_versions.APIVersion(
|
||||
MAX_VERSION)
|
||||
api_versions.MAX_VERSION)
|
||||
|
||||
self.replica_el_mock = (
|
||||
self.app.client_manager
|
||||
@ -179,6 +178,39 @@ class TestShareReplicaCreate(TestShareReplica):
|
||||
self.cmd.take_action,
|
||||
parsed_args)
|
||||
|
||||
def test_share_replica_create_share_network(self):
|
||||
self.app.client_manager.share.api_version = api_versions.APIVersion(
|
||||
"2.72")
|
||||
|
||||
arglist = [
|
||||
self.share.id,
|
||||
'--availability-zone', self.share.availability_zone,
|
||||
'--share-network', self.share.share_network_id
|
||||
]
|
||||
verifylist = [
|
||||
('share', self.share.id),
|
||||
('availability_zone', self.share.availability_zone),
|
||||
('share_network', self.share.share_network_id)
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
if self.share.share_network_id:
|
||||
self.replicas_mock.create.assert_called_with(
|
||||
share=self.share,
|
||||
availability_zone=self.share.availability_zone,
|
||||
share_network=self.share.share_network_id
|
||||
)
|
||||
else:
|
||||
self.replicas_mock.create.assert_called_with(
|
||||
share=self.share,
|
||||
availability_zone=self.share.availability_zone,
|
||||
)
|
||||
|
||||
self.assertCountEqual(self.columns, columns)
|
||||
self.assertCountEqual(self.data, data)
|
||||
|
||||
def test_share_replica_create_wait(self):
|
||||
arglist = [
|
||||
self.share.id,
|
||||
|
@ -18,6 +18,7 @@ from unittest import mock
|
||||
import ddt
|
||||
|
||||
from manilaclient import api_versions
|
||||
from manilaclient.common import constants
|
||||
from manilaclient.tests.unit import utils
|
||||
from manilaclient.tests.unit.v2 import fakes
|
||||
from manilaclient.v2 import share_replicas
|
||||
@ -37,17 +38,20 @@ class ShareReplicasTest(utils.TestCase):
|
||||
self.manager = share_replicas.ShareReplicaManager(
|
||||
fakes.FakeClient(api_version=microversion))
|
||||
|
||||
def test_create(self):
|
||||
@ddt.data("2.11",
|
||||
constants.REPLICA_PRE_GRADUATION_VERSION,
|
||||
constants.REPLICA_GRADUATION_VERSION)
|
||||
def test_create(self, microversion):
|
||||
api_version = api_versions.APIVersion(microversion)
|
||||
values = {
|
||||
'availability_zone': 'az1',
|
||||
'share': 's1',
|
||||
}
|
||||
self._create_common(values)
|
||||
|
||||
def _create_common(self, values):
|
||||
|
||||
with mock.patch.object(self.manager, '_create', fakes.fake_create):
|
||||
result = self.manager.create(**values)
|
||||
manager = share_replicas.ShareReplicaManager(
|
||||
fakes.FakeClient(api_version=api_version))
|
||||
with mock.patch.object(manager, '_create', fakes.fake_create):
|
||||
result = manager.create(**values)
|
||||
|
||||
values['share_id'] = values.pop('share')
|
||||
body_expected = {share_replicas.RESOURCE_NAME: values}
|
||||
@ -55,6 +59,27 @@ class ShareReplicasTest(utils.TestCase):
|
||||
self.assertEqual(share_replicas.RESOURCE_NAME, result['resp_key'])
|
||||
self.assertEqual(body_expected, result['body'])
|
||||
|
||||
@ddt.data("2.72")
|
||||
def test_create_with_share_network(self, microversion):
|
||||
api_version = api_versions.APIVersion(microversion)
|
||||
values = {
|
||||
'availability_zone': 'az1',
|
||||
'share': 's1',
|
||||
'share_network': 'sn1',
|
||||
}
|
||||
|
||||
manager = share_replicas.ShareReplicaManager(
|
||||
fakes.FakeClient(api_version=api_version))
|
||||
with mock.patch.object(manager, '_create', fakes.fake_create):
|
||||
result = manager.create(**values)
|
||||
|
||||
values['share_id'] = values.pop('share')
|
||||
values['share_network_id'] = values.pop('share_network')
|
||||
body_expected = {share_replicas.RESOURCE_NAME: values}
|
||||
self.assertEqual(share_replicas.RESOURCES_PATH, result['url'])
|
||||
self.assertEqual(share_replicas.RESOURCE_NAME, result['resp_key'])
|
||||
self.assertEqual(body_expected, result['body'])
|
||||
|
||||
def test_delete_str(self):
|
||||
with mock.patch.object(self.manager, '_delete', mock.Mock()):
|
||||
self.manager.delete(FAKE_REPLICA)
|
||||
|
@ -120,14 +120,23 @@ class ShareReplicaManager(base.ManagerWithFind):
|
||||
return self._create_share_replica(
|
||||
share, availability_zone=availability_zone)
|
||||
|
||||
@api_versions.wraps("2.67") # noqa
|
||||
@api_versions.wraps("2.67", "2.71") # noqa
|
||||
def create(self, share, availability_zone=None, scheduler_hints=None): # noqa F811
|
||||
return self._create_share_replica(
|
||||
share, availability_zone=availability_zone,
|
||||
scheduler_hints=scheduler_hints)
|
||||
|
||||
@api_versions.wraps("2.72") # noqa
|
||||
def create(self, share, # pylint: disable=function-redefined # noqa F811
|
||||
availability_zone=None, scheduler_hints=None,
|
||||
share_network=None):
|
||||
return self._create_share_replica(
|
||||
share, availability_zone=availability_zone,
|
||||
scheduler_hints=scheduler_hints,
|
||||
share_network=share_network)
|
||||
|
||||
def _create_share_replica(self, share, availability_zone=None,
|
||||
scheduler_hints=None):
|
||||
scheduler_hints=None, share_network=None):
|
||||
"""Create a replica for a share.
|
||||
|
||||
:param share: The share to create the replica of. Can be the share
|
||||
@ -135,6 +144,7 @@ class ShareReplicaManager(base.ManagerWithFind):
|
||||
:param availability_zone: The 'availability_zone' object or its UUID.
|
||||
:param scheduler_hints: The scheduler_hints as key=value pair. Only
|
||||
supported key is 'only_host'.
|
||||
:param share_network: either share network object or its UUID.
|
||||
"""
|
||||
|
||||
share_id = base.getid(share)
|
||||
@ -145,6 +155,10 @@ class ShareReplicaManager(base.ManagerWithFind):
|
||||
|
||||
if scheduler_hints:
|
||||
body['scheduler_hints'] = scheduler_hints
|
||||
|
||||
if share_network:
|
||||
body['share_network_id'] = base.getid(share_network)
|
||||
|
||||
return self._create(RESOURCES_PATH,
|
||||
{RESOURCE_NAME: body},
|
||||
RESOURCE_NAME)
|
||||
|
@ -6162,7 +6162,7 @@ def do_share_replica_create(cs, args):
|
||||
_print_share_replica(cs, replica)
|
||||
|
||||
|
||||
@api_versions.wraps("2.67")
|
||||
@api_versions.wraps("2.67", "2.71")
|
||||
@cliutils.arg(
|
||||
'share',
|
||||
metavar='<share>',
|
||||
@ -6208,6 +6208,67 @@ def do_share_replica_create(cs, args): # noqa
|
||||
_print_share_replica(cs, replica)
|
||||
|
||||
|
||||
@api_versions.wraps("2.72")
|
||||
@cliutils.arg(
|
||||
'share',
|
||||
metavar='<share>',
|
||||
help='Name or ID of the share to replicate.')
|
||||
@cliutils.arg(
|
||||
'--availability-zone',
|
||||
'--availability_zone',
|
||||
'--az',
|
||||
default=None,
|
||||
action='single_alias',
|
||||
metavar='<availability-zone>',
|
||||
help='Optional Availability zone in which replica should be created.')
|
||||
@cliutils.arg(
|
||||
'--scheduler-hints',
|
||||
'--scheduler_hints',
|
||||
'--sh',
|
||||
metavar='<key=value>',
|
||||
nargs='*',
|
||||
help='Scheduler hints for the share replica as key=value pairs, '
|
||||
'Supported key is only_host. Available for microversion >= 2.67. ',
|
||||
default=None)
|
||||
@cliutils.arg(
|
||||
'--share-network',
|
||||
'--share_network',
|
||||
metavar='<network-info>',
|
||||
default=None,
|
||||
action='single_alias',
|
||||
help='Optional network info ID or name. '
|
||||
'Available only for microversion >= 2.72')
|
||||
def do_share_replica_create(cs, args): # noqa
|
||||
"""Create a share replica."""
|
||||
share = _find_share(cs, args.share)
|
||||
|
||||
scheduler_hints = {}
|
||||
if args.scheduler_hints:
|
||||
hints = _extract_key_value_options(args, 'scheduler_hints')
|
||||
if 'only_host' not in hints.keys() or len(hints) > 1:
|
||||
raise exceptions.CommandError(
|
||||
"The only valid key supported with the --scheduler-hints "
|
||||
"argument is 'only_host'.")
|
||||
scheduler_hints['only_host'] = hints.get('only_host')
|
||||
|
||||
share_network = None
|
||||
if args.share_network:
|
||||
share_network = _find_share_network(cs, args.share_network)
|
||||
|
||||
body = {
|
||||
'share': share,
|
||||
'availability_zone': args.availability_zone,
|
||||
}
|
||||
if scheduler_hints:
|
||||
body['scheduler_hints'] = scheduler_hints
|
||||
|
||||
if share_network:
|
||||
body['share_network'] = share_network
|
||||
|
||||
replica = cs.share_replicas.create(**body)
|
||||
_print_share_replica(cs, replica)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'replica',
|
||||
metavar='<replica>',
|
||||
|
@ -0,0 +1,8 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
`Bug #1925486 <https://bugs.launchpad.net/manila/+bug/1925486>`_
|
||||
Share replica create command does not support share network option and
|
||||
manila internally uses parent share's share network. Fixed it to allow any
|
||||
share network by providing option ``share-network`` starting with microversion
|
||||
'2.72'.
|
Loading…
x
Reference in New Issue
Block a user