Skip to content

Commit 841d9d8

Browse files
Reedipreedip
authored andcommitted
Add support for setting router gateway
This patch adds the support to set the gateway information for a router. Implements: blueprint neutron-client-advanced-router Partially-Implements: blueprint network-commands-options Change-Id: Ifb5a4d1965cd7e75c0c8cf2cfb677e0628b699dc Depends-On: I2bda0dd40afd64b6cecca5f64ef2326bda4fac92
1 parent d6e058f commit 841d9d8

4 files changed

Lines changed: 189 additions & 7 deletions

File tree

doc/source/command-objects/router.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ Set router properties
213213
[--description <description>]
214214
[--route destination=<subnet>,gateway=<ip-address> | --no-route]
215215
[--ha | --no-ha]
216+
[--external-gateway <network> [--enable-snat|--disable-snat] [--fixed-ip subnet=<subnet>,ip-address=<ip-address>]]
216217
<router>
217218
218219
.. option:: --name <name>
@@ -258,6 +259,24 @@ Set router properties
258259
259260
Clear high availablability attribute of the router (disabled router only)
260261
262+
.. option:: --external-gateway <network>
263+
264+
External Network used as router's gateway (name or ID)
265+
266+
.. option:: --enable-snat
267+
268+
Enable Source NAT on external gateway
269+
270+
.. option:: --disable-snat
271+
272+
Disable Source NAT on external gateway
273+
274+
.. option:: --fixed-ip subnet=<subnet>,ip-address=<ip-address>
275+
276+
Desired IP and/or subnet (name or ID) on external gateway:
277+
subnet=<subnet>,ip-address=<ip-address>
278+
(repeat option to set multiple fixed IP addresses)
279+
261280
.. _router_set-router:
262281
.. describe:: <router>
263282

openstackclient/network/v2/router.py

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -473,9 +473,32 @@ def get_parser(self, prog_name):
473473
help=_("Clear high availablability attribute of the router "
474474
"(disabled router only)")
475475
)
476-
# TODO(tangchen): Support setting 'external_gateway_info' property in
477-
# 'router set' command.
478-
476+
parser.add_argument(
477+
'--external-gateway',
478+
metavar="<network>",
479+
help=_("External Network used as router's gateway (name or ID)")
480+
)
481+
parser.add_argument(
482+
'--fixed-ip',
483+
metavar='subnet=<subnet>,ip-address=<ip-address>',
484+
action=parseractions.MultiKeyValueAction,
485+
optional_keys=['subnet', 'ip-address'],
486+
help=_("Desired IP and/or subnet (name or ID)"
487+
"on external gateway: "
488+
"subnet=<subnet>,ip-address=<ip-address> "
489+
"(repeat option to set multiple fixed IP addresses)")
490+
)
491+
snat_group = parser.add_mutually_exclusive_group()
492+
snat_group.add_argument(
493+
'--enable-snat',
494+
action='store_true',
495+
help=_("Enable Source NAT on external gateway")
496+
)
497+
snat_group.add_argument(
498+
'--disable-snat',
499+
action='store_true',
500+
help=_("Disable Source NAT on external gateway")
501+
)
479502
return parser
480503

481504
def take_action(self, parsed_args):
@@ -504,7 +527,34 @@ def take_action(self, parsed_args):
504527
for route in parsed_args.routes:
505528
route['nexthop'] = route.pop('gateway')
506529
attrs['routes'] = obj.routes + parsed_args.routes
507-
530+
if (parsed_args.disable_snat or parsed_args.enable_snat or
531+
parsed_args.fixed_ip) and not parsed_args.external_gateway:
532+
msg = (_("You must specify '--external-gateway' in order"
533+
"to update the SNAT or fixed-ip values"))
534+
raise exceptions.CommandError(msg)
535+
if parsed_args.external_gateway:
536+
gateway_info = {}
537+
network = client.find_network(
538+
parsed_args.external_gateway, ignore_missing=False)
539+
gateway_info['network_id'] = network.id
540+
if parsed_args.disable_snat:
541+
gateway_info['enable_snat'] = False
542+
if parsed_args.enable_snat:
543+
gateway_info['enable_snat'] = True
544+
if parsed_args.fixed_ip:
545+
ips = []
546+
for ip_spec in parsed_args.fixed_ip:
547+
if ip_spec.get('subnet', False):
548+
subnet_name_id = ip_spec.pop('subnet')
549+
if subnet_name_id:
550+
subnet = client.find_subnet(subnet_name_id,
551+
ignore_missing=False)
552+
ip_spec['subnet_id'] = subnet.id
553+
if ip_spec.get('ip-address', False):
554+
ip_spec['ip_address'] = ip_spec.pop('ip-address')
555+
ips.append(ip_spec)
556+
gateway_info['external_fixed_ips'] = ips
557+
attrs['external_gateway_info'] = gateway_info
508558
client.update_router(obj, **attrs)
509559

510560

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

Lines changed: 109 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -561,17 +561,19 @@ class TestSetRouter(TestRouter):
561561

