diff --git a/openstackclient/network/v2/router.py b/openstackclient/network/v2/router.py index 746452e40..a3a4eb756 100644 --- a/openstackclient/network/v2/router.py +++ b/openstackclient/network/v2/router.py @@ -579,6 +579,17 @@ class SetRouter(command.Command): action='store_true', help=_("Disable Source NAT on external gateway") ) + qos_policy_group = parser.add_mutually_exclusive_group() + qos_policy_group.add_argument( + '--qos-policy', + metavar='', + help=_("Attach QoS policy to router gateway IPs") + ) + qos_policy_group.add_argument( + '--no-qos-policy', + action='store_true', + help=_("Remove QoS policy from router gateway IPs") + ) _tag.add_tag_option_to_parser_for_set(parser, _('router')) return parser @@ -638,6 +649,27 @@ class SetRouter(command.Command): 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): + try: + original_net_id = obj.external_gateway_info['network_id'] + except (KeyError, TypeError): + msg = (_("You must specify '--external-gateway' or the router " + "must already have an external network in order to " + "set router gateway IP QoS")) + raise exceptions.CommandError(msg) + else: + if not attrs.get('external_gateway_info'): + attrs['external_gateway_info'] = {} + attrs['external_gateway_info']['network_id'] = original_net_id + if parsed_args.qos_policy: + check_qos_id = client.find_qos_policy( + parsed_args.qos_policy, ignore_missing=False).id + attrs['external_gateway_info']['qos_policy_id'] = check_qos_id + + if 'no_qos_policy' in parsed_args and parsed_args.no_qos_policy: + attrs['external_gateway_info']['qos_policy_id'] = None if attrs: client.update_router(obj, **attrs) # tags is a subresource and it needs to be updated separately. @@ -701,6 +733,12 @@ class UnsetRouter(command.Command): action='store_true', default=False, help=_("Remove external gateway information from the router")) + parser.add_argument( + '--qos-policy', + action='store_true', + default=False, + help=_("Remove QoS policy from router gateway IPs") + ) parser.add_argument( 'router', metavar="", @@ -713,6 +751,7 @@ class UnsetRouter(command.Command): client = self.app.client_manager.network obj = client.find_router(parsed_args.router, ignore_missing=False) tmp_routes = copy.deepcopy(obj.routes) + tmp_external_gateway_info = copy.deepcopy(obj.external_gateway_info) attrs = {} if parsed_args.routes: try: @@ -723,6 +762,20 @@ class UnsetRouter(command.Command): msg = (_("Router does not contain route %s") % route) raise exceptions.CommandError(msg) attrs['routes'] = tmp_routes + if parsed_args.qos_policy: + try: + if (tmp_external_gateway_info['network_id'] and + tmp_external_gateway_info['qos_policy_id']): + pass + except (KeyError, TypeError): + msg = _("Router does not have external network or qos policy") + raise exceptions.CommandError(msg) + else: + attrs['external_gateway_info'] = { + 'network_id': tmp_external_gateway_info['network_id'], + 'qos_policy_id': None + } + if parsed_args.external_gateway: attrs['external_gateway_info'] = {} if attrs: diff --git a/openstackclient/tests/unit/network/v2/test_router.py b/openstackclient/tests/unit/network/v2/test_router.py index f383c1ddb..5102d0910 100644 --- a/openstackclient/tests/unit/network/v2/test_router.py +++ b/openstackclient/tests/unit/network/v2/test_router.py @@ -1113,6 +1113,102 @@ class TestSetRouter(TestRouter): def test_set_with_no_tag(self): self._test_set_tags(with_tags=False) + def test_set_gateway_ip_qos(self): + qos_policy = network_fakes.FakeNetworkQosPolicy.create_one_qos_policy() + self.network.find_qos_policy = mock.Mock(return_value=qos_policy) + arglist = [ + "--external-gateway", self._network.id, + "--qos-policy", qos_policy.id, + self._router.id, + ] + verifylist = [ + ('router', self._router.id), + ('external_gateway', self._network.id), + ('qos_policy', qos_policy.id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + self.network.update_router.assert_called_with( + self._router, **{'external_gateway_info': { + 'network_id': self._network.id, + 'qos_policy_id': qos_policy.id, }}) + self.assertIsNone(result) + + def test_unset_gateway_ip_qos(self): + arglist = [ + "--external-gateway", self._network.id, + "--no-qos-policy", + self._router.id, + ] + verifylist = [ + ('router', self._router.id), + ('external_gateway', self._network.id), + ('no_qos_policy', True), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + self.network.update_router.assert_called_with( + self._router, **{'external_gateway_info': { + 'network_id': self._network.id, + 'qos_policy_id': None, }}) + self.assertIsNone(result) + + def test_set_unset_gateway_ip_qos(self): + qos_policy = network_fakes.FakeNetworkQosPolicy.create_one_qos_policy() + self.network.find_qos_policy = mock.Mock(return_value=qos_policy) + arglist = [ + "--external-gateway", self._network.id, + "--qos-policy", qos_policy.id, + "--no-qos-policy", + self._router.id, + ] + verifylist = [ + ('router', self._router.id), + ('external_gateway', self._network.id), + ('qos_policy', qos_policy.id), + ('no_qos_policy', True), + ] + + self.assertRaises(tests_utils.ParserException, self.check_parser, + self.cmd, arglist, verifylist) + + def test_set_gateway_ip_qos_no_gateway(self): + qos_policy = network_fakes.FakeNetworkQosPolicy.create_one_qos_policy() + self.network.find_qos_policy = mock.Mock(return_value=qos_policy) + router = network_fakes.FakeRouter.create_one_router() + self.network.find_router = mock.Mock(return_value=router) + arglist = [ + "--qos-policy", qos_policy.id, + router.id, + ] + verifylist = [ + ('router', router.id), + ('qos_policy', qos_policy.id), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + self.assertRaises(exceptions.CommandError, + self.cmd.take_action, parsed_args) + + def test_unset_gateway_ip_qos_no_gateway(self): + qos_policy = network_fakes.FakeNetworkQosPolicy.create_one_qos_policy() + self.network.find_qos_policy = mock.Mock(return_value=qos_policy) + router = network_fakes.FakeRouter.create_one_router() + self.network.find_router = mock.Mock(return_value=router) + arglist = [ + "--no-qos-policy", + router.id, + ] + verifylist = [ + ('router', router.id), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + self.assertRaises(exceptions.CommandError, + self.cmd.take_action, parsed_args) + class TestShowRouter(TestRouter): @@ -1201,12 +1297,19 @@ class TestUnsetRouter(TestRouter): def setUp(self): super(TestUnsetRouter, self).setUp() + self.fake_network = network_fakes.FakeNetwork.create_one_network() + self.fake_qos_policy = ( + network_fakes.FakeNetworkQosPolicy.create_one_qos_policy()) self._testrouter = network_fakes.FakeRouter.create_one_router( {'routes': [{"destination": "192.168.101.1/24", "nexthop": "172.24.4.3"}, {"destination": "192.168.101.2/24", "nexthop": "172.24.4.3"}], - 'tags': ['green', 'red'], }) + 'tags': ['green', 'red'], + 'external_gateway_info': { + 'network_id': self.fake_network.id, + 'qos_policy_id': self.fake_qos_policy.id + }}) self.fake_subnet = network_fakes.FakeSubnet.create_one_subnet() self.network.find_router = mock.Mock(return_value=self._testrouter) self.network.update_router = mock.Mock(return_value=None) @@ -1289,3 +1392,54 @@ class TestUnsetRouter(TestRouter): def test_unset_with_all_tag(self): self._test_unset_tags(with_tags=False) + + def test_unset_router_qos_policy(self): + arglist = [ + '--qos-policy', + self._testrouter.name, + ] + verifylist = [ + ('qos_policy', True) + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + result = self.cmd.take_action(parsed_args) + attrs = {'external_gateway_info': {"network_id": self.fake_network.id, + "qos_policy_id": None}} + self.network.update_router.assert_called_once_with( + self._testrouter, **attrs) + self.assertIsNone(result) + + def test_unset_gateway_ip_qos_no_network(self): + qos_policy = network_fakes.FakeNetworkQosPolicy.create_one_qos_policy() + self.network.find_qos_policy = mock.Mock(return_value=qos_policy) + router = network_fakes.FakeRouter.create_one_router() + self.network.find_router = mock.Mock(return_value=router) + arglist = [ + "--qos-policy", + router.id, + ] + verifylist = [ + ('router', router.id), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + self.assertRaises(exceptions.CommandError, + self.cmd.take_action, parsed_args) + + def test_unset_gateway_ip_qos_no_qos(self): + qos_policy = network_fakes.FakeNetworkQosPolicy.create_one_qos_policy() + self.network.find_qos_policy = mock.Mock(return_value=qos_policy) + router = network_fakes.FakeRouter.create_one_router( + {"external_gateway_info": {"network_id": "fake-id"}}) + self.network.find_router = mock.Mock(return_value=router) + arglist = [ + "--qos-policy", + router.id, + ] + verifylist = [ + ('router', router.id), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + self.assertRaises(exceptions.CommandError, + self.cmd.take_action, parsed_args) diff --git a/releasenotes/notes/router-gateway-IP-QoS-c8ba95e180bca05f.yaml b/releasenotes/notes/router-gateway-IP-QoS-c8ba95e180bca05f.yaml new file mode 100644 index 000000000..efe9a3762 --- /dev/null +++ b/releasenotes/notes/router-gateway-IP-QoS-c8ba95e180bca05f.yaml @@ -0,0 +1,9 @@ +--- +features: + - | + Add support for attaching and removing qos policy to router gateway IPs. + + Add ``--qos-policy`` and ``--no-qos-policy`` options to the + ``router set`` command. + + Add ``--qos-policy`` option to the ``router unset`` command.