Merge "Fix neutron validation in share network creation"

This commit is contained in:
Zuul
2025-10-30 20:00:40 +00:00
committed by Gerrit Code Review
5 changed files with 259 additions and 8 deletions

View File

@@ -110,13 +110,37 @@ class CreateShareNetworkSubnet(command.ShowOne):
"Property can be specified only with manila API "
"version >= 2.78.")
if xor(bool(parsed_args.neutron_net_id),
bool(parsed_args.neutron_subnet_id)):
neutron_client = getattr(self.app.client_manager, 'network', None)
neutron_net_id = parsed_args.neutron_net_id
neutron_subnet_id = parsed_args.neutron_subnet_id
if xor(bool(neutron_net_id),
bool(neutron_subnet_id)):
raise exceptions.CommandError(
"Both neutron_net_id and neutron_subnet_id should be "
"specified. Alternatively, neither of them should be "
"specified.")
if neutron_client and neutron_net_id:
try:
neutron_net_id = neutron_client.find_network(
neutron_net_id,
ignore_missing=False).id
except Exception:
raise exceptions.CommandError(
f"Neutron network '{neutron_net_id}'"
f" not found.")
if neutron_client and neutron_subnet_id:
try:
neutron_subnet_id = neutron_client.find_subnet(
neutron_subnet_id,
ignore_missing=False).id
except Exception:
raise exceptions.CommandError(
f"Neutron subnet '{neutron_subnet_id}'"
f" not found.")
share_network_id = oscutils.find_resource(
share_client.share_networks,
parsed_args.share_network).id
@@ -129,8 +153,8 @@ class CreateShareNetworkSubnet(command.ShowOne):
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,
neutron_net_id=neutron_net_id,
neutron_subnet_id=neutron_subnet_id,
availability_zone=parsed_args.availability_zone,
reset_operation=parsed_args.restart_check,
share_network_id=share_network_id)
@@ -147,8 +171,8 @@ class CreateShareNetworkSubnet(command.ShowOne):
subnet_data[k] = dict_values
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,
neutron_net_id=neutron_net_id,
neutron_subnet_id=neutron_subnet_id,
availability_zone=parsed_args.availability_zone,
share_network_id=share_network_id,
metadata=parsed_args.property

View File

