Skip to content

Commit e51a2b3

Browse files
Jenkinsopenstack-gerrit
authored andcommitted
Merge "Add support for setting router gateway"
2 parents 25c563d + 841d9d8 commit e51a2b3

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
@@ -223,6 +223,7 @@ Set router properties
223223
[--description <description>]
224224
[--route destination=<subnet>,gateway=<ip-address> | --no-route]
225225
[--ha | --no-ha]
226+
[--external-gateway <network> [--enable-snat|--disable-snat] [--fixed-ip subnet=<subnet>,ip-address=<ip-address>]]
226227
<router>
227228
228229
.. option:: --name <name>
@@ -268,6 +269,24 @@ Set router properties
268269
269270
Clear high availablability attribute of the router (disabled router only)
270271
272+
.. option:: --external-gateway <network>
273+
274+
External Network used as router's gateway (name or ID)
275+
276+
.. option:: --enable-snat
277+
278+
Enable Source NAT on external gateway
279+
280+
.. option:: --disable-snat
281+
282+
Disable Source NAT on external gateway
283+
284+
.. option:: --fixed-ip subnet=<subnet>,ip-address=<ip-address>
285+
286+
Desired IP and/or subnet (name or ID) on external gateway:
287+
subnet=<subnet>,ip-address=<ip-address>
288+
(repeat option to set multiple fixed IP addresses)
289+
271290
.. _router_set-router:
272291
.. describe:: <router>
273292

openstackclient/network/v2/router.py

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -499,9 +499,32 @@ def get_parser(self, prog_name):
499499
help=_("Clear high availablability attribute of the router "
500500
"(disabled router only)")
501501
)
502-
# TODO(tangchen): Support setting 'external_gateway_info' property in
503-
# 'router set' command.
504-
502+
parser.add_argument(
503+
'--external-gateway',
504+
metavar="<network>",
505+
help=_("External Network used as router's gateway (name or ID)")
506+
)
507+
parser.add_argument(
508+
'--fixed-ip',
509+
metavar='subnet=<subnet>,ip-address=<ip-address>',
510+
action=parseractions.MultiKeyValueAction,
511+
optional_keys=['subnet', 'ip-address'],
512+
help=_("Desired IP and/or subnet (name or ID)"
513+
"on external gateway: "
514+
"subnet=<subnet>,ip-address=<ip-address> "
515+
"(repeat option to set multiple fixed IP addresses)")
516+
)
517+
snat_group = parser.add_mutually_exclusive_group()
518+
snat_group.add_argument(
519+
'--enable-snat',
520+
action='store_true',
521+
help=_("Enable Source NAT on external gateway")
522+
)
523+
snat_group.add_argument(
524+
'--disable-snat',
525+
action='store_true',
526+
help=_("Disable Source NAT on external gateway")
527+
)
505528
return parser
506529

507530
def take_action(self, parsed_args):
@@ -530,7 +553,34 @@ def take_action(self, parsed_args):
530553
for route in parsed_args.routes:
531554
route['nexthop'] = route.pop('gateway')
532555
attrs['routes'] = obj.routes + parsed_args.routes
533-
556+
if (parsed_args.disable_snat or parsed_args.enable_snat or
557+
parsed_args.fixed_ip) and not parsed_args.external_gateway:
558+
msg = (_("You must specify '--external-gateway' in order"
559+
"to update the SNAT or fixed-ip values"))
560+
raise exceptions.CommandError(msg)
561+
if parsed_args.external_gateway:
562+
gateway_info = {}
563+
network = client.find_network(
564+
parsed_args.external_gateway, ignore_missing=False)
565+
gateway_info['network_id'] = network.id
566+
if parsed_args.disable_snat:
567+
gateway_info['enable_snat'] = False
568+
if parsed_args.enable_snat:
569+
gateway_info['enable_snat'] = True
570+
if parsed_args.fixed_ip:
571+
ips = []
572+
for ip_spec in parsed_args.fixed_ip:
573+
if ip_spec.get('subnet', False):
574+
subnet_name_id = ip_spec.pop('subnet')
575+
if subnet_name_id:
576+
subnet = client.find_subnet(subnet_name_id,
577+
ignore_missing=False)
578+
ip_spec['subnet_id'] = subnet.id
579+
if ip_spec.get('ip-address', False):
580+
ip_spec['ip_address'] = ip_spec.pop('ip-address')
581+
ips.append(ip_spec)
582+
gateway_info['external_fixed_ips'] = ips
583+
attrs['external_gateway_info'] = gateway_info
534584
client.update_router(obj, **attrs)
535585

536586

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

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

