Support multiple subnets per AZ

Add new command ``share-network-subnet-create-check`` to
check if a new subnet configuration can be allocated to a
share-network. Bump CLI version to support the multiple
subnets feature and fix the list operation.

The equivalent OSC command is also added. Run the subnet
create command using the new option --check-only.

Depends-On: I7de9de4ae509182e9494bba604979cce03acceec
Partially-Implements: blueprint multiple-share-network-subnets
Signed-off-by: Andre Beltrami <debeltrami@gmail.com>
Co-Authored-by: Felipe Rodrigues <felipefuty01@gmail.com>
Change-Id: I7702f458f6bca5e3947479a13a843f30873597a7
This commit is contained in:
Felipe Rodrigues 2022-01-28 15:00:21 -03:00
parent 27bf8ec4e7
commit 586c6030ed
10 changed files with 331 additions and 8 deletions

View File

@ -17,6 +17,7 @@ from osc_lib.command import command
from osc_lib import exceptions
from osc_lib import utils as oscutils
from manilaclient import api_versions
from manilaclient.common._i18n import _
@ -59,11 +60,38 @@ class CreateShareNetworkSubnet(command.ShowOne):
"considered as being available across all availability "
"zones.")
)
parser.add_argument(
'--check-only',
default=False,
action='store_true',
help=_("Run a dry-run of a share network subnet create. "
"Available only for microversion >= 2.70.")
)
parser.add_argument(
'--restart-check',
default=False,
action='store_true',
help=_("Restart a dry-run of a share network subnet create. "
"Helpful when check results are stale. "
"Available only for microversion >= 2.70.")
)
return parser
def take_action(self, parsed_args):
share_client = self.app.client_manager.share
# check and restart check during create is only available from 2.70.
if (parsed_args.check_only and
share_client.api_version < api_versions.APIVersion("2.70")):
raise exceptions.CommandError(
"Check only can be specified only with manila API "
"version >= 2.70.")
if (parsed_args.restart_check and
share_client.api_version < api_versions.APIVersion("2.70")):
raise exceptions.CommandError(
"Restart check can be specified only with manila API "
"version >= 2.70.")
if xor(bool(parsed_args.neutron_net_id),
bool(parsed_args.neutron_subnet_id)):
raise exceptions.CommandError(
@ -75,13 +103,24 @@ class CreateShareNetworkSubnet(command.ShowOne):
share_client.share_networks,
parsed_args.share_network).id
share_network_subnet = share_client.share_network_subnets.create(
neutron_net_id=parsed_args.neutron_net_id,
neutron_subnet_id=parsed_args.neutron_subnet_id,
availability_zone=parsed_args.availability_zone,
share_network_id=share_network_id
)
subnet_data = share_network_subnet._info
if parsed_args.check_only or parsed_args.restart_check:
subnet_create_check = (
share_client.share_networks.share_network_subnet_create_check(
neutron_net_id=parsed_args.neutron_net_id,
neutron_subnet_id=parsed_args.neutron_subnet_id,
availability_zone=parsed_args.availability_zone,
reset_operation=parsed_args.restart_check,
share_network_id=share_network_id)
)
subnet_data = subnet_create_check[1]
else:
share_network_subnet = share_client.share_network_subnets.create(
neutron_net_id=parsed_args.neutron_net_id,
neutron_subnet_id=parsed_args.neutron_subnet_id,
availability_zone=parsed_args.availability_zone,
share_network_id=share_network_id
)
subnet_data = share_network_subnet._info
return self.dict2columns(subnet_data)

View File

@ -669,6 +669,26 @@ class ManilaCLIClient(base.CLIClient):
SHARE_NETWORK, res_id=share_network, interval=2, timeout=6,
microversion=microversion)
def share_network_subnet_create_check(
self, share_network_id, neutron_net_id=None,
neutron_subnet_id=None, availability_zone=None, reset=False,
microversion=None):
params = self._combine_share_network_subnet_data(
neutron_net_id=neutron_net_id,
neutron_subnet_id=neutron_subnet_id,
availability_zone=availability_zone)
cmd = (
'share-network-subnet-create-check %(network_id)s '
'%(params)s' % {
'network_id': share_network_id,
'params': params})
if reset:
cmd += '--reset %s' % reset
return output_parser.details(
self.manila(cmd, microversion=microversion))
# Share Network Subnets
def _combine_share_network_subnet_data(self, neutron_net_id=None,

View File

@ -390,3 +390,21 @@ class OSCClientTestBase(base.ClientTestBase):
f'{access_id} ')
self.dict_result('share', cmd)
def check_create_network_subnet(self, share_network, neutron_net_id=None,
neutron_subnet_id=None,
availability_zone=None,
restart_check=None):
cmd = f'network subnet create {share_network} --check-only'
if neutron_net_id:
cmd += f' --neutron-net-id {neutron_net_id}'
if neutron_subnet_id:
cmd += f' --neutron-subnet-id {neutron_subnet_id}'
if availability_zone:
cmd += f' --availability-zone {availability_zone}'
if restart_check:
cmd += f' --restart-check'
check_result = self.dict_result('share', cmd)
return check_result

