Allow setting gateway when creating a router

These options are not only valid when modifying a router, but also when
one is created initially.

Signed-off-by: Dr. Jens Harbott <harbott@osism.tech>
Change-Id: I3e12901f37cbd1639ac9dc9cc49b04114b80474c
This commit is contained in:
Dr. Jens Harbott 2021-11-30 09:21:56 +01:00 committed by Artem Goncharov
parent 32e18253fa
commit 4e9b929842
3 changed files with 101 additions and 23 deletions

View File

@ -111,6 +111,30 @@ def _get_attrs(client_manager, parsed_args):
parsed_args.project_domain,
).id
attrs['tenant_id'] = project_id
if parsed_args.external_gateway:
gateway_info = {}
n_client = client_manager.network
network = n_client.find_network(
parsed_args.external_gateway, ignore_missing=False)
gateway_info['network_id'] = network.id
if parsed_args.disable_snat:
gateway_info['enable_snat'] = False
if parsed_args.enable_snat:
gateway_info['enable_snat'] = True
if parsed_args.fixed_ip:
ips = []
for ip_spec in parsed_args.fixed_ip:
if ip_spec.get('subnet', False):
subnet_name_id = ip_spec.pop('subnet')
if subnet_name_id:
subnet = n_client.find_subnet(subnet_name_id,
ignore_missing=False)
ip_spec['subnet_id'] = subnet.id
if ip_spec.get('ip-address', False):
ip_spec['ip_address'] = ip_spec.pop('ip-address')
ips.append(ip_spec)
gateway_info['external_fixed_ips'] = ips
attrs['external_gateway_info'] = gateway_info
return attrs
@ -320,6 +344,32 @@ class CreateRouter(command.ShowOne, common.NeutronCommandWithExtraArgs):
"repeat option to set multiple availability zones)")
)
_tag.add_tag_option_to_parser_for_create(parser, _('router'))
parser.add_argument(
'--external-gateway',
metavar="<network>",
help=_("External Network used as router's gateway (name or ID)")
)
parser.add_argument(
'--fixed-ip',
metavar='subnet=<subnet>,ip-address=<ip-address>',
action=parseractions.MultiKeyValueAction,
optional_keys=['subnet', 'ip-address'],
help=_("Desired IP and/or subnet (name or ID) "
"on external gateway: "
"subnet=<subnet>,ip-address=<ip-address> "
"(repeat option to set multiple fixed IP addresses)")
)
snat_group = parser.add_mutually_exclusive_group()
snat_group.add_argument(
'--enable-snat',
action='store_true',
help=_("Enable Source NAT on external gateway")
)
snat_group.add_argument(
'--disable-snat',
action='store_true',
help=_("Disable Source NAT on external gateway")
)
return parser
@ -338,6 +388,12 @@ class CreateRouter(command.ShowOne, common.NeutronCommandWithExtraArgs):
# tags cannot be set when created, so tags need to be set later.
_tag.update_tags_for_set(client, obj, parsed_args)
if (parsed_args.disable_snat or parsed_args.enable_snat or
parsed_args.fixed_ip) and not parsed_args.external_gateway:
msg = (_("You must specify '--external-gateway' in order "
"to specify SNAT or fixed-ip values"))
raise exceptions.CommandError(msg)
display_columns, columns = _get_columns(obj)
data = utils.get_item_properties(obj, columns, formatters=_formatters)
@ -725,29 +781,6 @@ class SetRouter(common.NeutronCommandWithExtraArgs):
msg = (_("You must specify '--external-gateway' in order "
"to update the SNAT or fixed-ip values"))
raise exceptions.CommandError(msg)
if parsed_args.external_gateway:
gateway_info = {}
network = client.find_network(
parsed_args.external_gateway, ignore_missing=False)
gateway_info['network_id'] = network.id
if parsed_args.disable_snat:
gateway_info['enable_snat'] = False
if parsed_args.enable_snat:
gateway_info['enable_snat'] = True
if parsed_args.fixed_ip:
ips = []
for ip_spec in parsed_args.fixed_ip:
if ip_spec.get('subnet', False):
subnet_name_id = ip_spec.pop('subnet')
if subnet_name_id:
subnet = client.find_subnet(subnet_name_id,
ignore_missing=False)
ip_spec['subnet_id'] = subnet.id
if ip_spec.get('ip-address', False):
ip_spec['ip_address'] = ip_spec.pop('ip-address')
ips.append(ip_spec)
gateway_info['external_fixed_ips'] = ips
attrs['external_gateway_info'] = gateway_info
if ((parsed_args.qos_policy or parsed_args.no_qos_policy) and
not parsed_args.external_gateway):

View File

@ -186,6 +186,43 @@ class TestCreateRouter(TestRouter):
self.assertEqual(self.columns, columns)
self.assertCountEqual(self.data, data)
def test_create_with_gateway(self):
_network = network_fakes.FakeNetwork.create_one_network()
_subnet = network_fakes.FakeSubnet.create_one_subnet()
self.network.find_network = mock.Mock(return_value=_network)
self.network.find_subnet = mock.Mock(return_value=_subnet)
arglist = [
self.new_router.name,
'--external-gateway', _network.name,
'--enable-snat',
'--fixed-ip', 'ip-address=2001:db8::1'
]
verifylist = [
('name', self.new_router.name),
('enable', True),
('distributed', False),
('ha', False),
('external_gateway', _network.name),
('enable_snat', True),
('fixed_ip', [{'ip-address': '2001:db8::1'}]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = (self.cmd.take_action(parsed_args))
self.network.create_router.assert_called_once_with(**{
'admin_state_up': True,
'name': self.new_router.name,
'external_gateway_info': {
'network_id': _network.id,
'enable_snat': True,
'external_fixed_ips': [{'ip_address': '2001:db8::1'}],
},
})
self.assertFalse(self.network.set_tags.called)
self.assertEqual(self.columns, columns)
self.assertCountEqual(self.data, data)
def _test_create_with_ha_options(self, option, ha):
arglist = [
option,

View File

@ -0,0 +1,8 @@
---
features:
- |
It is now possible to add an external gateway to a router
immediately on creation. Previously it could only be done by
modifying the router after it had been created. This includes
the options to en- or disable SNAT and to specify a fixed-ip
on the external network.