Skip to content

Commit 4e9b929

Browse files
osfricklergtema
authored andcommitted
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
1 parent 32e1825 commit 4e9b929

3 files changed

Lines changed: 101 additions & 23 deletions

File tree

openstackclient/network/v2/router.py

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,30 @@ def _get_attrs(client_manager, parsed_args):
111111
parsed_args.project_domain,
112112
).id
113113
attrs['tenant_id'] = project_id
114+
if parsed_args.external_gateway:
115+
gateway_info = {}
116+
n_client = client_manager.network
117+
network = n_client.find_network(
118+
parsed_args.external_gateway, ignore_missing=False)
119+
gateway_info['network_id'] = network.id
120+
if parsed_args.disable_snat:
121+
gateway_info['enable_snat'] = False
122+
if parsed_args.enable_snat:
123+
gateway_info['enable_snat'] = True
124+
if parsed_args.fixed_ip:
125+
ips = []
126+
for ip_spec in parsed_args.fixed_ip:
127+
if ip_spec.get('subnet', False):
128+
subnet_name_id = ip_spec.pop('subnet')
129+
if subnet_name_id:
130+
subnet = n_client.find_subnet(subnet_name_id,
131+
ignore_missing=False)
132+
ip_spec['subnet_id'] = subnet.id
133+
if ip_spec.get('ip-address', False):
134+
ip_spec['ip_address'] = ip_spec.pop('ip-address')
135+
ips.append(ip_spec)
136+
gateway_info['external_fixed_ips'] = ips
137+
attrs['external_gateway_info'] = gateway_info
114138

115139
return attrs
116140

@@ -320,6 +344,32 @@ def get_parser(self, prog_name):
320344
"repeat option to set multiple availability zones)")
321345
)
322346
_tag.add_tag_option_to_parser_for_create(parser, _('router'))
347+
parser.add_argument(
348+
'--external-gateway',
349+
metavar="<network>",
350+
help=_("External Network used as router's gateway (name or ID)")
351+
)
352+
parser.add_argument(
353+
'--fixed-ip',
354+
metavar='subnet=<subnet>,ip-address=<ip-address>',
355+
action=parseractions.MultiKeyValueAction,
356+
optional_keys=['subnet', 'ip-address'],
357+
help=_("Desired IP and/or subnet (name or ID) "
358+
"on external gateway: "
359+
"subnet=<subnet>,ip-address=<ip-address> "
360+
"(repeat option to set multiple fixed IP addresses)")
361+
)
362+
snat_group = parser.add_mutually_exclusive_group()
363+
snat_group.add_argument(
364+
'--enable-snat',
365+
action='store_true',
366+
help=_("Enable Source NAT on external gateway")
367+
)
368+
snat_group.add_argument(
369+
'--disable-snat',
370+
action='store_true',
371+
help=_("Disable Source NAT on external gateway")
372+
)
323373

324374
return parser
325375

@@ -338,6 +388,12 @@ def take_action(self, parsed_args):
338388
# tags cannot be set when created, so tags need to be set later.
339389
_tag.update_tags_for_set(client, obj, parsed_args)
340390

391+
if (parsed_args.disable_snat or parsed_args.enable_snat or
392+
parsed_args.fixed_ip) and not parsed_args.external_gateway:
393+
msg = (_("You must specify '--external-gateway' in order "
394+
"to specify SNAT or fixed-ip values"))
395+
raise exceptions.CommandError(msg)
396+
341397
display_columns, columns = _get_columns(obj)
342398
data = utils.get_item_properties(obj, columns, formatters=_formatters)
343399

@@ -725,29 +781,6 @@ def take_action(self, parsed_args):
725781
msg = (_("You must specify '--external-gateway' in order "
726782
"to update the SNAT or fixed-ip values"))
727783
raise exceptions.CommandError(msg)
728-
if parsed_args.external_gateway:
729-
gateway_info = {}
730-
network = client.find_network(
731-
parsed_args.external_gateway, ignore_missing=False)
732-
gateway_info['network_id'] = network.id
733-
if parsed_args.disable_snat:
734-
gateway_info['enable_snat'] = False
735-
if parsed_args.enable_snat:
736-
gateway_info['enable_snat'] = True
737-
if parsed_args.fixed_ip:
738-
ips = []
739-
for ip_spec in parsed_args.fixed_ip:
740-
if ip_spec.get('subnet', False):
741-
subnet_name_id = ip_spec.pop('subnet')
742-
if subnet_name_id:
743-
subnet = client.find_subnet(subnet_name_id,
744-
ignore_missing=False)
745-
ip_spec['subnet_id'] = subnet.id
746-
if ip_spec.get('ip-address', False):
747-
ip_spec['ip_address'] = ip_spec.pop('ip-address')
748-
ips.append(ip_spec)
749-
gateway_info['external_fixed_ips'] = ips
750-
attrs['external_gateway_info'] = gateway_info
751784

752785
if ((parsed_args.qos_policy or parsed_args.no_qos_policy) and
753786
not parsed_args.external_gateway):

openstackclient/tests/unit/network/v2/test_router.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,43 @@ def test_create_default_options(self):
186186
self.assertEqual(self.columns, columns)
187187
self.assertCountEqual(self.data, data)
188188

189+
def test_create_with_gateway(self):
190+
_network = network_fakes.FakeNetwork.create_one_network()
191+
_subnet = network_fakes.FakeSubnet.create_one_subnet()
192+
self.network.find_network = mock.Mock(return_value=_network)
193+
self.network.find_subnet = mock.Mock(return_value=_subnet)
194+
arglist = [
195+
self.new_router.name,
196+
'--external-gateway', _network.name,
197+
'--enable-snat',
198+
'--fixed-ip', 'ip-address=2001:db8::1'
199+
]
200+
verifylist = [
201+
('name', self.new_router.name),
202+
('enable', True),
203+
('distributed', False),
204+
('ha', False),
205+
('external_gateway', _network.name),
206+
('enable_snat', True),
207+
('fixed_ip', [{'ip-address': '2001:db8::1'}]),
208+
]
209+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
210+
211+
columns, data = (self.cmd.take_action(parsed_args))
212+
213+
self.network.create_router.assert_called_once_with(**{
214+
'admin_state_up': True,
215+
'name': self.new_router.name,
216+
'external_gateway_info': {
217+
'network_id': _network.id,
218+
'enable_snat': True,
219+
'external_fixed_ips': [{'ip_address': '2001:db8::1'}],
220+
},
221+
})
222+
self.assertFalse(self.network.set_tags.called)
223+
self.assertEqual(self.columns, columns)
224+
self.assertCountEqual(self.data, data)
225+
189226
def _test_create_with_ha_options(self, option, ha):
190227
arglist = [
191228
option,
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
features:
3+
- |
4+
It is now possible to add an external gateway to a router
5+
immediately on creation. Previously it could only be done by
6+
modifying the router after it had been created. This includes
7+
the options to en- or disable SNAT and to specify a fixed-ip
8+
on the external network.

0 commit comments

Comments
 (0)