View File

@ -0,0 +1,37 @@
# Copyright 2022 NetApp, Inc.
# 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.tests.functional.osc import base
class ShareNetworkSubnetsCLITest(base.OSCClientTestBase):
def test_openstack_share_network_create_check(self):
share_network = self.create_share_network()
check_result = self.check_create_network_subnet(
share_network['id'])
self.assertEqual('True', check_result['compatible'])
self.assertEqual('{}', check_result['hosts_check_result'])
def test_openstack_share_network_create_check_restart(self):
share_network = self.create_share_network()
check_result = self.check_create_network_subnet(
share_network['id'], restart_check=True)
self.assertEqual('True', check_result['compatible'])
self.assertEqual('{}', check_result['hosts_check_result'])

View File

@ -397,6 +397,39 @@ class ShareNetworksReadWriteTest(base.BaseTestCase):
self.assertEqual(len(network_services), 1)
self.assertEqual(network_services[0]['name'], new_name)
def test_share_network_subnet_create_check(self):
share_network = self.create_share_network(
client=self.user_client,
description='fakedescription',
)
check_result = (
self.user_client.share_network_subnet_create_check(
share_network['id'], neutron_net_id='fake_neutron_net_id',
neutron_subnet_id='fake_neutron_subnet_id'))
self.assertEqual(check_result['compatible'], 'True')
@ddt.data(
{'neutron_net_id': None, 'neutron_subnet_id': 'fake_subnet_id'},
{'neutron_net_id': 'fake_net_id', 'neutron_subnet_id': None},
{'availability_zone': 'invalid_availability_zone'},
)
def test_check_add_share_network_subnet_with_invalid_params(self, params):
self.assertRaises(
tempest_lib_exc.CommandFailed,
self.user_client.share_network_subnet_create_check,
self.sn['id'],
**params)
def test_check_add_share_network_subnet_to_invalid_share_network(self):
self.assertRaises(
tempest_lib_exc.CommandFailed,
self.user_client.share_network_subnet_create_check,
'invalid_share_network',
self.neutron_net_id,
self.neutron_subnet_id)
class ShareNetworkSecurityServiceCheckReadWriteTests(base.BaseTestCase):
protocol = None

View File

@ -10,10 +10,13 @@
# License for the specific language governing permissions and limitations
# under the License.
#
from unittest import mock
import uuid
import ddt
from osc_lib import exceptions
from manilaclient import api_versions
from manilaclient.osc.v2 import share_network_subnets as osc_share_subnets
from manilaclient.tests.unit.osc import osc_utils
from manilaclient.tests.unit.osc.v2 import fakes as manila_fakes
@ -32,6 +35,7 @@ class TestShareNetworkSubnet(manila_fakes.TestShare):
self.share_subnets_mock.reset_mock()
@ddt.ddt
class TestShareNetworkSubnetCreate(TestShareNetworkSubnet):
def setUp(self):
@ -105,6 +109,60 @@ class TestShareNetworkSubnetCreate(TestShareNetworkSubnet):
self.cmd.take_action,
parsed_args)
@ddt.data({'check_only': False, 'restart_check': True},
{'check_only': True, 'restart_check': True},
{'check_only': True, 'restart_check': False})
@ddt.unpack
def test_share_network_subnet_create_check_api_version_exception(
self, check_only, restart_check):
self.app.client_manager.share.api_version = api_versions.APIVersion(
'2.69'
)
arglist = [
self.share_network.id,
]
verifylist = [
('share_network', self.share_network.id),
]
if check_only:
arglist.append('--check-only')
verifylist.append(('check_only', True))
if restart_check:
arglist.append('--restart-check')
verifylist.append(('restart_check', True))
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises(
exceptions.CommandError, self.cmd.take_action, parsed_args)
@ddt.data(True, False)
def test_share_network_subnet_create_check(self, restart_check):
self.app.client_manager.share.api_version = api_versions.APIVersion(
'2.70'
)
self.share_networks_mock.share_network_subnet_create_check = (
mock.Mock(return_value=(200, {'compatible': True})))
arglist = [
self.share_network.id,
'--check-only'
]
verifylist = [
('share_network', self.share_network.id),
('check_only', True),
]
if restart_check:
arglist.append('--restart-check')
verifylist.append(('restart_check', True))
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
(self.share_networks_mock.share_network_subnet_create_check
.assert_called_once_with(
share_network_id=self.share_network.id, neutron_net_id=None,
neutron_subnet_id=None, availability_zone=None,
reset_operation=restart_check))
class TestShareNetworkSubnetDelete(TestShareNetworkSubnet):