@@ -300,6 +300,28 @@ class CreateShareNetwork(command.ShowOne):
def take_action(self, parsed_args):
share_client = self.app.client_manager.share
neutron_client = getattr(self.app.client_manager, 'network', None)
neutron_net_id = parsed_args.neutron_net_id
neutron_subnet_id = parsed_args.neutron_subnet_id
if neutron_client and neutron_net_id:
try:
neutron_net_id = neutron_client.find_network(
neutron_net_id,
ignore_missing=False).id
except Exception:
raise exceptions.CommandError(
f"Neutron network '{parsed_args.neutron_net_id}'"
f" not found.")
if neutron_client and neutron_subnet_id:
try:
neutron_subnet_id = neutron_client.find_subnet(
neutron_subnet_id,
ignore_missing=False).id
except Exception:
raise exceptions.CommandError(
f"Neutron subnet '{parsed_args.neutron_subnet_id}'"
f" not found.")
availability_zone = None
if (parsed_args.availability_zone and
@@ -313,8 +335,8 @@ class CreateShareNetwork(command.ShowOne):
kwargs = {
"name": parsed_args.name,
"description": parsed_args.description,
"neutron_net_id": parsed_args.neutron_net_id,
"neutron_subnet_id": parsed_args.neutron_subnet_id,
"neutron_net_id": neutron_net_id,
"neutron_subnet_id": neutron_subnet_id,
}
if availability_zone:
kwargs['availability_zone'] = availability_zone

View File

@@ -93,6 +93,109 @@ class TestShareNetworkSubnetCreate(TestShareNetworkSubnet):
self.assertCountEqual(self.columns, columns)
self.assertCountEqual(self.data, data)
def test_share_network_subnet_create_valid_neutron_info(self):
fake_neutron_net_id = str(uuid.uuid4())
fake_neutron_subnet_id = str(uuid.uuid4())
neutron_client = mock.Mock()
self.app.client_manager.network = neutron_client
neutron_client.find_network.return_value = mock.Mock(
id=fake_neutron_net_id)
neutron_client.find_subnet.return_value = mock.Mock(
id=fake_neutron_subnet_id)
arglist = [
self.share_network.id,
'--neutron-net-id', fake_neutron_net_id,
'--neutron-subnet-id', fake_neutron_subnet_id,
]
verifylist = [
('share_network', self.share_network.id),
('neutron_net_id', fake_neutron_net_id),
('neutron_subnet_id', fake_neutron_subnet_id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
neutron_client.find_network.assert_called_once_with(
fake_neutron_net_id,
ignore_missing=False
)
neutron_client.find_subnet.assert_called_once_with(
fake_neutron_subnet_id,
ignore_missing=False
)
self.share_subnets_mock.create.assert_called_once_with(
share_network_id=self.share_network.id,
neutron_net_id=fake_neutron_net_id,
neutron_subnet_id=fake_neutron_subnet_id,
availability_zone=None,
metadata={},
)
self.assertCountEqual(self.columns, columns)
self.assertCountEqual(self.data, data)
def test_share_network_subnet_create_invalid_neutron_network(self):
fake_neutron_net_id = str(uuid.uuid4())
fake_neutron_net_id = str(uuid.uuid4())
neutron_client = mock.Mock()
self.app.client_manager.network = neutron_client
neutron_client.find_network.side_effect = Exception(
"Network not found.")
arglist = [
self.share_network.id,
'--neutron-net-id', fake_neutron_net_id,
'--neutron-subnet-id', fake_neutron_net_id,
]
verifylist = [
('share_network', self.share_network.id),
('neutron_net_id', fake_neutron_net_id),
('neutron_subnet_id', fake_neutron_net_id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises(exceptions.CommandError,
self.cmd.take_action,
parsed_args)
neutron_client.find_network.assert_called_once_with(
fake_neutron_net_id,
ignore_missing=False
)
neutron_client.find_subnet.assert_not_called()
self.share_subnets_mock.create.assert_not_called()
def test_share_network_subnet_create_invalid_neutron_subnet(self):
fake_neutron_net_id = str(uuid.uuid4())
fake_neutron_subnet_id = str(uuid.uuid4())
neutron_client = mock.Mock()
self.app.client_manager.network = neutron_client
neutron_client.find_subnet.side_effect = Exception(
"Subnet not found.")
arglist = [
self.share_network.id,
'--neutron-net-id', fake_neutron_net_id,
'--neutron-subnet-id', fake_neutron_subnet_id,
]
verifylist = [
('share_network', self.share_network.id),
('neutron_net_id', fake_neutron_net_id),
('neutron_subnet_id', fake_neutron_subnet_id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises(exceptions.CommandError,
self.cmd.take_action,
parsed_args)
neutron_client.find_network.assert_called_once_with(
fake_neutron_net_id,
ignore_missing=False
)
neutron_client.find_subnet.assert_called_once_with(
fake_neutron_subnet_id,
ignore_missing=False
)
self.share_subnets_mock.create.assert_not_called()
def test_share_network_subnet_create_arg_group_exception(self):
fake_neutron_net_id = str(uuid.uuid4())

View File

@@ -122,6 +122,96 @@ class TestShareNetworkCreate(TestShareNetwork):
self.assertCountEqual(self.columns, columns)
self.assertCountEqual(self.data, data)
def test_share_network_create_with_valid_neutron_info(self):
fake_neutron_net_id = str(uuid.uuid4())
fake_neutron_subnet_id = str(uuid.uuid4())
neutron_client = mock.Mock()
self.app.client_manager.network = neutron_client
neutron_client.find_network.return_value = mock.Mock(
id=fake_neutron_net_id)
neutron_client.find_subnet.return_value = mock.Mock(
id=fake_neutron_subnet_id)
arglist = [
'--neutron-net-id', fake_neutron_net_id,
'--neutron-subnet-id', fake_neutron_subnet_id,
]
verifylist = [
('neutron_net_id', fake_neutron_net_id),
('neutron_subnet_id', fake_neutron_subnet_id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
neutron_client.find_network.assert_called_once_with(
fake_neutron_net_id, ignore_missing=False)
neutron_client.find_subnet.assert_called_once_with(
fake_neutron_subnet_id, ignore_missing=False)
self.share_networks_mock.create.assert_called_once_with(
name=None,
description=None,
neutron_net_id=fake_neutron_net_id,
neutron_subnet_id=fake_neutron_subnet_id
)
self.assertCountEqual(self.columns, columns)
self.assertCountEqual(self.data, data)
def test_share_network_create_with_invalid_neutron_network(self):
fake_neutron_net_id = str(uuid.uuid4())
neutron_client = mock.Mock()
self.app.client_manager.network = neutron_client
neutron_client.find_network.side_effect = Exception(
"Network not found")
arglist = [
'--neutron-net-id', fake_neutron_net_id
]
verifylist = [
('neutron_net_id', fake_neutron_net_id)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises(
exceptions.CommandError,
self.cmd.take_action,
parsed_args
)
neutron_client.find_network.assert_called_once_with(
fake_neutron_net_id, ignore_missing=False)
self.share_networks_mock.create.assert_not_called()
def test_share_network_create_with_invalid_neutron_subnet(self):
fake_neutron_subnet_id = str(uuid.uuid4())
neutron_client = mock.Mock()
self.app.client_manager.network = neutron_client
neutron_client.find_subnet.side_effect = Exception(
"Subnet not found")
arglist = [
'--neutron-subnet-id', fake_neutron_subnet_id
]
verifylist = [
('neutron_subnet_id', fake_neutron_subnet_id)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises(
exceptions.CommandError,
self.cmd.take_action,
parsed_args
)
neutron_client.find_subnet.assert_called_once_with(
fake_neutron_subnet_id, ignore_missing=False)
self.share_networks_mock.create.assert_not_called()
@ddt.ddt
class TestShareNetworkDelete(TestShareNetwork):

View File

@@ -0,0 +1,12 @@
fixes:
- |
The "openstack share network create" and
"openstack share network subnet create" commands
now validate Neutron network information provided
before sending the request.
Previously, validation only occured in the Manila service
which could result in client-side errors when invalid network
or subnet IDs were supplied. The client now performs
proper validation and handles missing or invalid
network data gracefully.