562562
# The router to set.
563563
_default_route = {'destination': '10.20.20.0/24', 'nexthop': '10.20.30.1'}
564+
_network = network_fakes.FakeNetwork.create_one_network()
565+
_subnet = network_fakes.FakeSubnet.create_one_subnet()
564566
_router = network_fakes.FakeRouter.create_one_router(
565567
attrs={'routes': [_default_route]}
566568
)
567569

568570
def setUp(self):
569571
super(TestSetRouter, self).setUp()
570-
572+
self.network.router_add_gateway = mock.Mock()
571573
self.network.update_router = mock.Mock(return_value=None)
572-
573574
self.network.find_router = mock.Mock(return_value=self._router)
574-
575+
self.network.find_network = mock.Mock(return_value=self._network)
576+
self.network.find_subnet = mock.Mock(return_value=self._subnet)
575577
# Get the command object to test
576578
self.cmd = router.SetRouter(self.app, self.namespace)
577579

@@ -758,6 +760,110 @@ def test_set_nothing(self):
758760
self._router, **attrs)
759761
self.assertIsNone(result)
760762

763+
def test_wrong_gateway_params(self):
764+
arglist = [
765+
"--fixed-ip", "subnet='abc'",
766+
self._router.id,
767+
]
768+
verifylist = [
769+
('fixed_ip', [{'subnet': "'abc'"}]),
770+
('router', self._router.id),
771+
]
772+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
773+
self.assertRaises(exceptions.CommandError,
774+
self.cmd.take_action, parsed_args)
775+
776+
def test_set_gateway_network_only(self):
777+
arglist = [
778+
"--external-gateway", self._network.id,
779+
self._router.id,
780+
]
781+
verifylist = [
782+
('external_gateway', self._network.id),
783+
('router', self._router.id),
784+
]
785+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
786+
787+
result = self.cmd.take_action(parsed_args)
788+
self.network.update_router.assert_called_with(
789+
self._router, **{'external_gateway_info': {
790+
'network_id': self._network.id}})
791+
self.assertIsNone(result)
792+
793+
def test_set_gateway_options_subnet_only(self):
794+
arglist = [
795+
"--external-gateway", self._network.id,
796+
"--fixed-ip", "subnet='abc'",
797+
self._router.id,
798+
'--enable-snat',
799+
]
800+
verifylist = [
801+
('router', self._router.id),
802+
('external_gateway', self._network.id),
803+
('fixed_ip', [{'subnet': "'abc'"}]),
804+
('enable_snat', True),
805+
]
806+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
807+
808+
result = self.cmd.take_action(parsed_args)
809+
self.network.update_router.assert_called_with(
810+
self._router, **{'external_gateway_info': {
811+
'network_id': self._network.id,
812+
'external_fixed_ips': [{
813+
'subnet_id': self._subnet.id, }],
814+
'enable_snat': True, }})
815+
self.assertIsNone(result)
816+
817+
def test_set_gateway_option_ipaddress_only(self):
818+
arglist = [
819+
"--external-gateway", self._network.id,
820+
"--fixed-ip", "ip-address=10.0.1.1",
821+
self._router.id,
822+
'--enable-snat',
823+
]
824+
verifylist = [
825+
('router', self._router.id),
826+
('external_gateway', self._network.id),
827+
('fixed_ip', [{'ip-address': "10.0.1.1"}]),
828+
('enable_snat', True),
829+
]
830+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
831+
832+
result = self.cmd.take_action(parsed_args)
833+
self.network.update_router.assert_called_with(
834+
self._router, **{'external_gateway_info': {
835+
'network_id': self._network.id,
836+
'external_fixed_ips': [{
837+
'ip_address': "10.0.1.1", }],
838+
'enable_snat': True, }})
839+
self.assertIsNone(result)
840+
841+
def test_set_gateway_options_subnet_ipaddress(self):
842+
arglist = [
843+
"--external-gateway", self._network.id,
844+
"--fixed-ip", "subnet='abc',ip-address=10.0.1.1",
845+
self._router.id,
846+
'--enable-snat',
847+
]
848+
verifylist = [
849+
('router', self._router.id),
850+
('external_gateway', self._network.id),
851+
('fixed_ip', [{'subnet': "'abc'",
852+
'ip-address': "10.0.1.1"}]),
853+
('enable_snat', True),
854+
]
855+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
856+
857+
result = self.cmd.take_action(parsed_args)
858+
self.network.update_router.assert_called_with(
859+
self._router, **{'external_gateway_info': {
860+
'network_id': self._network.id,
861+
'external_fixed_ips': [{
862+
'subnet_id': self._subnet.id,
863+
'ip_address': "10.0.1.1", }],
864+
'enable_snat': True, }})
865+
self.assertIsNone(result)
866+
761867

762868
class TestShowRouter(TestRouter):
763869

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
features:
3+
- |
4+
Add support for setting the gateway information in a router,
5+
by introducing the new option ``--external-gateway`` in
6+
``router set`` CLI.
7+
[ Blueprint `neutron-client-advanced-router <https://blueprints.launchpad.net/python-openstackclient/+spec/neutron-client-advanced-router>`_]

0 commit comments

Comments
 (0)