View File

@ -279,3 +279,23 @@ class ShareNetworkTest(utils.TestCase):
expected_path,
share_nw,
expected_body)
def test_share_network_subnet_create_check(self):
share_nw = self._FakeShareNetwork()
expected_path = 'share_network_subnet_create_check'
expected_body = {
'neutron_net_id': self.values['neutron_net_id'],
'neutron_subnet_id': self.values['neutron_subnet_id'],
'reset_operation': False
}
with mock.patch.object(self.manager, '_action', mock.Mock()):
self.manager.share_network_subnet_create_check(
share_nw, self.values['neutron_net_id'],
self.values['neutron_subnet_id'])
self.manager._action.assert_called_once_with(
expected_path,
share_nw,
expected_body)

View File

@ -321,3 +321,30 @@ class ShareNetworkManager(base.ManagerWithFind):
"""
return self._action('reset_status', share_network,
{"status": state})
@api_versions.wraps("2.70")
def share_network_subnet_create_check(self, share_network_id,
neutron_net_id=None,
neutron_subnet_id=None,
availability_zone=None,
reset_operation=False):
"""Check if share network subnet can be created in given share network.
:param share_network_id: ID of the Share network
:param neutron_net_id: ID of Neutron network
:param neutron_subnet_id: ID of Neutron subnet
:param availability_zone: Name of the target availability zone
:param reset_operation: Start over the check operation
:rtype: :class:`ShareNetworkSubnet`
"""
values = {}
if neutron_net_id:
values['neutron_net_id'] = neutron_net_id
if neutron_subnet_id:
values['neutron_subnet_id'] = neutron_subnet_id
if availability_zone:
values['availability_zone'] = availability_zone
values['reset_operation'] = reset_operation
return self._action('share_network_subnet_create_check',
share_network_id, values)

View File

@ -4006,6 +4006,67 @@ def do_share_network_subnet_create(cs, args):
cliutils.print_dict(info)
@cliutils.arg(
'share_network',
metavar='<share-network>',
help='Share network name or ID.')
@cliutils.arg(
'--neutron-net-id',
'--neutron-net_id', '--neutron_net_id', '--neutron_net-id',
metavar='<neutron-net-id>',
default=None,
action='single_alias',
help="Neutron network ID. Used to set up network for share servers. "
"Optional, Default = None.")
@cliutils.arg(
'--neutron-subnet-id',
'--neutron-subnet_id', '--neutron_subnet_id', '--neutron_subnet-id',
metavar='<neutron-subnet-id>',
default=None,
action='single_alias',
help="Neutron subnet ID. Used to set up network for share servers. "
"This subnet should belong to specified neutron network. "
"Optional, Default = None.")
@cliutils.arg(
'--availability-zone',
'--availability_zone',
'--az',
default=None,
action='single_alias',
metavar='<availability-zone>',
help='Optional availability zone that the subnet is available within '
'(Default=None). If None, the subnet will be considered as being '
'available across all availability zones.')
@cliutils.arg(
'--reset',
metavar='<True|False>',
choices=['True', 'False'],
required=False,
default=False,
help='Reset and start again the check operation.'
'(Optional, Default=False)')
@api_versions.wraps("2.70")
def do_share_network_subnet_create_check(cs, args):
"""Check if a new subnet can be added to a share network."""
if xor(bool(args.neutron_net_id), bool(args.neutron_subnet_id)):
raise exceptions.CommandError(
"Both neutron_net_id and neutron_subnet_id should be specified. "
"Alternatively, neither of them should be specified.")
share_network = _find_share_network(cs, args.share_network)
values = {
'neutron_net_id': args.neutron_net_id,
'neutron_subnet_id': args.neutron_subnet_id,
'availability_zone': args.availability_zone,
'reset_operation': args.reset,
}
subnet_create_check = (
cs.share_networks.share_network_subnet_create_check(
share_network.id, **values))
# result[0] is response code, result[1] is dict body
cliutils.print_dict(subnet_create_check[1])
@cliutils.arg(
'share_network',
metavar='<share-network>',
@ -4434,10 +4495,14 @@ def do_share_server_list(cs, args):
raise exceptions.CommandError(
"Share network subnet option is only available with manila "
"API version >= 2.51")
else:
elif cs.api_version < api_versions.APIVersion("2.70"):
search_opts.update({
'share_network_subnet_id': args.share_network_subnet})
fields.append("Share Network Subnet Id")
else:
search_opts.update({
'share_network_subnet_id': args.share_network_subnet})
fields.append("Share Network Subnet IDs")
if args.columns is not None:
fields = _split_columns(columns=args.columns)

View File

@ -0,0 +1,6 @@
---
features:
- The command `share-network-subnet-create-check` was added. This command
will check if the share network subnet can be created in a specific share
network based on the cloud support. The OSC equivalent command is also
added, run the subnet create with the new option --check-only.