603603
# The router to set.
604604
_default_route = {'destination': '10.20.20.0/24', 'nexthop': '10.20.30.1'}
605+
_network = network_fakes.FakeNetwork.create_one_network()
606+
_subnet = network_fakes.FakeSubnet.create_one_subnet()
605607
_router = network_fakes.FakeRouter.create_one_router(
606608
attrs={'routes': [_default_route]}
607609
)
608610

609611
def setUp(self):
610612
super(TestSetRouter, self).setUp()
611-
613+
self.network.router_add_gateway = mock.Mock()
612614
self.network.update_router = mock.Mock(return_value=None)
613-
614615
self.network.find_router = mock.Mock(return_value=self._router)
615-
616+
self.network.find_network = mock.Mock(return_value=self._network)
617+
self.network.find_subnet = mock.Mock(return_value=self._subnet)
616618
# Get the command object to test
617619
self.cmd = router.SetRouter(self.app, self.namespace)
618620

@@ -799,6 +801,110 @@ def test_set_nothing(self):
799801
self._router, **attrs)
800802
self.assertIsNone(result)
801803

804+
def test_wrong_gateway_params(self):
805+
arglist = [
806+
"--fixed-ip", "subnet='abc'",
807+
self._router.id,
808+
]
809+
verifylist = [
810+
('fixed_ip', [{'subnet': "'abc'"}]),
811+
('router', self._router.id),
812+
]
813+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
814+
self.assertRaises(exceptions.CommandError,
815+
self.cmd.take_action, parsed_args)
816+
817+
def test_set_gateway_network_only(self):
818+
arglist = [
819+
"--external-gateway", self._network.id,
820+
self._router.id,
821+
]
822+
verifylist = [
823+
('external_gateway', self._network.id),
824+
('router', self._router.id),
825+
]
826+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
827+
828+
result = self.cmd.take_action(parsed_args)
829+
self.network.update_router.assert_called_with(
830+
self._router, **{'external_gateway_info': {
831+
'network_id': self._network.id}})
832+
self.assertIsNone(result)
833+
834+
def test_set_gateway_options_subnet_only(self):
835+
arglist = [
836+
"--external-gateway", self._network.id,
837+
"--fixed-ip", "subnet='abc'",
838+
self._router.id,
839+
'--enable-snat',
840+
]
841+
verifylist = [
842+
('router', self._router.id),
843+
('external_gateway', self._network.id),
844+
('fixed_ip', [{'subnet': "'abc'"}]),
845+
('enable_snat', True),
846+
]
847+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
848+
849+
result = self.cmd.take_action(parsed_args)
850+
self.network.update_router.assert_called_with(
851+
self._router, **{'external_gateway_info': {
852+
'network_id': self._network.id,
853+
'external_fixed_ips': [{
854+
'subnet_id': self._subnet.id, }],
855+
'enable_snat': True, }})
856+
self.assertIsNone(result)
857+
858+
def test_set_gateway_option_ipaddress_only(self):
859+
arglist = [
860+
"--external-gateway", self._network.id,
861+
"--fixed-ip", "ip-address=10.0.1.1",
862+
self._router.id,
863+
'--enable-snat',
864+
]
865+
verifylist = [
866+
('router', self._router.id),
867+
('external_gateway', self._network.id),
868+
('fixed_ip', [{'ip-address': "10.0.1.1"}]),
869+
('enable_snat', True),
870+
]
871+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
872+
873+
result = self.cmd.take_action(parsed_args)
874+
self.network.update_router.assert_called_with(
875+
self._router, **{'external_gateway_info': {
876+
'network_id': self._network.id,
877+
'external_fixed_ips': [{
878+
'ip_address': "10.0.1.1", }],
879+
'enable_snat': True, }})
880+
self.assertIsNone(result)
881+
882+
def test_set_gateway_options_subnet_ipaddress(self):
883+
arglist = [
884+
"--external-gateway", self._network.id,
885+
"--fixed-ip", "subnet='abc',ip-address=10.0.1.1",
886+
self._router.id,
887+
'--enable-snat',
888+
]
889+
verifylist = [
890+
('router', self._router.id),
891+
('external_gateway', self._network.id),
892+
('fixed_ip', [{'subnet': "'abc'",
893+
'ip-address': "10.0.1.1"}]),
894+
('enable_snat', True),
895+
]
896+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
897+
898+
result = self.cmd.take_action(parsed_args)
899+
self.network.update_router.assert_called_with(
900+
self._router, **{'external_gateway_info': {
901+
'network_id': self._network.id,
902+
'external_fixed_ips': [{
903+
'subnet_id': self._subnet.id,
904+
'ip_address': "10.0.1.1", }],
905+
'enable_snat': True, }})
906+
self.assertIsNone(result)
907+
802908

803909
class TestShowRouter(TestRouter):
804910

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)