Add support for managing external gateways
This change implements the logic to call the new API for managing external gateways. Relevant Neutron core change: https://review.opendev.org/c/openstack/neutron/+/873593 Co-Authored-by: Frode Nordahl <frode.nordahl@canonical.com> Related-Bug: #2002687 Change-Id: Ib45f30f552934a0a5c035c3b7fadfc0d522219ba
This commit is contained in:
parent
58ad3cefa7
commit
16c695045c
@ -13,6 +13,7 @@
|
||||
|
||||
"""Router action implementations"""
|
||||
|
||||
import collections
|
||||
import copy
|
||||
import json
|
||||
import logging
|
||||
@ -85,23 +86,67 @@ def _get_columns(item):
|
||||
)
|
||||
|
||||
|
||||
def is_multiple_gateways_supported(n_client):
|
||||
return n_client.find_extension("external-gateway-multihoming") is not None
|
||||
|
||||
|
||||
def _passed_multiple_gateways(extension_supported, external_gateways):
|
||||
passed_multiple_gws = len(external_gateways) > 1
|
||||
if passed_multiple_gws and not extension_supported:
|
||||
msg = _(
|
||||
'Supplying --external-gateway option multiple times is not '
|
||||
'supported due to the lack of external-gateway-multihoming '
|
||||
'extension at the Neutron side.'
|
||||
)
|
||||
raise exceptions.CommandError(msg)
|
||||
return passed_multiple_gws
|
||||
|
||||
|
||||
def _get_external_gateway_attrs(client_manager, parsed_args):
|
||||
attrs = {}
|
||||
|
||||
if parsed_args.external_gateway:
|
||||
gateway_info = {}
|
||||
if parsed_args.external_gateways:
|
||||
external_gateways: collections.defaultdict[
|
||||
str, list[dict]
|
||||
] = collections.defaultdict(list)
|
||||
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
|
||||
first_network_id = None
|
||||
|
||||
for gw_net_name_or_id in parsed_args.external_gateways:
|
||||
gateway_info = {}
|
||||
gw_net = n_client.find_network(
|
||||
gw_net_name_or_id, ignore_missing=False
|
||||
)
|
||||
if first_network_id is None:
|
||||
first_network_id = gw_net.id
|
||||
gateway_info['network_id'] = gw_net.id
|
||||
if 'disable_snat' in parsed_args and parsed_args.disable_snat:
|
||||
gateway_info['enable_snat'] = False
|
||||
if 'enable_snat' in parsed_args and parsed_args.enable_snat:
|
||||
gateway_info['enable_snat'] = True
|
||||
|
||||
# This option was added before multiple gateways were supported, so
|
||||
# it does not have a per-gateway port granularity so just pass it
|
||||
# along in gw info in case it is specified.
|
||||
if 'qos_policy' in parsed_args and parsed_args.qos_policy:
|
||||
qos_id = n_client.find_qos_policy(
|
||||
parsed_args.qos_policy, ignore_missing=False
|
||||
).id
|
||||
gateway_info['qos_policy_id'] = qos_id
|
||||
if 'no_qos_policy' in parsed_args and parsed_args.no_qos_policy:
|
||||
gateway_info['qos_policy_id'] = None
|
||||
|
||||
external_gateways[gw_net.id].append(gateway_info)
|
||||
|
||||
multiple_gws_supported = is_multiple_gateways_supported(n_client)
|
||||
# Parse the external fixed IP specs and match them to specific gateway
|
||||
# ports if needed.
|
||||
if parsed_args.fixed_ips:
|
||||
ips = []
|
||||
for ip_spec in parsed_args.fixed_ips:
|
||||
# If there is only one gateway, this value will represent the
|
||||
# network ID for it, otherwise it will be overridden.
|
||||
ip_net_id = first_network_id
|
||||
|
||||
if ip_spec.get('subnet', False):
|
||||
subnet_name_id = ip_spec.pop('subnet')
|
||||
if subnet_name_id:
|
||||
@ -109,12 +154,45 @@ def _get_external_gateway_attrs(client_manager, parsed_args):
|
||||
subnet_name_id, ignore_missing=False
|
||||
)
|
||||
ip_spec['subnet_id'] = subnet.id
|
||||
ip_net_id = subnet.network_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
|
||||
# Finally, add an ip_spec to the specific gateway identified
|
||||
# by a network from the spec.
|
||||
if (
|
||||
'subnet_id' in ip_spec
|
||||
and ip_net_id not in external_gateways
|
||||
):
|
||||
msg = _(
|
||||
'Subnet %s does not belong to any of the networks '
|
||||
'provided for --external-gateway.'
|
||||
) % (ip_spec['subnet_id'])
|
||||
raise exceptions.CommandError(msg)
|
||||
for gw_info in external_gateways[ip_net_id]:
|
||||
if 'external_fixed_ips' not in gw_info:
|
||||
gw_info['external_fixed_ips'] = [ip_spec]
|
||||
break
|
||||
else:
|
||||
# The end user has requested more fixed IPs than there are
|
||||
# gateways, add multiple fixed IPs to single gateway to
|
||||
# retain current behavior.
|
||||
for gw_info in external_gateways[ip_net_id]:
|
||||
gw_info['external_fixed_ips'].append(ip_spec)
|
||||
break
|
||||
|
||||
# Use the newer API whenever it is supported regardless of whether one
|
||||
# or multiple gateways are passed as arguments.
|
||||
if multiple_gws_supported:
|
||||
gateway_list = []
|
||||
# Now merge the per-network-id lists of external gateway info
|
||||
# dicts into one list.
|
||||
for gw_info_list in external_gateways.values():
|
||||
gateway_list.extend(gw_info_list)
|
||||
attrs['external_gateways'] = gateway_list
|
||||
else:
|
||||
attrs['external_gateway_info'] = external_gateways[
|
||||
first_network_id
|
||||
][0]
|
||||
return attrs
|
||||
|
||||
|
||||
@ -372,7 +450,13 @@ class CreateRouter(command.ShowOne, common.NeutronCommandWithExtraArgs):
|
||||
parser.add_argument(
|
||||
'--external-gateway',
|
||||
metavar="<network>",
|
||||
help=_("External Network used as router's gateway (name or ID)"),
|
||||
action='append',
|
||||
help=_(
|
||||
"External Network used as router's gateway (name or ID). "
|
||||
"(repeat option to set multiple gateways per router "
|
||||
"if the L3 service plugin in use supports it)."
|
||||
),
|
||||
dest='external_gateways',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--fixed-ip',
|
||||
@ -384,7 +468,7 @@ class CreateRouter(command.ShowOne, common.NeutronCommandWithExtraArgs):
|
||||
"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)"
|
||||
"(repeat option to set multiple fixed IP addresses)."
|
||||
),
|
||||
)
|
||||
snat_group = parser.add_mutually_exclusive_group()
|
||||
@ -433,7 +517,7 @@ class CreateRouter(command.ShowOne, common.NeutronCommandWithExtraArgs):
|
||||
self._parse_extra_properties(parsed_args.extra_properties)
|
||||
)
|
||||
|
||||
if parsed_args.enable_ndp_proxy and not parsed_args.external_gateway:
|
||||
if parsed_args.enable_ndp_proxy and not parsed_args.external_gateways:
|
||||
msg = _(
|
||||
"You must specify '--external-gateway' in order "
|
||||
"to enable router's NDP proxy"
|
||||
@ -443,15 +527,24 @@ class CreateRouter(command.ShowOne, common.NeutronCommandWithExtraArgs):
|
||||
if parsed_args.enable_ndp_proxy is not None:
|
||||
attrs['enable_ndp_proxy'] = parsed_args.enable_ndp_proxy
|
||||
|
||||
external_gateways = attrs.pop('external_gateways', None)
|
||||
obj = client.create_router(**attrs)
|
||||
# tags cannot be set when created, so tags need to be set later.
|
||||
_tag.update_tags_for_set(client, obj, parsed_args)
|
||||
|
||||
# If the multiple external gateways API is intended to be used,
|
||||
# do a separate API call to set the desired external gateways as the
|
||||
# router creation API supports adding only one.
|
||||
if external_gateways:
|
||||
client.update_external_gateways(
|
||||
obj, body={'router': {'external_gateways': external_gateways}}
|
||||
)
|
||||
|
||||
if (
|
||||
parsed_args.disable_snat
|
||||
or parsed_args.enable_snat
|
||||
or parsed_args.fixed_ips
|
||||
) and not parsed_args.external_gateway:
|
||||
) and not parsed_args.external_gateways:
|
||||
msg = _(
|
||||
"You must specify '--external-gateway' in order "
|
||||
"to specify SNAT or fixed-ip values"
|
||||
@ -791,7 +884,13 @@ class SetRouter(common.NeutronCommandWithExtraArgs):
|
||||
parser.add_argument(
|
||||
'--external-gateway',
|
||||
metavar="<network>",
|
||||
help=_("External Network used as router's gateway (name or ID)"),
|
||||
action='append',
|
||||
help=_(
|
||||
"External Network used as router's gateway (name or ID). "
|
||||
"(repeat option to set multiple gateways per router "
|
||||
"if the L3 service plugin in use supports it)."
|
||||
),
|
||||
dest='external_gateways',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--fixed-ip',
|
||||
@ -803,7 +902,7 @@ class SetRouter(common.NeutronCommandWithExtraArgs):
|
||||
"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)"
|
||||
"(repeat option to set multiple fixed IP addresses)."
|
||||
),
|
||||
)
|
||||
snat_group = parser.add_mutually_exclusive_group()
|
||||
@ -873,7 +972,7 @@ class SetRouter(common.NeutronCommandWithExtraArgs):
|
||||
parsed_args.disable_snat
|
||||
or parsed_args.enable_snat
|
||||
or parsed_args.fixed_ips
|
||||
) and not parsed_args.external_gateway:
|
||||
) and not parsed_args.external_gateways:
|
||||
msg = _(
|
||||
"You must specify '--external-gateway' in order "
|
||||
"to update the SNAT or fixed-ip values"
|
||||
@ -882,7 +981,7 @@ class SetRouter(common.NeutronCommandWithExtraArgs):
|
||||
|
||||
if (
|
||||
parsed_args.qos_policy or parsed_args.no_qos_policy
|
||||
) and not parsed_args.external_gateway:
|
||||
) and not parsed_args.external_gateways:
|
||||
try:
|
||||
original_net_id = obj.external_gateway_info['network_id']
|
||||
except (KeyError, TypeError):
|
||||
@ -893,17 +992,21 @@ class SetRouter(common.NeutronCommandWithExtraArgs):
|
||||
)
|
||||
raise exceptions.CommandError(msg)
|
||||
else:
|
||||
if not attrs.get('external_gateway_info'):
|
||||
if not attrs.get('external_gateway_info') and not attrs.get(
|
||||
'external_gateways'
|
||||
):
|
||||
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 not attrs.get('external_gateways'):
|
||||
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 not attrs.get('external_gateways'):
|
||||
attrs['external_gateway_info']['qos_policy_id'] = None
|
||||
|
||||
attrs.update(
|
||||
self._parse_extra_properties(parsed_args.extra_properties)
|
||||
@ -913,7 +1016,16 @@ class SetRouter(common.NeutronCommandWithExtraArgs):
|
||||
attrs['enable_ndp_proxy'] = parsed_args.enable_ndp_proxy
|
||||
|
||||
if attrs:
|
||||
external_gateways = attrs.pop('external_gateways', None)
|
||||
client.update_router(obj, **attrs)
|
||||
# If the multiple external gateways API is intended to be used,
|
||||
# do a separate API call to set external gateways.
|
||||
if external_gateways:
|
||||
client.update_external_gateways(
|
||||
obj,
|
||||
body={'router': {'external_gateways': external_gateways}},
|
||||
)
|
||||
|
||||
# tags is a subresource and it needs to be updated separately.
|
||||
_tag.update_tags_for_set(client, obj, parsed_args)
|
||||
|
||||
@ -973,11 +1085,15 @@ class UnsetRouter(common.NeutronUnsetCommandWithExtraArgs):
|
||||
"(repeat option to unset multiple routes)"
|
||||
),
|
||||
)
|
||||
# NOTE(dmitriis): This was not extended to support selective removal
|
||||
# of external gateways due to a cpython bug in argparse:
|
||||
# https://github.com/python/cpython/issues/53584
|
||||
parser.add_argument(
|
||||
'--external-gateway',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_("Remove external gateway information from the router"),
|
||||
dest='external_gateways',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--qos-policy',
|
||||
@ -1024,7 +1140,7 @@ class UnsetRouter(common.NeutronUnsetCommandWithExtraArgs):
|
||||
'qos_policy_id': None,
|
||||
}
|
||||
|
||||
if parsed_args.external_gateway:
|
||||
if parsed_args.external_gateways:
|
||||
attrs['external_gateway_info'] = {}
|
||||
|
||||
attrs.update(
|
||||
@ -1032,6 +1148,149 @@ class UnsetRouter(common.NeutronUnsetCommandWithExtraArgs):
|
||||
)
|
||||
|
||||
if attrs:
|
||||
# If removing multiple gateways per router are supported,
|
||||
# use the relevant API to remove them all.
|
||||
if is_multiple_gateways_supported(client):
|
||||
client.remove_external_gateways(
|
||||
obj,
|
||||
body={'router': {'external_gateways': {}}},
|
||||
)
|
||||
|
||||
client.update_router(obj, **attrs)
|
||||
# tags is a subresource and it needs to be updated separately.
|
||||
_tag.update_tags_for_unset(client, obj, parsed_args)
|
||||
|
||||
|
||||
class AddGatewayToRouter(command.ShowOne):
|
||||
_description = _("Add router gateway")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super().get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'router',
|
||||
metavar="<router>",
|
||||
help=_("Router to modify (name or ID)."),
|
||||
)
|
||||
parser.add_argument(
|
||||
metavar="<network>",
|
||||
help=_(
|
||||
"External Network to a attach a router gateway to (name or "
|
||||
"ID)."
|
||||
),
|
||||
dest='external_gateways',
|
||||
# The argument is stored in a list in order to reuse the
|
||||
# common attribute parsing code.
|
||||
nargs=1,
|
||||
)
|
||||
parser.add_argument(
|
||||
'--fixed-ip',
|
||||
metavar='subnet=<subnet>,ip-address=<ip-address>',
|
||||
action=parseractions.MultiKeyValueAction,
|
||||
optional_keys=['subnet', 'ip-address'],
|
||||
dest='fixed_ips',
|
||||
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)."
|
||||
),
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = self.app.client_manager.network
|
||||
if not is_multiple_gateways_supported(client):
|
||||
msg = _(
|
||||
'The external-gateway-multihoming extension is not enabled at '
|
||||
'the Neutron side.'
|
||||
)
|
||||
raise exceptions.CommandError(msg)
|
||||
|
||||
router_obj = client.find_router(
|
||||
parsed_args.router, ignore_missing=False
|
||||
)
|
||||
|
||||
# Get the common attributes.
|
||||
attrs = _get_external_gateway_attrs(
|
||||
self.app.client_manager, parsed_args
|
||||
)
|
||||
|
||||
if attrs:
|
||||
external_gateways = attrs.pop('external_gateways')
|
||||
router_obj = client.add_external_gateways(
|
||||
router_obj,
|
||||
body={'router': {'external_gateways': external_gateways}},
|
||||
)
|
||||
|
||||
display_columns, columns = _get_columns(router_obj)
|
||||
data = utils.get_item_properties(
|
||||
router_obj, columns, formatters=_formatters
|
||||
)
|
||||
return (display_columns, data)
|
||||
|
||||
|
||||
class RemoveGatewayFromRouter(command.ShowOne):
|
||||
_description = _("Remove router gateway")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super().get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'router',
|
||||
metavar="<router>",
|
||||
help=_("Router to modify (name or ID)."),
|
||||
)
|
||||
parser.add_argument(
|
||||
metavar="<network>",
|
||||
help=_(
|
||||
"External Network to remove a router gateway from (name or "
|
||||
"ID)."
|
||||
),
|
||||
dest='external_gateways',
|
||||
# The argument is stored in a list in order to reuse the
|
||||
# common attribute parsing code.
|
||||
nargs=1,
|
||||
)
|
||||
parser.add_argument(
|
||||
'--fixed-ip',
|
||||
metavar='subnet=<subnet>,ip-address=<ip-address>',
|
||||
action=parseractions.MultiKeyValueAction,
|
||||
optional_keys=['subnet', 'ip-address'],
|
||||
dest='fixed_ips',
|
||||
help=_(
|
||||
"IP and/or subnet (name or ID) on the external gateway "
|
||||
"which is used to identify a particular gateway if multiple "
|
||||
"are attached to the same network: subnet=<subnet>,"
|
||||
"ip-address=<ip-address>."
|
||||
),
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = self.app.client_manager.network
|
||||
if not is_multiple_gateways_supported(client):
|
||||
msg = _(
|
||||
'The external-gateway-multihoming extension is not enabled at '
|
||||
'the Neutron side.'
|
||||
)
|
||||
raise exceptions.CommandError(msg)
|
||||
|
||||
router_obj = client.find_router(
|
||||
parsed_args.router, ignore_missing=False
|
||||
)
|
||||
|
||||
# Get the common attributes.
|
||||
attrs = _get_external_gateway_attrs(
|
||||
self.app.client_manager, parsed_args
|
||||
)
|
||||
if attrs:
|
||||
external_gateways = attrs.pop('external_gateways')
|
||||
router_obj = client.remove_external_gateways(
|
||||
router_obj,
|
||||
body={'router': {'external_gateways': external_gateways}},
|
||||
)
|
||||
|
||||
display_columns, columns = _get_columns(router_obj)
|
||||
data = utils.get_item_properties(
|
||||
router_obj, columns, formatters=_formatters
|
||||
)
|
||||
return (display_columns, data)
|
||||
|
@ -75,7 +75,7 @@ class TestAddPortToRouter(TestRouter):
|
||||
self._router,
|
||||
**{
|
||||
'port_id': self._router.port,
|
||||
}
|
||||
},
|
||||
)
|
||||
self.assertIsNone(result)
|
||||
|
||||
@ -130,6 +130,7 @@ class TestAddSubnetToRouter(TestRouter):
|
||||
class TestCreateRouter(TestRouter):
|
||||
# The new router created.
|
||||
new_router = network_fakes.FakeRouter.create_one_router()
|
||||
_extensions = {'fake': network_fakes.create_one_extension()}
|
||||
|
||||
columns = (
|
||||
'admin_state_up',
|
||||
@ -169,7 +170,9 @@ class TestCreateRouter(TestRouter):
|
||||
return_value=self.new_router
|
||||
)
|
||||
self.network_client.set_tags = mock.Mock(return_value=None)
|
||||
|
||||
self.network_client.find_extension = mock.Mock(
|
||||
side_effect=lambda name: self._extensions.get(name)
|
||||
)
|
||||
# Get the command object to test
|
||||
self.cmd = router.CreateRouter(self.app, self.namespace)
|
||||
|
||||
@ -228,7 +231,7 @@ class TestCreateRouter(TestRouter):
|
||||
('enable', True),
|
||||
('distributed', False),
|
||||
('ha', False),
|
||||
('external_gateway', _network.name),
|
||||
('external_gateways', [_network.name]),
|
||||
('enable_snat', True),
|
||||
('fixed_ips', [{'ip-address': '2001:db8::1'}]),
|
||||
]
|
||||
@ -1100,10 +1103,13 @@ class TestSetRouter(TestRouter):
|
||||
# The router to set.
|
||||
_default_route = {'destination': '10.20.20.0/24', 'nexthop': '10.20.30.1'}
|
||||
_network = network_fakes.create_one_network()
|
||||
_subnet = network_fakes.FakeSubnet.create_one_subnet()
|
||||
_subnet = network_fakes.FakeSubnet.create_one_subnet(
|
||||
attrs={'network_id': _network.id}
|
||||
)
|
||||
_router = network_fakes.FakeRouter.create_one_router(
|
||||
attrs={'routes': [_default_route], 'tags': ['green', 'red']}
|
||||
)
|
||||
_extensions = {'fake': network_fakes.create_one_extension()}
|
||||
|
||||
def setUp(self):
|
||||
super(TestSetRouter, self).setUp()
|
||||
@ -1114,7 +1120,9 @@ class TestSetRouter(TestRouter):
|
||||
return_value=self._network
|
||||
)
|
||||
self.network_client.find_subnet = mock.Mock(return_value=self._subnet)
|
||||
|
||||
self.network_client.find_extension = mock.Mock(
|
||||
side_effect=lambda name: self._extensions.get(name)
|
||||
)
|
||||
# Get the command object to test
|
||||
self.cmd = router.SetRouter(self.app, self.namespace)
|
||||
|
||||
@ -1312,7 +1320,7 @@ class TestSetRouter(TestRouter):
|
||||
self._router.id,
|
||||
]
|
||||
verifylist = [
|
||||
('external_gateway', self._network.id),
|
||||
('external_gateways', [self._network.id]),
|
||||
('router', self._router.id),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
@ -1320,7 +1328,7 @@ class TestSetRouter(TestRouter):
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
self.network_client.update_router.assert_called_with(
|
||||
self._router,
|
||||
**{'external_gateway_info': {'network_id': self._network.id}}
|
||||
**{'external_gateway_info': {'network_id': self._network.id}},
|
||||
)
|
||||
self.assertIsNone(result)
|
||||
|
||||
@ -1335,7 +1343,7 @@ class TestSetRouter(TestRouter):
|
||||
]
|
||||
verifylist = [
|
||||
('router', self._router.id),
|
||||
('external_gateway', self._network.id),
|
||||
('external_gateways', [self._network.id]),
|
||||
('fixed_ips', [{'subnet': "'abc'"}]),
|
||||
('enable_snat', True),
|
||||
]
|
||||
@ -1354,7 +1362,7 @@ class TestSetRouter(TestRouter):
|
||||
],
|
||||
'enable_snat': True,
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
self.assertIsNone(result)
|
||||
|
||||
@ -1369,7 +1377,7 @@ class TestSetRouter(TestRouter):
|
||||
]
|
||||
verifylist = [
|
||||
('router', self._router.id),
|
||||
('external_gateway', self._network.id),
|
||||
('external_gateways', [self._network.id]),
|
||||
('fixed_ips', [{'ip-address': "10.0.1.1"}]),
|
||||
('enable_snat', True),
|
||||
]
|
||||
@ -1388,7 +1396,7 @@ class TestSetRouter(TestRouter):
|
||||
],
|
||||
'enable_snat': True,
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
self.assertIsNone(result)
|
||||
|
||||
@ -1403,7 +1411,7 @@ class TestSetRouter(TestRouter):
|
||||
]
|
||||
verifylist = [
|
||||
('router', self._router.id),
|
||||
('external_gateway', self._network.id),
|
||||
('external_gateways', [self._network.id]),
|
||||
('fixed_ips', [{'subnet': "'abc'", 'ip-address': "10.0.1.1"}]),
|
||||
('enable_snat', True),
|
||||
]
|
||||
@ -1423,7 +1431,7 @@ class TestSetRouter(TestRouter):
|
||||
],
|
||||
'enable_snat': True,
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
self.assertIsNone(result)
|
||||
|
||||
@ -1468,7 +1476,7 @@ class TestSetRouter(TestRouter):
|
||||
]
|
||||
verifylist = [
|
||||
('router', self._router.id),
|
||||
('external_gateway', self._network.id),
|
||||
('external_gateways', [self._network.id]),
|
||||
('qos_policy', qos_policy.id),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
@ -1481,7 +1489,7 @@ class TestSetRouter(TestRouter):
|
||||
'network_id': self._network.id,
|
||||
'qos_policy_id': qos_policy.id,
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
self.assertIsNone(result)
|
||||
|
||||
@ -1494,7 +1502,7 @@ class TestSetRouter(TestRouter):
|
||||
]
|
||||
verifylist = [
|
||||
('router', self._router.id),
|
||||
('external_gateway', self._network.id),
|
||||
('external_gateways', [self._network.id]),
|
||||
('no_qos_policy', True),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
@ -1507,7 +1515,7 @@ class TestSetRouter(TestRouter):
|
||||
'network_id': self._network.id,
|
||||
'qos_policy_id': None,
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
self.assertIsNone(result)
|
||||
|
||||
@ -1526,7 +1534,7 @@ class TestSetRouter(TestRouter):
|
||||
]
|
||||
verifylist = [
|
||||
('router', self._router.id),
|
||||
('external_gateway', self._network.id),
|
||||
('external_gateways', [self._network.id]),
|
||||
('qos_policy', qos_policy.id),
|
||||
('no_qos_policy', True),
|
||||
]
|
||||
@ -1747,6 +1755,13 @@ class TestUnsetRouter(TestRouter):
|
||||
)
|
||||
self.network_client.update_router = mock.Mock(return_value=None)
|
||||
self.network_client.set_tags = mock.Mock(return_value=None)
|
||||
self._extensions = {'fake': network_fakes.create_one_extension()}
|
||||
self.network_client.find_extension = mock.Mock(
|
||||
side_effect=lambda name: self._extensions.get(name)
|
||||
)
|
||||
self.network_client.remove_external_gateways = mock.Mock(
|
||||
return_value=None
|
||||
)
|
||||
# Get the command object to test
|
||||
self.cmd = router.UnsetRouter(self.app, self.namespace)
|
||||
|
||||
@ -1799,7 +1814,7 @@ class TestUnsetRouter(TestRouter):
|
||||
'--external-gateway',
|
||||
self._testrouter.name,
|
||||
]
|
||||
verifylist = [('external_gateway', True)]
|
||||
verifylist = [('external_gateways', True)]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
attrs = {'external_gateway_info': {}}
|
||||
@ -1808,6 +1823,33 @@ class TestUnsetRouter(TestRouter):
|
||||
)
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_unset_router_external_gateway_multiple_supported(self):
|
||||
# Add the relevant extension in order to test the alternate behavior.
|
||||
self._extensions = {
|
||||
'external-gateway-multihoming': network_fakes.create_one_extension(
|
||||
attrs={'name': 'external-gateway-multihoming'}
|
||||
)
|
||||
}
|
||||
arglist = [
|
||||
'--external-gateway',
|
||||
self._testrouter.name,
|
||||
]
|
||||
verifylist = [('external_gateways', True)]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
# The removal of all gateways should be requested using the multiple
|
||||
# gateways API.
|
||||
self.network_client.remove_external_gateways.assert_called_once_with(
|
||||
self._testrouter, body={'router': {'external_gateways': {}}}
|
||||
)
|
||||
# The compatibility API will also be called in order to potentially
|
||||
# unset other parameters along with external_gateway_info which
|
||||
# should already be empty at that point anyway.
|
||||
self.network_client.update_router.assert_called_once_with(
|
||||
self._testrouter, **{'external_gateway_info': {}}
|
||||
)
|
||||
self.assertIsNone(result)
|
||||
|
||||
def _test_unset_tags(self, with_tags=True):
|
||||
if with_tags:
|
||||
arglist = ['--tag', 'red', '--tag', 'blue']
|
||||
@ -1895,3 +1937,539 @@ class TestUnsetRouter(TestRouter):
|
||||
self.assertRaises(
|
||||
exceptions.CommandError, self.cmd.take_action, parsed_args
|
||||
)
|
||||
|
||||
|
||||
class TestGatewayOps(TestRouter):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self._networks = []
|
||||
self._network = network_fakes.create_one_network()
|
||||
self._networks.append(self._network)
|
||||
|
||||
self._router = network_fakes.FakeRouter.create_one_router(
|
||||
{
|
||||
'external_gateway_info': {
|
||||
'network_id': self._network.id,
|
||||
},
|
||||
}
|
||||
)
|
||||
self._subnet = network_fakes.FakeSubnet.create_one_subnet(
|
||||
attrs={'network_id': self._network.id}
|
||||
)
|
||||
self._extensions = {
|
||||
'external-gateway-multihoming': network_fakes.create_one_extension(
|
||||
attrs={'name': 'external-gateway-multihoming'}
|
||||
)
|
||||
}
|
||||
self.network_client.find_extension = mock.Mock(
|
||||
side_effect=lambda name: self._extensions.get(name)
|
||||
)
|
||||
self.network_client.find_router = mock.Mock(return_value=self._router)
|
||||
|
||||
def _find_network(name_or_id, ignore_missing):
|
||||
for network in self._networks:
|
||||
if name_or_id in (network.id, network.name):
|
||||
return network
|
||||
if ignore_missing:
|
||||
return None
|
||||
raise Exception('Test resource not found')
|
||||
|
||||
self.network_client.find_network = mock.Mock(side_effect=_find_network)
|
||||
|
||||
self.network_client.find_subnet = mock.Mock(return_value=self._subnet)
|
||||
self.network_client.add_external_gateways = mock.Mock(
|
||||
return_value=None
|
||||
)
|
||||
self.network_client.remove_external_gateways = mock.Mock(
|
||||
return_value=None
|
||||
)
|
||||
|
||||
|
||||
class TestCreateMultipleGateways(TestGatewayOps):
|
||||
_columns = (
|
||||
'admin_state_up',
|
||||
'availability_zone_hints',
|
||||
'availability_zones',
|
||||
'description',
|
||||
'distributed',
|
||||
'external_gateway_info',
|
||||
'ha',
|
||||
'id',
|
||||
'name',
|
||||
'project_id',
|
||||
'routes',
|
||||
'status',
|
||||
'tags',
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self._second_network = network_fakes.create_one_network()
|
||||
self._networks.append(self._second_network)
|
||||
|
||||
self.network_client.create_router = mock.Mock(
|
||||
return_value=self._router
|
||||
)
|
||||
self.network_client.update_router = mock.Mock(return_value=None)
|
||||
self.network_client.update_external_gateways = mock.Mock(
|
||||
return_value=None
|
||||
)
|
||||
|
||||
self._data = (
|
||||
router.AdminStateColumn(self._router.admin_state_up),
|
||||
format_columns.ListColumn(self._router.availability_zone_hints),
|
||||
format_columns.ListColumn(self._router.availability_zones),
|
||||
self._router.description,
|
||||
self._router.distributed,
|
||||
router.RouterInfoColumn(self._router.external_gateway_info),
|
||||
self._router.ha,
|
||||
self._router.id,
|
||||
self._router.name,
|
||||
self._router.project_id,
|
||||
router.RoutesColumn(self._router.routes),
|
||||
self._router.status,
|
||||
format_columns.ListColumn(self._router.tags),
|
||||
)
|
||||
self.cmd = router.CreateRouter(self.app, self.namespace)
|
||||
|
||||
def test_create_one_gateway(self):
|
||||
arglist = [
|
||||
"--external-gateway",
|
||||
self._network.id,
|
||||
self._router.name,
|
||||
]
|
||||
verifylist = [
|
||||
('name', self._router.name),
|
||||
('external_gateways', [self._network.id]),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
self.network_client.update_external_gateways.assert_called_with(
|
||||
self._router,
|
||||
body={
|
||||
'router': {
|
||||
'external_gateways': [
|
||||
{
|
||||
'network_id': self._network.id,
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
)
|
||||
self.assertEqual(self._columns, columns)
|
||||
self.assertCountEqual(self._data, data)
|
||||
|
||||
def test_create_multiple_gateways(self):
|
||||
arglist = [
|
||||
self._router.name,
|
||||
"--external-gateway",
|
||||
self._network.id,
|
||||
"--external-gateway",
|
||||
self._network.id,
|
||||
"--external-gateway",
|
||||
self._second_network.id,
|
||||
'--fixed-ip',
|
||||
'subnet={},ip-address=10.0.1.1'.format(self._subnet.id),
|
||||
'--fixed-ip',
|
||||
'subnet={},ip-address=10.0.1.2'.format(self._subnet.id),
|
||||
]
|
||||
verifylist = [
|
||||
('name', self._router.name),
|
||||
(
|
||||
'external_gateways',
|
||||
[self._network.id, self._network.id, self._second_network.id],
|
||||
),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
# The router will not have a gateway after the create call, but it
|
||||
# will be added after the update call.
|
||||
self.network_client.create_router.assert_called_once_with(
|
||||
**{
|
||||
'admin_state_up': True,
|
||||
'name': self._router.name,
|
||||
}
|
||||
)
|
||||
self.network_client.update_external_gateways.assert_called_with(
|
||||
self._router,
|
||||
body={
|
||||
'router': {
|
||||
'external_gateways': [
|
||||
{
|
||||
'network_id': self._network.id,
|
||||
'external_fixed_ips': [
|
||||
{
|
||||
'subnet_id': self._subnet.id,
|
||||
'ip_address': '10.0.1.1',
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
'network_id': self._network.id,
|
||||
'external_fixed_ips': [
|
||||
{
|
||||
'subnet_id': self._subnet.id,
|
||||
'ip_address': '10.0.1.2',
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
'network_id': self._second_network.id,
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
)
|
||||
self.assertEqual(self._columns, columns)
|
||||
self.assertCountEqual(self._data, data)
|
||||
|
||||
|
||||
class TestUpdateMultipleGateways(TestGatewayOps):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self._second_network = network_fakes.create_one_network()
|
||||
self._networks.append(self._second_network)
|
||||
|
||||
self.network_client.update_router = mock.Mock(return_value=None)
|
||||
self.network_client.update_external_gateways = mock.Mock(
|
||||
return_value=None
|
||||
)
|
||||
self.cmd = router.SetRouter(self.app, self.namespace)
|
||||
|
||||
def test_update_one_gateway(self):
|
||||
arglist = [
|
||||
"--external-gateway",
|
||||
self._network.id,
|
||||
"--no-qos-policy",
|
||||
self._router.name,
|
||||
]
|
||||
verifylist = [
|
||||
('router', self._router.name),
|
||||
('external_gateways', [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_client.update_external_gateways.assert_called_with(
|
||||
self._router,
|
||||
body={
|
||||
'router': {
|
||||
'external_gateways': [
|
||||
{'network_id': self._network.id, 'qos_policy_id': None}
|
||||
]
|
||||
}
|
||||
},
|
||||
)
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_update_multiple_gateways(self):
|
||||
arglist = [
|
||||
self._router.name,
|
||||
"--external-gateway",
|
||||
self._network.id,
|
||||
"--external-gateway",
|
||||
self._network.id,
|
||||
"--external-gateway",
|
||||
self._second_network.id,
|
||||
'--fixed-ip',
|
||||
'subnet={},ip-address=10.0.1.1'.format(self._subnet.id),
|
||||
'--fixed-ip',
|
||||
'subnet={},ip-address=10.0.1.2'.format(self._subnet.id),
|
||||
"--no-qos-policy",
|
||||
]
|
||||
verifylist = [
|
||||
('router', self._router.name),
|
||||
(
|
||||
'external_gateways',
|
||||
[self._network.id, self._network.id, self._second_network.id],
|
||||
),
|
||||
('no_qos_policy', True),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
self.network_client.update_external_gateways.assert_called_with(
|
||||
self._router,
|
||||
body={
|
||||
'router': {
|
||||
'external_gateways': [
|
||||
{
|
||||
'network_id': self._network.id,
|
||||
'external_fixed_ips': [
|
||||
{
|
||||
'subnet_id': self._subnet.id,
|
||||
'ip_address': '10.0.1.1',
|
||||
}
|
||||
],
|
||||
'qos_policy_id': None,
|
||||
},
|
||||
{
|
||||
'network_id': self._network.id,
|
||||
'external_fixed_ips': [
|
||||
{
|
||||
'subnet_id': self._subnet.id,
|
||||
'ip_address': '10.0.1.2',
|
||||
}
|
||||
],
|
||||
'qos_policy_id': None,
|
||||
},
|
||||
{
|
||||
'network_id': self._second_network.id,
|
||||
'qos_policy_id': None,
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
)
|
||||
self.assertIsNone(result)
|
||||
|
||||
|
||||
class TestAddGatewayRouter(TestGatewayOps):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
# Get the command object to test
|
||||
self.cmd = router.AddGatewayToRouter(self.app, self.namespace)
|
||||
|
||||
self.network_client.add_external_gateways.return_value = self._router
|
||||
|
||||
def test_add_gateway_network_only(self):
|
||||
arglist = [
|
||||
self._router.name,
|
||||
self._network.id,
|
||||
]
|
||||
verifylist = [
|
||||
('router', self._router.name),
|
||||
('external_gateways', [self._network.id]),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
self.network_client.add_external_gateways.assert_called_with(
|
||||
self._router,
|
||||
body={
|
||||
'router': {
|
||||
'external_gateways': [{'network_id': self._network.id}]
|
||||
}
|
||||
},
|
||||
)
|
||||
self.assertEqual(result[1][result[0].index('id')], self._router.id)
|
||||
|
||||
def test_add_gateway_network_fixed_ip(self):
|
||||
arglist = [
|
||||
self._router.name,
|
||||
self._network.id,
|
||||
'--fixed-ip',
|
||||
'subnet={},ip-address=10.0.1.1'.format(self._subnet.id),
|
||||
]
|
||||
verifylist = [
|
||||
('router', self._router.name),
|
||||
('external_gateways', [self._network.id]),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
self.network_client.add_external_gateways.assert_called_with(
|
||||
self._router,
|
||||
body={
|
||||
'router': {
|
||||
'external_gateways': [
|
||||
{
|
||||
'network_id': self._network.id,
|
||||
'external_fixed_ips': [
|
||||
{
|
||||
'subnet_id': self._subnet.id,
|
||||
'ip_address': '10.0.1.1',
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
)
|
||||
self.assertEqual(result[1][result[0].index('id')], self._router.id)
|
||||
|
||||
def test_add_gateway_network_multiple_fixed_ips(self):
|
||||
arglist = [
|
||||
self._router.name,
|
||||
self._network.id,
|
||||
'--fixed-ip',
|
||||
'subnet={},ip-address=10.0.1.1'.format(self._subnet.id),
|
||||
'--fixed-ip',
|
||||
'subnet={},ip-address=10.0.1.2'.format(self._subnet.id),
|
||||
]
|
||||
verifylist = [
|
||||
('router', self._router.name),
|
||||
('external_gateways', [self._network.id]),
|
||||
(
|
||||
'fixed_ips',
|
||||
[
|
||||
{'ip-address': '10.0.1.1', 'subnet': self._subnet.id},
|
||||
{'ip-address': '10.0.1.2', 'subnet': self._subnet.id},
|
||||
],
|
||||
),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
self.network_client.add_external_gateways.assert_called_with(
|
||||
self._router,
|
||||
body={
|
||||
'router': {
|
||||
'external_gateways': [
|
||||
{
|
||||
'network_id': self._network.id,
|
||||
'external_fixed_ips': [
|
||||
{
|
||||
'subnet_id': self._subnet.id,
|
||||
'ip_address': '10.0.1.1',
|
||||
},
|
||||
{
|
||||
'subnet_id': self._subnet.id,
|
||||
'ip_address': '10.0.1.2',
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
)
|
||||
self.assertEqual(result[1][result[0].index('id')], self._router.id)
|
||||
|
||||
def test_add_gateway_network_only_no_extension(self):
|
||||
self._extensions = {}
|
||||
arglist = [
|
||||
self._router.name,
|
||||
self._network.id,
|
||||
]
|
||||
verifylist = [
|
||||
('router', self._router.name),
|
||||
('external_gateways', [self._network.id]),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.assertRaises(
|
||||
exceptions.CommandError, self.cmd.take_action, parsed_args
|
||||
)
|
||||
|
||||
|
||||
class TestRemoveGatewayRouter(TestGatewayOps):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
# Get the command object to test
|
||||
self.cmd = router.RemoveGatewayFromRouter(self.app, self.namespace)
|
||||
|
||||
self.network_client.remove_external_gateways.return_value = (
|
||||
self._router
|
||||
)
|
||||
|
||||
def test_remove_gateway_network_only(self):
|
||||
arglist = [
|
||||
self._router.name,
|
||||
self._network.id,
|
||||
]
|
||||
verifylist = [
|
||||
('router', self._router.name),
|
||||
('external_gateways', [self._network.id]),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
self.network_client.remove_external_gateways.assert_called_with(
|
||||
self._router,
|
||||
body={
|
||||
'router': {
|
||||
'external_gateways': [{'network_id': self._network.id}]
|
||||
}
|
||||
},
|
||||
)
|
||||
self.assertEqual(result[1][result[0].index('id')], self._router.id)
|
||||
|
||||
def test_remove_gateway_network_fixed_ip(self):
|
||||
arglist = [
|
||||
self._router.name,
|
||||
self._network.id,
|
||||
'--fixed-ip',
|
||||
'subnet={},ip-address=10.0.1.1'.format(self._subnet.id),
|
||||
]
|
||||
verifylist = [
|
||||
('router', self._router.name),
|
||||
('external_gateways', [self._network.id]),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
self.network_client.remove_external_gateways.assert_called_with(
|
||||
self._router,
|
||||
body={
|
||||
'router': {
|
||||
'external_gateways': [
|
||||
{
|
||||
'network_id': self._network.id,
|
||||
'external_fixed_ips': [
|
||||
{
|
||||
'subnet_id': self._subnet.id,
|
||||
'ip_address': '10.0.1.1',
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
)
|
||||
self.assertEqual(result[1][result[0].index('id')], self._router.id)
|
||||
|
||||
def test_remove_gateway_network_multiple_fixed_ips(self):
|
||||
arglist = [
|
||||
self._router.name,
|
||||
self._network.id,
|
||||
'--fixed-ip',
|
||||
'subnet={},ip-address=10.0.1.1'.format(self._subnet.id),
|
||||
'--fixed-ip',
|
||||
'subnet={},ip-address=10.0.1.2'.format(self._subnet.id),
|
||||
]
|
||||
verifylist = [
|
||||
('router', self._router.name),
|
||||
('external_gateways', [self._network.id]),
|
||||
(
|
||||
'fixed_ips',
|
||||
[
|
||||
{'ip-address': '10.0.1.1', 'subnet': self._subnet.id},
|
||||
{'ip-address': '10.0.1.2', 'subnet': self._subnet.id},
|
||||
],
|
||||
),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
self.network_client.remove_external_gateways.assert_called_with(
|
||||
self._router,
|
||||
body={
|
||||
'router': {
|
||||
'external_gateways': [
|
||||
{
|
||||
'network_id': self._network.id,
|
||||
'external_fixed_ips': [
|
||||
{
|
||||
'subnet_id': self._subnet.id,
|
||||
'ip_address': '10.0.1.1',
|
||||
},
|
||||
{
|
||||
'subnet_id': self._subnet.id,
|
||||
'ip_address': '10.0.1.2',
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
)
|
||||
self.assertEqual(result[1][result[0].index('id')], self._router.id)
|
||||
|
||||
def test_remove_gateway_network_only_no_extension(self):
|
||||
self._extensions = {}
|
||||
arglist = [
|
||||
self._router.name,
|
||||
self._network.id,
|
||||
]
|
||||
verifylist = [
|
||||
('router', self._router.name),
|
||||
('external_gateways', [self._network.id]),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.assertRaises(
|
||||
exceptions.CommandError, self.cmd.take_action, parsed_args
|
||||
)
|
||||
|
@ -560,12 +560,14 @@ openstack.network.v2 =
|
||||
port_show = openstackclient.network.v2.port:ShowPort
|
||||
port_unset = openstackclient.network.v2.port:UnsetPort
|
||||
|
||||
router_add_gateway = openstackclient.network.v2.router:AddGatewayToRouter
|
||||
router_add_port = openstackclient.network.v2.router:AddPortToRouter
|
||||
router_add_route = openstackclient.network.v2.router:AddExtraRoutesToRouter
|
||||
router_add_subnet = openstackclient.network.v2.router:AddSubnetToRouter
|
||||
router_create = openstackclient.network.v2.router:CreateRouter
|
||||
router_delete = openstackclient.network.v2.router:DeleteRouter
|
||||
router_list = openstackclient.network.v2.router:ListRouter
|
||||
router_remove_gateway = openstackclient.network.v2.router:RemoveGatewayFromRouter
|
||||
router_remove_port = openstackclient.network.v2.router:RemovePortFromRouter
|
||||
router_remove_route = openstackclient.network.v2.router:RemoveExtraRoutesFromRouter
|
||||
router_remove_subnet = openstackclient.network.v2.router:RemoveSubnetFromRouter
|
||||
|
Loading…
x
Reference in New Issue
Block a user