NSXv3: Router GW support
Change-Id: Ifae6815754f048cc1e8708662fa28e74ca297eeb
This commit is contained in:
parent
43d2a57b82
commit
8d26063364
|
@ -16,6 +16,8 @@
|
|||
from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
|
||||
from neutron.i18n import _LW
|
||||
|
||||
from vmware_nsx.neutron.plugins.vmware.common import exceptions as nsx_exc
|
||||
from vmware_nsx.neutron.plugins.vmware.common import nsx_constants
|
||||
from vmware_nsx.neutron.plugins.vmware.common import utils
|
||||
|
@ -23,6 +25,16 @@ from vmware_nsx.neutron.plugins.vmware.nsxlib.v3 import client
|
|||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
# TODO(berlin): move them to nsx_constants file
|
||||
# Router logical port types
|
||||
LROUTERPORT_UPLINK = "LogicalRouterUplinkPort"
|
||||
LROUTERPORT_DOWNLINK = "LogicalRouterDownLinkPort"
|
||||
LROUTERPORT_LINK = "LogicalRouterLinkPort"
|
||||
|
||||
LROUTER_TYPES = [LROUTERPORT_UPLINK,
|
||||
LROUTERPORT_DOWNLINK,
|
||||
LROUTERPORT_LINK]
|
||||
|
||||
ROUTER_INTF_PORT_NAME = "Tier1-RouterDownLinkPort"
|
||||
|
||||
|
||||
|
@ -39,6 +51,32 @@ def update_resource_with_retry(resource, payload):
|
|||
return client.update_resource(resource, revised_payload)
|
||||
|
||||
|
||||
def delete_resource_by_values(resource, res_id='id', skip_not_found=True,
|
||||
**kwargs):
|
||||
resources_get = client.get_resource(resource)
|
||||
for res in resources_get['results']:
|
||||
is_matched = True
|
||||
for (key, value) in kwargs.items():
|
||||
if res.get(key) != value:
|
||||
is_matched = False
|
||||
break
|
||||
if is_matched:
|
||||
LOG.debug("Deleting %s from resource %s", res, resource)
|
||||
delete_resource = resource + "/" + str(res[res_id])
|
||||
client.delete_resource(delete_resource)
|
||||
return
|
||||
if skip_not_found:
|
||||
LOG.warning(_LW("No resource in %(res)s matched for values: "
|
||||
"%(values)s"), {'res': resource,
|
||||
'values': kwargs})
|
||||
else:
|
||||
err_msg = (_("No resource in %(res)s matched for values: %(values)s") %
|
||||
{'res': resource,
|
||||
'values': kwargs})
|
||||
raise nsx_exc.ResourceNotFound(manager=client._get_manager_ip(),
|
||||
operation=err_msg)
|
||||
|
||||
|
||||
def create_logical_switch(display_name, transport_zone_id, tags,
|
||||
replication_mode=nsx_constants.MTEP,
|
||||
admin_state=True, vlan_id=None):
|
||||
|
@ -181,6 +219,8 @@ def update_logical_router(lrouter_id, **kwargs):
|
|||
|
||||
|
||||
def delete_logical_router(lrouter_id):
|
||||
# TODO(berlin): need to verify whether cascade prefix is valid to delete
|
||||
# router link port and its relative nat rules
|
||||
resource = 'logical-routers/%s/' % lrouter_id
|
||||
|
||||
# TODO(salv-orlando): Must handle connection exceptions
|
||||
|
@ -213,8 +253,8 @@ def create_logical_router_port_by_ls_id(logical_router_id,
|
|||
except nsx_exc.ResourceNotFound:
|
||||
return create_logical_router_port(logical_router_id,
|
||||
ROUTER_INTF_PORT_NAME,
|
||||
logical_switch_port_id,
|
||||
resource_type,
|
||||
logical_switch_port_id,
|
||||
address_groups)
|
||||
else:
|
||||
return update_logical_router_port(port['id'], subnets=address_groups)
|
||||
|
@ -222,15 +262,23 @@ def create_logical_router_port_by_ls_id(logical_router_id,
|
|||
|
||||
def create_logical_router_port(logical_router_id,
|
||||
display_name,
|
||||
logical_switch_port_id,
|
||||
resource_type,
|
||||
address_groups):
|
||||
logical_port_id,
|
||||
address_groups,
|
||||
edge_cluster_member_index=None):
|
||||
resource = 'logical-router-ports'
|
||||
body = {'display_name': display_name,
|
||||
'resource_type': resource_type,
|
||||
'logical_router_id': logical_router_id,
|
||||
'subnets': address_groups,
|
||||
'linked_logical_switch_port_id': logical_switch_port_id}
|
||||
'logical_router_id': logical_router_id}
|
||||
if address_groups:
|
||||
body['subnets'] = address_groups
|
||||
if resource_type in [LROUTERPORT_UPLINK,
|
||||
LROUTERPORT_DOWNLINK]:
|
||||
body['linked_logical_switch_port_id'] = logical_port_id
|
||||
elif logical_port_id:
|
||||
body['linked_logical_router_port_id'] = logical_port_id
|
||||
if edge_cluster_member_index:
|
||||
body['edge_cluster_member_index'] = edge_cluster_member_index
|
||||
|
||||
return client.create_resource(resource, body)
|
||||
|
||||
|
@ -256,6 +304,56 @@ def delete_logical_router_port(logical_port_id):
|
|||
client.delete_resource(resource)
|
||||
|
||||
|
||||
def get_logical_router_ports_by_router_id(logical_router_id):
|
||||
resource = 'logical-router-ports'
|
||||
logical_router_ports = client.get_resource(
|
||||
resource, logical_router_id=logical_router_id)
|
||||
return logical_router_ports['results']
|
||||
|
||||
|
||||
def get_tier1_logical_router_link_port(logical_router_id):
|
||||
logical_router_ports = get_logical_router_ports_by_router_id(
|
||||
logical_router_id)
|
||||
for port in logical_router_ports:
|
||||
if port['resource_type'] == LROUTERPORT_LINK:
|
||||
return port
|
||||
raise nsx_exc.ResourceNotFound(
|
||||
manager=client._get_manager_ip(),
|
||||
operation="get router link port")
|
||||
|
||||
|
||||
def add_nat_rule(logical_router_id, action, translated_network,
|
||||
source_net=None, dest_net=None,
|
||||
enabled=True, rule_priority=None):
|
||||
resource = 'logical-routers/%s/nat/rules' % logical_router_id
|
||||
body = {'action': action,
|
||||
'enabled': enabled,
|
||||
'translated_network': translated_network}
|
||||
if source_net:
|
||||
body['match_source_network'] = source_net
|
||||
if dest_net:
|
||||
body['match_destination_network'] = dest_net
|
||||
if rule_priority:
|
||||
body['rule_priority'] = rule_priority
|
||||
return client.create_resource(resource, body)
|
||||
|
||||
|
||||
def delete_nat_rule(logical_router_id, nat_rule_id):
|
||||
resource = 'logical-routers/%s/nat/rules/%s' % (logical_router_id,
|
||||
nat_rule_id)
|
||||
client.delete_resource(resource)
|
||||
|
||||
|
||||
def delete_nat_rule_by_values(logical_router_id, **kwargs):
|
||||
resource = 'logical-routers/%s/nat/rules' % logical_router_id
|
||||
return delete_resource_by_values(resource, res_id='rule_id', **kwargs)
|
||||
|
||||
|
||||
def update_logical_router_advertisement(logical_router_id, **kwargs):
|
||||
resource = 'logical-routers/%s/routing/advertisement' % logical_router_id
|
||||
return update_resource_with_retry(resource, kwargs)
|
||||
|
||||
|
||||
def create_qos_switching_profile(tags, qos_marking=None, dscp=None, name=None,
|
||||
description=None):
|
||||
resource = 'switching-profiles'
|
||||
|
|
|
@ -65,13 +65,14 @@ def _validate_result(result, expected, operation):
|
|||
raise manager_error(manager=manager_ip, operation=operation)
|
||||
|
||||
|
||||
def get_resource(resource):
|
||||
def get_resource(resource, **params):
|
||||
manager, user, password, verify = _get_manager_endpoint()
|
||||
url = manager + "/api/v1/%s" % resource
|
||||
headers = {'Accept': 'application/json'}
|
||||
result = requests.get(url, auth=auth.HTTPBasicAuth(user, password),
|
||||
verify=verify, headers=headers,
|
||||
cert=cfg.CONF.nsx_v3.ca_file)
|
||||
cert=cfg.CONF.nsx_v3.ca_file,
|
||||
params=params)
|
||||
_validate_result(result, [requests.codes.ok],
|
||||
_("reading resource: %s") % resource)
|
||||
return result.json()
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
# Copyright 2015 VMware, Inc.
|
||||
# All Rights Reserved
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
NSX-V3 Plugin router module
|
||||
"""
|
||||
|
||||
import random
|
||||
|
||||
from neutron.common import exceptions as n_exc
|
||||
from neutron.i18n import _LW
|
||||
from oslo_log import log
|
||||
|
||||
from vmware_nsx.neutron.plugins.vmware.common import exceptions as nsx_exc
|
||||
from vmware_nsx.neutron.plugins.vmware.nsxlib import v3 as nsxlib
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
# TODO(berlin): Remove this when we merges the edge node auto
|
||||
# placement feature.
|
||||
MIN_EDGE_NODE_NUM = 1
|
||||
|
||||
TIER0_ROUTER_LINK_PORT_NAME = "TIER0-RouterLinkPort"
|
||||
TIER1_ROUTER_LINK_PORT_NAME = "TIER1-RouterLinkPort"
|
||||
|
||||
|
||||
def validate_tier0(tier0_groups_dict, tier0_uuid):
|
||||
if tier0_uuid in tier0_groups_dict:
|
||||
return
|
||||
err_msg = None
|
||||
try:
|
||||
lrouter = nsxlib.get_logical_router(tier0_uuid)
|
||||
except nsx_exc.ResourceNotFound:
|
||||
err_msg = _("Failed to validate tier0 router %s since it is "
|
||||
"not found at the backend") % tier0_uuid
|
||||
else:
|
||||
edge_cluster_uuid = lrouter.get('edge_cluster_id')
|
||||
if not edge_cluster_uuid:
|
||||
err_msg = _("Failed to get edge cluster uuid from tier0 "
|
||||
"router %s at the backend") % lrouter
|
||||
else:
|
||||
edge_cluster = nsxlib.get_edge_cluster(edge_cluster_uuid)
|
||||
member_index_list = [member['member_index']
|
||||
for member in edge_cluster['members']]
|
||||
if len(member_index_list) < MIN_EDGE_NODE_NUM:
|
||||
err_msg = _("%(act_num)s edge members found in "
|
||||
"edge_cluster %(cluster_id)s, however we "
|
||||
"require at least %(exp_num)s edge nodes "
|
||||
"in edge cluster for HA use.") % {
|
||||
'act_num': len(member_index_list),
|
||||
'exp_num': MIN_EDGE_NODE_NUM,
|
||||
'cluster_id': edge_cluster_uuid}
|
||||
if err_msg:
|
||||
raise n_exc.InvalidInput(error_message=err_msg)
|
||||
else:
|
||||
tier0_groups_dict[tier0_uuid] = {
|
||||
'edge_cluster_uuid': edge_cluster_uuid,
|
||||
'member_index_list': member_index_list}
|
||||
|
||||
|
||||
def add_router_link_port(tier1_uuid, tier0_uuid, edge_members):
|
||||
# Create Tier0 logical router link port
|
||||
tier0_link_port = nsxlib.create_logical_router_port(
|
||||
tier0_uuid, display_name=TIER0_ROUTER_LINK_PORT_NAME,
|
||||
resource_type=nsxlib.LROUTERPORT_LINK,
|
||||
logical_port_id=None,
|
||||
address_groups=None)
|
||||
linked_logical_port_id = tier0_link_port['id']
|
||||
|
||||
edge_cluster_member_index = random.sample(
|
||||
edge_members, MIN_EDGE_NODE_NUM)
|
||||
# Create Tier1 logical router link port
|
||||
nsxlib.create_logical_router_port(
|
||||
tier1_uuid, display_name=TIER1_ROUTER_LINK_PORT_NAME,
|
||||
resource_type=nsxlib.LROUTERPORT_LINK,
|
||||
logical_port_id=linked_logical_port_id,
|
||||
address_groups=None,
|
||||
edge_cluster_member_index=edge_cluster_member_index)
|
||||
|
||||
|
||||
def remove_router_link_port(tier1_uuid, tier0_uuid):
|
||||
try:
|
||||
tier1_link_port = nsxlib.get_tier1_logical_router_link_port(
|
||||
tier1_uuid)
|
||||
except nsx_exc.ResourceNotFound:
|
||||
LOG.warning(_LW("Logical router link port for tier1 router: %s "
|
||||
"not found at the backend"), tier1_uuid)
|
||||
return
|
||||
tier1_link_port_id = tier1_link_port['id']
|
||||
tier0_link_port_id = tier1_link_port['linked_logical_router_port_id']
|
||||
nsxlib.delete_logical_router_port(tier1_link_port_id)
|
||||
nsxlib.delete_logical_router_port(tier0_link_port_id)
|
||||
|
||||
|
||||
def update_advertisement(logical_router_id, advertise_route_nat,
|
||||
advertise_route_connected):
|
||||
return nsxlib.update_logical_router_advertisement(
|
||||
logical_router_id,
|
||||
advertise_nat_routes=advertise_route_nat,
|
||||
advertise_connected_routes=advertise_route_connected)
|
||||
|
||||
|
||||
def delete_gw_snat_rule(logical_router_id, gw_ip):
|
||||
return nsxlib.delete_nat_rule_by_values(logical_router_id,
|
||||
translated_network=gw_ip)
|
||||
|
||||
|
||||
def add_gw_snat_rule(logical_router_id, gw_ip):
|
||||
return nsxlib.add_nat_rule(logical_router_id, action="SNAT",
|
||||
translated_network=gw_ip,
|
||||
rule_priority=1000)
|
||||
|
||||
|
||||
def update_router_edge_cluster(nsx_router_id, edge_cluster_uuid):
|
||||
return nsxlib.update_logical_router(nsx_router_id,
|
||||
edge_cluster_id=edge_cluster_uuid)
|
|
@ -59,6 +59,7 @@ from vmware_nsx.neutron.plugins.vmware.common import utils
|
|||
from vmware_nsx.neutron.plugins.vmware.dbexts import db as nsx_db
|
||||
from vmware_nsx.neutron.plugins.vmware.nsxlib import v3 as nsxlib
|
||||
from vmware_nsx.neutron.plugins.vmware.nsxlib.v3 import dfw_api as firewall
|
||||
from vmware_nsx.neutron.plugins.vmware.nsxlib.v3 import router as routerlib
|
||||
from vmware_nsx.neutron.plugins.vmware.nsxlib.v3 import security
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
@ -187,35 +188,11 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||
|
||||
return net_type, physical_net, vlan_id
|
||||
|
||||
def _validate_tier0(self, tier0_uuid):
|
||||
if tier0_uuid in self.tier0_groups_dict:
|
||||
return
|
||||
err_msg = None
|
||||
try:
|
||||
lrouter = nsxlib.get_logical_router(tier0_uuid)
|
||||
except nsx_exc.ResourceNotFound:
|
||||
err_msg = _("Failed to validate tier0 router %s since it is "
|
||||
"not found at the backend") % tier0_uuid
|
||||
else:
|
||||
edge_cluster_uuid = lrouter.get('edge_cluster_id')
|
||||
if not edge_cluster_uuid:
|
||||
err_msg = _("Failed to get edge cluster uuid from tier0 "
|
||||
"router %s at the backend") % lrouter
|
||||
else:
|
||||
edge_cluster = nsxlib.get_edge_cluster(edge_cluster_uuid)
|
||||
member_index_list = [member['member_index']
|
||||
for member in edge_cluster['members']]
|
||||
if not member_index_list:
|
||||
err_msg = _("No edge members found in edge_cluster "
|
||||
"%(cluster)s from tier0 router %(tier0)s") % {
|
||||
'cluster': edge_cluster_uuid,
|
||||
'tier0': tier0_uuid}
|
||||
if err_msg:
|
||||
raise n_exc.InvalidInput(error_message=err_msg)
|
||||
else:
|
||||
self.tier0_groups_dict[tier0_uuid] = {
|
||||
'edge_cluster_uuid': edge_cluster_uuid,
|
||||
'member_index_list': member_index_list}
|
||||
def _get_edge_cluster_and_members(self, tier0_uuid):
|
||||
routerlib.validate_tier0(self.tier0_groups_dict, tier0_uuid)
|
||||
tier0_info = self.tier0_groups_dict[tier0_uuid]
|
||||
return (tier0_info['edge_cluster_uuid'],
|
||||
tier0_info['member_index_list'])
|
||||
|
||||
def _validate_external_net_create(self, net_data):
|
||||
is_provider_net = False
|
||||
|
@ -224,7 +201,7 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||
else:
|
||||
tier0_uuid = net_data[pnet.PHYSICAL_NETWORK]
|
||||
is_provider_net = True
|
||||
self._validate_tier0(tier0_uuid)
|
||||
routerlib.validate_tier0(self.tier0_groups_dict, tier0_uuid)
|
||||
return (is_provider_net, utils.NetworkTypes.L3_EXT, tier0_uuid, 0)
|
||||
|
||||
def _create_network_at_the_backend(self, context, net_data):
|
||||
|
@ -559,6 +536,129 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||
raise n_exc.BadRequest(resource='router', msg=msg)
|
||||
return gw_info
|
||||
|
||||
def _get_external_attachment_info(self, context, router):
|
||||
gw_port = router.gw_port
|
||||
ipaddress = None
|
||||
netmask = None
|
||||
nexthop = None
|
||||
|
||||
if gw_port:
|
||||
# gw_port may have multiple IPs, only configure the first one
|
||||
if gw_port.get('fixed_ips'):
|
||||
ipaddress = gw_port['fixed_ips'][0]['ip_address']
|
||||
|
||||
network_id = gw_port.get('network_id')
|
||||
if network_id:
|
||||
ext_net = self._get_network(context, network_id)
|
||||
if not ext_net.external:
|
||||
msg = (_("Network '%s' is not a valid external "
|
||||
"network") % network_id)
|
||||
raise n_exc.BadRequest(resource='router', msg=msg)
|
||||
if ext_net.subnets:
|
||||
ext_subnet = ext_net.subnets[0]
|
||||
netmask = str(netaddr.IPNetwork(ext_subnet.cidr).netmask)
|
||||
nexthop = ext_subnet.gateway_ip
|
||||
|
||||
return (ipaddress, netmask, nexthop)
|
||||
|
||||
def _get_tier0_uuid_by_net(self, context, network_id):
|
||||
if not network_id:
|
||||
return
|
||||
network = self.get_network(context, network_id)
|
||||
if not network.get(pnet.PHYSICAL_NETWORK):
|
||||
return cfg.CONF.nsx_v3.default_tier0_router_uuid
|
||||
else:
|
||||
return network.get(pnet.PHYSICAL_NETWORK)
|
||||
|
||||
def _update_router_gw_info(self, context, router_id, info):
|
||||
router = self._get_router(context, router_id)
|
||||
org_ext_net_id = router.gw_port_id and router.gw_port.network_id
|
||||
org_tier0_uuid = self._get_tier0_uuid_by_net(context, org_ext_net_id)
|
||||
org_enable_snat = router.enable_snat
|
||||
new_ext_net_id = info and info.get('network_id')
|
||||
orgaddr, orgmask, _orgnexthop = (
|
||||
self._get_external_attachment_info(
|
||||
context, router))
|
||||
|
||||
# TODO(berlin): For nonat user case, we actually don't need a gw port
|
||||
# which consumes one external ip. But after looking at the DB logic
|
||||
# and we need to make a big change so don't touch it at present.
|
||||
super(NsxV3Plugin, self)._update_router_gw_info(
|
||||
context, router_id, info, router=router)
|
||||
|
||||
new_ext_net_id = router.gw_port_id and router.gw_port.network_id
|
||||
new_tier0_uuid = self._get_tier0_uuid_by_net(context, new_ext_net_id)
|
||||
new_enable_snat = router.enable_snat
|
||||
newaddr, newmask, _newnexthop = (
|
||||
self._get_external_attachment_info(
|
||||
context, router))
|
||||
nsx_router_id = nsx_db.get_nsx_router_id(context.session, router_id)
|
||||
|
||||
# Remove router link port between tier1 and tier0 if tier0 router link
|
||||
# is removed or changed
|
||||
remove_router_link_port = (org_tier0_uuid and
|
||||
(not new_tier0_uuid or
|
||||
org_tier0_uuid != new_tier0_uuid))
|
||||
|
||||
# Remove SNAT rules for gw ip if gw ip is deleted/changed or
|
||||
# enable_snat is updated from True to False
|
||||
remove_snat_rules = (org_enable_snat and orgaddr and
|
||||
(newaddr != orgaddr or
|
||||
not new_enable_snat))
|
||||
|
||||
# Revocate bgp announce for nonat subnets if tier0 router link is
|
||||
# changed or enable_snat is updated from False to True
|
||||
revocate_bgp_announce = (not org_enable_snat and org_tier0_uuid and
|
||||
(new_tier0_uuid != org_tier0_uuid or
|
||||
new_enable_snat))
|
||||
|
||||
# Add router link port between tier1 and tier0 if tier0 router link is
|
||||
# added or changed to a new one
|
||||
add_router_link_port = (new_tier0_uuid and
|
||||
(not org_tier0_uuid or
|
||||
org_tier0_uuid != new_tier0_uuid))
|
||||
|
||||
# Add SNAT rules for gw ip if gw ip is add/changed or
|
||||
# enable_snat is updated from False to True
|
||||
add_snat_rules = (new_enable_snat and newaddr and
|
||||
(newaddr != orgaddr or
|
||||
not org_enable_snat))
|
||||
|
||||
# Bgp announce for nonat subnets if tier0 router link is changed or
|
||||
# enable_snat is updated from True to False
|
||||
bgp_announce = (not new_enable_snat and new_tier0_uuid and
|
||||
(new_tier0_uuid != org_tier0_uuid or
|
||||
not org_enable_snat))
|
||||
|
||||
advertise_route_nat_flag = True if new_enable_snat else False
|
||||
advertise_route_connected_flag = True if not new_enable_snat else False
|
||||
|
||||
if revocate_bgp_announce:
|
||||
# TODO(berlin): revocate bgp announce on org tier0 router
|
||||
pass
|
||||
if remove_snat_rules:
|
||||
routerlib.delete_gw_snat_rule(nsx_router_id, orgaddr)
|
||||
if remove_router_link_port:
|
||||
routerlib.remove_router_link_port(nsx_router_id, org_tier0_uuid)
|
||||
if add_router_link_port:
|
||||
# First update edge cluster info for router
|
||||
edge_cluster_uuid, members = self._get_edge_cluster_and_members(
|
||||
new_tier0_uuid)
|
||||
routerlib.update_router_edge_cluster(
|
||||
nsx_router_id, edge_cluster_uuid)
|
||||
routerlib.add_router_link_port(nsx_router_id, new_tier0_uuid,
|
||||
members)
|
||||
if add_snat_rules:
|
||||
routerlib.add_gw_snat_rule(nsx_router_id, newaddr)
|
||||
if bgp_announce:
|
||||
# TODO(berlin): bgp announce on new tier0 router
|
||||
pass
|
||||
|
||||
if remove_snat_rules or add_snat_rules:
|
||||
routerlib.update_advertisement(nsx_router_id,
|
||||
advertise_route_nat_flag,
|
||||
advertise_route_connected_flag)
|
||||
|
||||
def create_router(self, context, router):
|
||||
# TODO(berlin): admin_state_up support
|
||||
gw_info = self._extract_external_gw(context, router, is_extract=True)
|
||||
|
@ -590,6 +690,9 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||
return self.get_router(context, router['id'])
|
||||
|
||||
def delete_router(self, context, router_id):
|
||||
router = self.get_router(context, router_id)
|
||||
if router.get(l3.EXTERNAL_GW_INFO):
|
||||
self._update_router_gw_info(context, router_id, {})
|
||||
nsx_router_id = nsx_db.get_nsx_router_id(context.session,
|
||||
router_id)
|
||||
ret_val = super(NsxV3Plugin, self).delete_router(context,
|
||||
|
|
|
@ -210,6 +210,7 @@ class NsxV3Mock(object):
|
|||
self.logical_routers = {}
|
||||
self.logical_router_ports = {}
|
||||
self.logical_ports = {}
|
||||
self.logical_router_nat_rules = {}
|
||||
if default_tier0_router_uuid:
|
||||
self.create_logical_router(
|
||||
DEFAULT_TIER0_ROUTER_UUID, None,
|
||||
|
@ -268,10 +269,11 @@ class NsxV3Mock(object):
|
|||
def get_logical_router_port_by_ls_id(self, logical_switch_id):
|
||||
router_ports = []
|
||||
for router_port in self.logical_router_ports.values():
|
||||
ls_port_id = router_port['linked_logical_switch_port_id']
|
||||
port = self.get_logical_port(ls_port_id)
|
||||
if port['logical_switch_id'] == logical_switch_id:
|
||||
router_ports.append(router_port)
|
||||
ls_port_id = router_port.get('linked_logical_switch_port_id')
|
||||
if ls_port_id:
|
||||
port = self.get_logical_port(ls_port_id)
|
||||
if port['logical_switch_id'] == logical_switch_id:
|
||||
router_ports.append(router_port)
|
||||
if len(router_ports) >= 2:
|
||||
raise nsx_exc.NsxPluginException(
|
||||
err_msg=_("Can't support more than one logical router ports "
|
||||
|
@ -305,18 +307,34 @@ class NsxV3Mock(object):
|
|||
raise nsx_exc.ResourceNotFound(
|
||||
manager=FAKE_MANAGER, operation="get_logical_port")
|
||||
|
||||
def get_logical_router_ports_by_router_id(self, logical_router_id):
|
||||
logical_router_ports = []
|
||||
for port_id in self.logical_router_ports.keys():
|
||||
if (self.logical_router_ports[port_id]['logical_router_id'] ==
|
||||
logical_router_id):
|
||||
logical_router_ports.append(self.logical_router_ports[port_id])
|
||||
return logical_router_ports
|
||||
|
||||
def create_logical_router_port(self, logical_router_id,
|
||||
display_name,
|
||||
logical_switch_port_id,
|
||||
resource_type,
|
||||
address_groups):
|
||||
logical_port_id,
|
||||
address_groups,
|
||||
edge_cluster_member_index=None):
|
||||
fake_router_port_uuid = uuidutils.generate_uuid()
|
||||
body = {'id': fake_router_port_uuid,
|
||||
'display_name': display_name,
|
||||
body = {'display_name': display_name,
|
||||
'resource_type': resource_type,
|
||||
'logical_router_id': logical_router_id,
|
||||
'subnets': address_groups,
|
||||
'linked_logical_switch_port_id': logical_switch_port_id}
|
||||
'logical_router_id': logical_router_id}
|
||||
if address_groups:
|
||||
body['subnets'] = address_groups
|
||||
if resource_type in ["LogicalRouterUplinkPort",
|
||||
"LogicalRouterDownLinkPort"]:
|
||||
body['linked_logical_switch_port_id'] = logical_port_id
|
||||
elif logical_port_id:
|
||||
body['linked_logical_router_port_id'] = logical_port_id
|
||||
if edge_cluster_member_index:
|
||||
body['edge_cluster_member_index'] = edge_cluster_member_index
|
||||
body['id'] = fake_router_port_uuid
|
||||
self.logical_router_ports[fake_router_port_uuid] = body
|
||||
return body
|
||||
|
||||
|
@ -335,3 +353,58 @@ class NsxV3Mock(object):
|
|||
else:
|
||||
raise nsx_exc.ResourceNotFound(
|
||||
manager=FAKE_MANAGER, operation="update_logical_router_port")
|
||||
|
||||
def add_nat_rule(self, logical_router_id, action, translated_network,
|
||||
source_net=None, dest_net=None, enabled=True,
|
||||
rule_priority=None):
|
||||
fake_rule_id = uuidutils.generate_uuid()
|
||||
if logical_router_id not in self.logical_routers.keys():
|
||||
raise nsx_exc.ResourceNotFound(
|
||||
manager=FAKE_MANAGER, operation="get_logical_router")
|
||||
body = {'action': action,
|
||||
'enabled': enabled,
|
||||
'translated_network': translated_network}
|
||||
if source_net:
|
||||
body['match_source_network'] = source_net
|
||||
if dest_net:
|
||||
body['match_destination_network'] = dest_net
|
||||
if rule_priority:
|
||||
body['rule_priority'] = rule_priority
|
||||
body['rule_id'] = fake_rule_id
|
||||
if self.logical_router_nat_rules.get(logical_router_id):
|
||||
self.logical_router_nat_rules[logical_router_id][fake_rule_id] = (
|
||||
body)
|
||||
else:
|
||||
self.logical_router_nat_rules[logical_router_id] = {
|
||||
fake_rule_id: body}
|
||||
return body
|
||||
|
||||
def delete_nat_rule(self, logical_router_id, nat_rule_id):
|
||||
if (self.logical_router_nat_rules.get(logical_router_id) and
|
||||
self.logical_router_nat_rules[logical_router_id].get(nat_rule_id)):
|
||||
del self.logical_router_nat_rules[logical_router_id][nat_rule_id]
|
||||
else:
|
||||
raise nsx_exc.ResourceNotFound(
|
||||
manager=FAKE_MANAGER, operation="delete_nat_rule")
|
||||
|
||||
def delete_nat_rule_by_values(self, logical_router_id, **kwargs):
|
||||
if self.logical_router_nat_rules.get(logical_router_id):
|
||||
nat_rules = self.logical_router_nat_rules[logical_router_id]
|
||||
remove_nat_rule_ids = []
|
||||
for nat_id, nat_body in nat_rules.items():
|
||||
remove_flag = True
|
||||
for k, v in kwargs.items():
|
||||
if nat_body[k] != v:
|
||||
remove_flag = False
|
||||
break
|
||||
if remove_flag:
|
||||
remove_nat_rule_ids.append(nat_id)
|
||||
for nat_id in remove_nat_rule_ids:
|
||||
del nat_rules[nat_id]
|
||||
else:
|
||||
raise nsx_exc.ResourceNotFound(
|
||||
manager=FAKE_MANAGER, operation="delete_nat_rule_by_values")
|
||||
|
||||
def update_logical_router_advertisement(self, logical_router_id, **kwargs):
|
||||
# TODO(berlin): implement this latter.
|
||||
pass
|
||||
|
|
|
@ -205,6 +205,14 @@ class L3NatTest(test_l3_plugin.L3BaseForIntTests, NsxPluginV3TestCase):
|
|||
self.v3_mock.update_logical_router_port)
|
||||
nsxlib.delete_logical_router_port = (
|
||||
self.v3_mock.delete_logical_router_port)
|
||||
nsxlib.add_nat_rule = self.v3_mock.add_nat_rule
|
||||
nsxlib.delete_nat_rule = self.v3_mock.delete_nat_rule
|
||||
nsxlib.delete_nat_rule_by_values = (
|
||||
self.v3_mock.delete_nat_rule_by_values)
|
||||
nsxlib.get_logical_router_ports_by_router_id = (
|
||||
self.v3_mock.get_logical_router_ports_by_router_id)
|
||||
nsxlib.update_logical_router_advertisement = (
|
||||
self.v3_mock.update_logical_router_advertisement)
|
||||
|
||||
def _create_l3_ext_network(
|
||||
self, physical_network=nsx_v3_mocks.DEFAULT_TIER0_ROUTER_UUID):
|
||||
|
|
Loading…
Reference in New Issue