Rename Router related methods for VMware NSX plugin

This is another step for the renaming/refactoring of
nvplib and related modules. This is about routers.

Partial-implements blueprint: nicira-plugin-renaming

Change-Id: Ic69b2777fa1ae3125b8adf23943360e3fe18e4c2
This commit is contained in:
armando-migliaccio 2014-01-15 17:18:54 -08:00
parent 06fafcb82b
commit 72c058f45a
13 changed files with 1829 additions and 1730 deletions

View File

@ -77,6 +77,7 @@ from neutron.plugins.nicira.extensions import maclearning as mac_ext
from neutron.plugins.nicira.extensions import nvp_networkgw as networkgw
from neutron.plugins.nicira.extensions import nvp_qos as ext_qos
from neutron.plugins.nicira.nsxlib import queue as queuelib
from neutron.plugins.nicira.nsxlib import router as routerlib
from neutron.plugins.nicira import NvpApiClient
from neutron.plugins.nicira import nvplib
@ -257,7 +258,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
port_data['fixed_ips'],
subnet_ids))
try:
lrouter_port = nvplib.create_router_lport(
lrouter_port = routerlib.create_router_lport(
cluster, nsx_router_id, port_data.get('tenant_id', 'fake'),
port_data.get('id', 'fake'), port_data.get('name', 'fake'),
port_data.get('admin_state_up', True), ip_addresses,
@ -314,7 +315,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
# Be safe and concede NAT rules might not exist.
# Therefore use min_num_expected=0
for cidr in cidrs:
nvplib.delete_nat_rules_by_match(
routerlib.delete_nat_rules_by_match(
self.cluster, nsx_router_id, "SourceNatRule",
max_num_expected=1, min_num_expected=0,
source_ip_addresses=cidr)
@ -324,7 +325,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
# Set the SNAT rule for each subnet (only first IP)
for cidr in cidrs:
cidr_prefix = int(cidr.split('/')[1])
nvplib.create_lrouter_snat_rule(
routerlib.create_lrouter_snat_rule(
self.cluster, nsx_router_id,
ip_addresses[0].split('/')[0],
ip_addresses[0].split('/')[0],
@ -333,34 +334,34 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
def _update_router_port_attachment(self, cluster, context,
nsx_router_id, port_data,
nvp_router_port_id,
nsx_router_port_id,
attachment_type,
attachment,
attachment_vlan=None):
if not nvp_router_port_id:
nvp_router_port_id = self._find_router_gw_port(context, port_data)
if not nsx_router_port_id:
nsx_router_port_id = self._find_router_gw_port(context, port_data)
try:
nvplib.plug_router_port_attachment(cluster, nsx_router_id,
nvp_router_port_id,
attachment,
attachment_type,
attachment_vlan)
routerlib.plug_router_port_attachment(cluster, nsx_router_id,
nsx_router_port_id,
attachment,
attachment_type,
attachment_vlan)
LOG.debug(_("Attached %(att)s to NVP router port %(port)s"),
{'att': attachment, 'port': nvp_router_port_id})
{'att': attachment, 'port': nsx_router_port_id})
except NvpApiClient.NvpApiException:
# Must remove NVP logical port
nvplib.delete_router_lport(cluster, nsx_router_id,
nvp_router_port_id)
routerlib.delete_router_lport(cluster, nsx_router_id,
nsx_router_port_id)
LOG.exception(_("Unable to plug attachment in NVP logical "
"router port %(r_port_id)s, associated with "
"Neutron %(q_port_id)s"),
{'r_port_id': nvp_router_port_id,
{'r_port_id': nsx_router_port_id,
'q_port_id': port_data.get('id')})
raise nvp_exc.NvpPluginException(
err_msg=(_("Unable to plug attachment in router port "
"%(r_port_id)s for neutron port id %(q_port_id)s "
"on router %(router_id)s") %
{'r_port_id': nvp_router_port_id,
{'r_port_id': nsx_router_port_id,
'q_port_id': port_data.get('id'),
'router_id': nsx_router_id}))
@ -525,9 +526,9 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
# Delete logical router port
nsx_router_id = nsx_utils.get_nsx_router_id(
context.session, self.cluster, port_data['device_id'])
nvp_switch_id, nvp_port_id = nsx_utils.get_nsx_switch_and_port_id(
nsx_switch_id, nsx_port_id = nsx_utils.get_nsx_switch_and_port_id(
context.session, self.cluster, port_data['id'])
if not nvp_port_id:
if not nsx_port_id:
LOG.warn(_("Neutron port %(port_id)s not found on NVP backend. "
"Terminating delete operation. A dangling router port "
"might have been left on router %(router_id)s"),
@ -535,17 +536,17 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
'router_id': nsx_router_id})
return
try:
nvplib.delete_peer_router_lport(self.cluster,
nsx_router_id,
nvp_switch_id,
nvp_port_id)
routerlib.delete_peer_router_lport(self.cluster,
nsx_router_id,
nsx_switch_id,
nsx_port_id)
except NvpApiClient.NvpApiException:
# Do not raise because the issue might as well be that the
# router has already been deleted, so there would be nothing
# to do here
LOG.exception(_("Ignoring exception as this means the peer "
"for port '%s' has already been deleted."),
nvp_port_id)
nsx_port_id)
# Delete logical switch port
self._nvp_delete_port(context, port_data)
@ -599,8 +600,8 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
port_data['network_id'])
nsx_router_id = nsx_utils.get_nsx_router_id(
context.session, self.cluster, router_id)
lr_port = nvplib.find_router_gw_port(context, self.cluster,
nsx_router_id)
lr_port = routerlib.find_router_gw_port(context, self.cluster,
nsx_router_id)
if not lr_port:
raise nvp_exc.NvpPluginException(
err_msg=(_("The gateway port for the NSX router %s "
@ -624,14 +625,14 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
# regardless of what the user specifies in neutron
nsx_router_id = nsx_utils.get_nsx_router_id(
context.session, self.cluster, port_data['device_id'])
nvplib.update_router_lport(self.cluster,
nsx_router_id,
lr_port['uuid'],
port_data['tenant_id'],
port_data['id'],
port_data['name'],
True,
ip_addresses)
routerlib.update_router_lport(self.cluster,
nsx_router_id,
lr_port['uuid'],
port_data['tenant_id'],
port_data['id'],
port_data['name'],
True,
ip_addresses)
ext_network = self.get_network(context, port_data['network_id'])
if ext_network.get(pnet.NETWORK_TYPE) == NetworkTypes.L3_EXT:
# Update attachment
@ -662,14 +663,14 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
router_id = port_data['device_id']
nsx_router_id = nsx_utils.get_nsx_router_id(
context.session, self.cluster, router_id)
nvplib.update_router_lport(self.cluster,
nsx_router_id,
lr_port['uuid'],
port_data['tenant_id'],
port_data['id'],
port_data['name'],
True,
['0.0.0.0/31'])
routerlib.update_router_lport(self.cluster,
nsx_router_id,
lr_port['uuid'],
port_data['tenant_id'],
port_data['id'],
port_data['name'],
True,
['0.0.0.0/31'])
# Reset attachment
self._update_router_port_attachment(
self.cluster, context, nsx_router_id, port_data,
@ -1036,7 +1037,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
'device_owner': ['network:router_interface']}
router_iface_ports = self.get_ports(context, filters=port_filter)
for port in router_iface_ports:
nvp_switch_id, nvp_port_id = nsx_utils.get_nsx_switch_and_port_id(
nsx_switch_id, nsx_port_id = nsx_utils.get_nsx_switch_and_port_id(
context.session, self.cluster, id)
# Before removing entry from Neutron DB, retrieve NSX switch
# identifiers for removing them from backend
@ -1047,13 +1048,13 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
# clean up network owned ports
for port in router_iface_ports:
try:
if nvp_port_id:
if nsx_port_id:
nsx_router_id = nsx_utils.get_nsx_router_id(
context.session, self.cluster, port['device_id'])
nvplib.delete_peer_router_lport(self.cluster,
nsx_router_id,
nvp_switch_id,
nvp_port_id)
routerlib.delete_peer_router_lport(self.cluster,
nsx_router_id,
nsx_switch_id,
nsx_port_id)
else:
LOG.warning(_("A nvp lport identifier was not found for "
"neutron port '%s'. Unable to remove "
@ -1068,7 +1069,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
# to do here
LOG.warning(_("Ignoring exception as this means the peer for "
"port '%s' has already been deleted."),
nvp_port_id)
nsx_port_id)
# Do not go to NVP for external networks
if not external:
@ -1395,7 +1396,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
tenant_id = self._get_tenant_id_for_create(context, router)
distributed = router.get('distributed')
try:
lrouter = nvplib.create_lrouter(
lrouter = routerlib.create_lrouter(
self.cluster, router['id'],
tenant_id, router['name'], nexthop,
distributed=attr.is_attr_set(distributed) and distributed)
@ -1424,7 +1425,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
'def_l3_gw_svc':
self.cluster.default_l3_gw_service_uuid})
# Try and remove logical router from NVP
nvplib.delete_lrouter(self.cluster, lrouter['uuid'])
routerlib.delete_lrouter(self.cluster, lrouter['uuid'])
# Return user a 500 with an apter message
raise nvp_exc.NvpPluginException(
err_msg=(_("Unable to create router %s on NSX backend") %
@ -1517,14 +1518,14 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
def _update_lrouter(self, context, router_id, name, nexthop, routes=None):
nsx_router_id = nsx_utils.get_nsx_router_id(
context.session, self.cluster, router_id)
return nvplib.update_lrouter(
return routerlib.update_lrouter(
self.cluster, nsx_router_id, name,
nexthop, routes=routes)
def _update_lrouter_routes(self, context, router_id, routes):
nsx_router_id = nsx_utils.get_nsx_router_id(
context.session, self.cluster, router_id)
nvplib.update_explicit_routes_lrouter(
routerlib.update_explicit_routes_lrouter(
self.cluster, nsx_router_id, routes)
def update_router(self, context, router_id, router):
@ -1591,7 +1592,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
def _delete_lrouter(self, context, router_id, nsx_router_id):
# The neutron router id (router_id) is ignored in this routine,
# but used in plugins deriving from this one
nvplib.delete_lrouter(self.cluster, nsx_router_id)
routerlib.delete_lrouter(self.cluster, nsx_router_id)
def delete_router(self, context, router_id):
with context.session.begin(subtransactions=True):
@ -1660,7 +1661,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
cidr_prefix = int(subnet['cidr'].split('/')[1])
nsx_router_id = nsx_utils.get_nsx_router_id(
context.session, self.cluster, router['id'])
nvplib.create_lrouter_snat_rule(
routerlib.create_lrouter_snat_rule(
self.cluster, nsx_router_id, snat_ip, snat_ip,
order=NVP_EXTGW_NAT_RULES_ORDER - cidr_prefix,
match_criteria={'source_ip_addresses': subnet['cidr']})
@ -1670,7 +1671,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
if router.gw_port:
nsx_router_id = nsx_utils.get_nsx_router_id(
context.session, self.cluster, router['id'])
nvplib.delete_nat_rules_by_match(
routerlib.delete_nat_rules_by_match(
self.cluster, nsx_router_id, "SourceNatRule",
max_num_expected=1, min_num_expected=1,
source_ip_addresses=subnet['cidr'])
@ -1701,7 +1702,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
# Fetch router from DB
router = self._get_router(context, router_id)
self._add_subnet_snat_rule(context, router, subnet)
nvplib.create_lrouter_nosnat_rule(
routerlib.create_lrouter_nosnat_rule(
self.cluster, nsx_router_id,
order=NVP_NOSNAT_RULES_ORDER,
match_criteria={'destination_ip_addresses': subnet['cidr']})
@ -1768,7 +1769,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
# do not exist in 2.x deployments
nsx_router_id = nsx_utils.get_nsx_router_id(
context.session, self.cluster, router_id)
nvplib.delete_nat_rules_by_match(
routerlib.delete_nat_rules_by_match(
self.cluster, nsx_router_id, "NoSourceNatRule",
max_num_expected=1, min_num_expected=0,
destination_ip_addresses=subnet['cidr'])
@ -1790,19 +1791,19 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
# but used by derived classes
try:
# Remove DNAT rule for the floating IP
nvplib.delete_nat_rules_by_match(
routerlib.delete_nat_rules_by_match(
self.cluster, nsx_router_id, "DestinationNatRule",
max_num_expected=1,
min_num_expected=min_num_rules_expected,
destination_ip_addresses=floating_ip_address)
# Remove SNAT rules for the floating IP
nvplib.delete_nat_rules_by_match(
routerlib.delete_nat_rules_by_match(
self.cluster, nsx_router_id, "SourceNatRule",
max_num_expected=1,
min_num_expected=min_num_rules_expected,
source_ip_addresses=internal_ip)
nvplib.delete_nat_rules_by_match(
routerlib.delete_nat_rules_by_match(
self.cluster, nsx_router_id, "SourceNatRule",
max_num_expected=1,
min_num_expected=min_num_rules_expected,
@ -1824,17 +1825,17 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
router_id = fip_db.router_id
nsx_router_id = nsx_utils.get_nsx_router_id(
context.session, self.cluster, router_id)
nvp_gw_port_id = nvplib.find_router_gw_port(
nsx_gw_port_id = routerlib.find_router_gw_port(
context, self.cluster, nsx_router_id)['uuid']
ext_neutron_port_db = self._get_port(context.elevated(),
fip_db.floating_port_id)
nvp_floating_ips = self._build_ip_address_list(
nsx_floating_ips = self._build_ip_address_list(
context.elevated(), ext_neutron_port_db['fixed_ips'])
nvplib.update_lrouter_port_ips(self.cluster,
nsx_router_id,
nvp_gw_port_id,
ips_to_add=[],
ips_to_remove=nvp_floating_ips)
routerlib.update_lrouter_port_ips(self.cluster,
nsx_router_id,
nsx_gw_port_id,
ips_to_add=[],
ips_to_remove=nsx_floating_ips)
def _get_fip_assoc_data(self, context, fip, floatingip_db):
if (('fixed_ip_address' in fip and fip['fixed_ip_address']) and
@ -1895,22 +1896,22 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
'port_id': floatingip_db.fixed_port_id,
'fixed_ip_address': floatingip_db.fixed_ip_address,
'tenant_id': floatingip_db.tenant_id})
nvp_gw_port_id = nvplib.find_router_gw_port(
nsx_gw_port_id = routerlib.find_router_gw_port(
context, self.cluster, nsx_old_router_id)['uuid']
self._retrieve_and_delete_nat_rules(
context, floating_ip, old_internal_ip, nsx_old_router_id)
nvplib.update_lrouter_port_ips(
self.cluster, nsx_old_router_id, nvp_gw_port_id,
routerlib.update_lrouter_port_ips(
self.cluster, nsx_old_router_id, nsx_gw_port_id,
ips_to_add=[], ips_to_remove=nvp_floating_ips)
if router_id:
nvp_gw_port_id = nvplib.find_router_gw_port(
nsx_gw_port_id = routerlib.find_router_gw_port(
context, self.cluster, nsx_router_id)['uuid']
# Re-create NAT rules only if a port id is specified
if fip.get('port_id'):
try:
# Setup DNAT rules for the floating IP
nvplib.create_lrouter_dnat_rule(
routerlib.create_lrouter_dnat_rule(
self.cluster, nsx_router_id, internal_ip,
order=NVP_FLOATINGIP_NAT_RULES_ORDER,
match_criteria={'destination_ip_addresses':
@ -1928,7 +1929,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
internal_subnet_cidr = self._build_ip_address_list(
context, internal_port['fixed_ips'],
subnet_ids=subnet_ids)[0]
nvplib.create_lrouter_snat_rule(
routerlib.create_lrouter_snat_rule(
self.cluster, nsx_router_id, floating_ip, floating_ip,
order=NVP_NOSNAT_RULES_ORDER - 1,
match_criteria={'source_ip_addresses':
@ -1937,17 +1938,15 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
internal_ip})
# setup snat rule such that src ip of a IP packet when
# using floating is the floating ip itself.
nvplib.create_lrouter_snat_rule(
routerlib.create_lrouter_snat_rule(
self.cluster, nsx_router_id, floating_ip, floating_ip,
order=NVP_FLOATINGIP_NAT_RULES_ORDER,
match_criteria={'source_ip_addresses': internal_ip})
# Add Floating IP address to router_port
nvplib.update_lrouter_port_ips(self.cluster,
nsx_router_id,
nvp_gw_port_id,
ips_to_add=nvp_floating_ips,
ips_to_remove=[])
routerlib.update_lrouter_port_ips(
self.cluster, nsx_router_id, nsx_gw_port_id,
ips_to_add=nvp_floating_ips, ips_to_remove=[])
except NvpApiClient.NvpApiException:
LOG.exception(_("An error occurred while creating NAT "
"rules on the NVP platform for floating "

View File

@ -36,6 +36,7 @@ from neutron.plugins.nicira.dbexts import vcns_db
from neutron.plugins.nicira.dbexts import vcns_models
from neutron.plugins.nicira.extensions import servicerouter as sr
from neutron.plugins.nicira import NeutronPlugin
from neutron.plugins.nicira.nsxlib import router as routerlib
from neutron.plugins.nicira import NvpApiClient
from neutron.plugins.nicira import nvplib
from neutron.plugins.nicira.vshield.common import (
@ -425,7 +426,7 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
neutron_port_id = ''
pname = name[:36] + '-lp'
admin_status_enabled = True
lr_port = nvplib.create_router_lport(
lr_port = routerlib.create_router_lport(
self.cluster, lrouter['uuid'], tenant_id,
neutron_port_id, pname, admin_status_enabled,
[vcns_const.INTEGRATION_LR_IPADDRESS])
@ -464,7 +465,7 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
msg = _("Unable to create integration logic switch "
"for router %s") % name
LOG.exception(msg)
nvplib.delete_lrouter(self.cluster, lrouter['uuid'])
routerlib.delete_lrouter(self.cluster, lrouter['uuid'])
raise q_exc.NeutronException(message=msg)
try:
@ -474,7 +475,7 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
msg = _("Unable to add router interface to integration lswitch "
"for router %s") % name
LOG.exception(msg)
nvplib.delete_lrouter(self.cluster, lrouter['uuid'])
routerlib.delete_lrouter(self.cluster, lrouter['uuid'])
raise q_exc.NeutronException(message=msg)
try:
@ -484,7 +485,7 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
msg = (_("Unable to create advance service router for %s") % name)
LOG.exception(msg)
self.vcns_driver.delete_lswitch(lswitch('uuid'))
nvplib.delete_lrouter(self.cluster, lrouter['uuid'])
routerlib.delete_lrouter(self.cluster, lrouter['uuid'])
raise q_exc.NeutronException(message=msg)
lrouter['status'] = service_constants.PENDING_CREATE
@ -516,7 +517,7 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
self.vcns_driver.delete_edge(router_id, edge_id, jobdata=jobdata)
# delete NSX logical router
nvplib.delete_lrouter(self.cluster, nsx_router_id)
routerlib.delete_lrouter(self.cluster, nsx_router_id)
if id in self._router_type:
del self._router_type[router_id]
@ -563,7 +564,7 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
def _get_nvp_lrouter_status(self, id):
try:
lrouter = nvplib.get_lrouter(self.cluster, id)
lrouter = routerlib.get_lrouter(self.cluster, id)
lr_status = lrouter["_relations"]["LogicalRouterStatus"]
if lr_status["fabric_status"]:
nvp_status = RouterStatus.ROUTER_STATUS_ACTIVE
@ -587,9 +588,9 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
def _get_all_nvp_lrouters_statuses(self, tenant_id, fields):
# get nvp lrouters status
nvp_lrouters = nvplib.get_lrouters(self.cluster,
tenant_id,
fields)
nvp_lrouters = routerlib.get_lrouters(self.cluster,
tenant_id,
fields)
nvp_status = {}
for nvp_lrouter in nvp_lrouters:

View File

@ -18,6 +18,7 @@
from neutron.openstack.common import log
from neutron.plugins.nicira.dbexts import nicira_db
from neutron.plugins.nicira import nsx_cluster
from neutron.plugins.nicira.nsxlib import router as routerlib
from neutron.plugins.nicira import NvpApiClient
from neutron.plugins.nicira import nvplib
@ -155,7 +156,7 @@ def get_nsx_router_id(session, cluster, neutron_router_id):
# Find logical router from backend.
# This is a rather expensive query, but it won't be executed
# more than once for each router in Neutron's lifetime
nsx_routers = nvplib.query_lrouters(
nsx_routers = routerlib.query_lrouters(
cluster, '*',
filters={'tag': neutron_router_id,
'tag_scope': 'q_router_id'})

View File

@ -27,6 +27,7 @@ from neutron.openstack.common import loopingcall
from neutron.openstack.common import timeutils
from neutron.plugins.nicira.common import exceptions as nvp_exc
from neutron.plugins.nicira.common import nsx_utils
from neutron.plugins.nicira.nsxlib import router as routerlib
from neutron.plugins.nicira import NvpApiClient
from neutron.plugins.nicira import nvplib
@ -191,7 +192,7 @@ class NvpSynchronizer():
nvplib.LSWITCH_RESOURCE, fields='uuid,tags,fabric_status',
relations='LogicalSwitchStatus')
LR_URI = nvplib._build_uri_path(
nvplib.LROUTER_RESOURCE, fields='uuid,tags,fabric_status',
routerlib.LROUTER_RESOURCE, fields='uuid,tags,fabric_status',
relations='LogicalRouterStatus')
LP_URI = nvplib._build_uri_path(
nvplib.LSWITCHPORT_RESOURCE,
@ -319,7 +320,7 @@ class NvpSynchronizer():
# This query will return the logical router status too
nsx_router_id = nsx_utils.get_nsx_router_id(
context.session, self._cluster, neutron_router_data['id'])
lrouter = nvplib.get_lrouter(
lrouter = routerlib.get_lrouter(
self._cluster, nsx_router_id)
except exceptions.NotFound:
# NOTE(salv-orlando): We should be catching

View File

@ -1,16 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 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.

View File

@ -0,0 +1,676 @@
# Copyright 2014 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.
from neutron.common import exceptions as exception
from neutron.openstack.common import excutils
from neutron.openstack.common import jsonutils
from neutron.openstack.common import log
from neutron.plugins.nicira.common import exceptions as nvp_exc
from neutron.plugins.nicira.common import utils
from neutron.plugins.nicira.nsxlib.versioning import DEFAULT_VERSION
from neutron.plugins.nicira.nsxlib.versioning import versioned
from neutron.plugins.nicira import NvpApiClient
from neutron.plugins.nicira.nvplib import _build_uri_path
from neutron.plugins.nicira.nvplib import do_request
from neutron.plugins.nicira.nvplib import get_all_query_pages
from neutron.plugins.nicira.nvplib import get_port
HTTP_GET = "GET"
HTTP_POST = "POST"
HTTP_DELETE = "DELETE"
HTTP_PUT = "PUT"
LROUTER_RESOURCE = "lrouter"
LROUTER_RESOURCE = "lrouter"
LROUTERPORT_RESOURCE = "lport/%s" % LROUTER_RESOURCE
LROUTERRIB_RESOURCE = "rib/%s" % LROUTER_RESOURCE
LROUTERNAT_RESOURCE = "nat/lrouter"
# Constants for NAT rules
MATCH_KEYS = ["destination_ip_addresses", "destination_port_max",
"destination_port_min", "source_ip_addresses",
"source_port_max", "source_port_min", "protocol"]
LOG = log.getLogger(__name__)
def _prepare_lrouter_body(name, neutron_router_id, tenant_id,
router_type, distributed=None, **kwargs):
body = {
"display_name": utils.check_and_truncate(name),
"tags": utils.get_tags(os_tid=tenant_id,
q_router_id=neutron_router_id),
"routing_config": {
"type": router_type
},
"type": "LogicalRouterConfig"
}
# add the distributed key only if not None (ie: True or False)
if distributed is not None:
body['distributed'] = distributed
if kwargs:
body["routing_config"].update(kwargs)
return body
def _create_implicit_routing_lrouter(cluster, neutron_router_id, tenant_id,
display_name, nexthop, distributed=None):
implicit_routing_config = {
"default_route_next_hop": {
"gateway_ip_address": nexthop,
"type": "RouterNextHop"
},
}
lrouter_obj = _prepare_lrouter_body(
display_name, neutron_router_id, tenant_id,
"SingleDefaultRouteImplicitRoutingConfig",
distributed=distributed,
**implicit_routing_config)
return do_request(HTTP_POST, _build_uri_path(LROUTER_RESOURCE),
jsonutils.dumps(lrouter_obj), cluster=cluster)
def create_implicit_routing_lrouter(cluster, neutron_router_id, tenant_id,
display_name, nexthop):
"""Create a NSX logical router on the specified cluster.
:param cluster: The target NSX cluster
:param tenant_id: Identifier of the Openstack tenant for which
the logical router is being created
:param display_name: Descriptive name of this logical router
:param nexthop: External gateway IP address for the logical router
:raise NvpApiException: if there is a problem while communicating
with the NSX controller
"""
return _create_implicit_routing_lrouter(
cluster, neutron_router_id, tenant_id, display_name, nexthop)
def create_implicit_routing_lrouter_with_distribution(
cluster, neutron_router_id, tenant_id, display_name,
nexthop, distributed=None):
"""Create a NSX logical router on the specified cluster.
This function also allows for creating distributed lrouters
:param cluster: The target NSX cluster
:param tenant_id: Identifier of the Openstack tenant for which
the logical router is being created
:param display_name: Descriptive name of this logical router
:param nexthop: External gateway IP address for the logical router
:param distributed: True for distributed logical routers
:raise NvpApiException: if there is a problem while communicating
with the NSX controller
"""
return _create_implicit_routing_lrouter(
cluster, neutron_router_id, tenant_id,
display_name, nexthop, distributed)
def create_explicit_routing_lrouter(cluster, neutron_router_id, tenant_id,
display_name, nexthop, distributed=None):
lrouter_obj = _prepare_lrouter_body(
display_name, neutron_router_id, tenant_id,
"RoutingTableRoutingConfig", distributed=distributed)
router = do_request(HTTP_POST, _build_uri_path(LROUTER_RESOURCE),
jsonutils.dumps(lrouter_obj), cluster=cluster)
default_gw = {'prefix': '0.0.0.0/0', 'next_hop_ip': nexthop}
create_explicit_route_lrouter(cluster, router['uuid'], default_gw)
return router
def delete_lrouter(cluster, lrouter_id):
do_request(HTTP_DELETE, _build_uri_path(LROUTER_RESOURCE,
resource_id=lrouter_id),
cluster=cluster)
def get_lrouter(cluster, lrouter_id):
return do_request(HTTP_GET,
_build_uri_path(LROUTER_RESOURCE,
resource_id=lrouter_id,
relations='LogicalRouterStatus'),
cluster=cluster)
def query_lrouters(cluster, fields=None, filters=None):
return get_all_query_pages(
_build_uri_path(LROUTER_RESOURCE,
fields=fields,
relations='LogicalRouterStatus',
filters=filters),
cluster)
def get_lrouters(cluster, tenant_id, fields=None, filters=None):
# FIXME(salv-orlando): Fields parameter is ignored in this routine
actual_filters = {}
if filters:
actual_filters.update(filters)
if tenant_id:
actual_filters['tag'] = tenant_id
actual_filters['tag_scope'] = 'os_tid'
lrouter_fields = "uuid,display_name,fabric_status,tags"
return query_lrouters(cluster, lrouter_fields, actual_filters)
def update_implicit_routing_lrouter(cluster, r_id, display_name, nexthop):
lrouter_obj = get_lrouter(cluster, r_id)
if not display_name and not nexthop:
# Nothing to update
return lrouter_obj
# It seems that this is faster than the doing an if on display_name
lrouter_obj["display_name"] = (utils.check_and_truncate(display_name) or
lrouter_obj["display_name"])
if nexthop:
nh_element = lrouter_obj["routing_config"].get(
"default_route_next_hop")
if nh_element:
nh_element["gateway_ip_address"] = nexthop
return do_request(HTTP_PUT, _build_uri_path(LROUTER_RESOURCE,
resource_id=r_id),
jsonutils.dumps(lrouter_obj),
cluster=cluster)
def get_explicit_routes_lrouter(cluster, router_id, protocol_type='static'):
static_filter = {'protocol': protocol_type}
existing_routes = do_request(
HTTP_GET,
_build_uri_path(LROUTERRIB_RESOURCE,
filters=static_filter,
fields="*",
parent_resource_id=router_id),
cluster=cluster)['results']
return existing_routes
def delete_explicit_route_lrouter(cluster, router_id, route_id):
do_request(HTTP_DELETE,
_build_uri_path(LROUTERRIB_RESOURCE,
resource_id=route_id,
parent_resource_id=router_id),
cluster=cluster)
def create_explicit_route_lrouter(cluster, router_id, route):
next_hop_ip = route.get("nexthop") or route.get("next_hop_ip")
prefix = route.get("destination") or route.get("prefix")
uuid = do_request(
HTTP_POST,
_build_uri_path(LROUTERRIB_RESOURCE,
parent_resource_id=router_id),
jsonutils.dumps({
"action": "accept",
"next_hop_ip": next_hop_ip,
"prefix": prefix,
"protocol": "static"
}),
cluster=cluster)['uuid']
return uuid
def update_explicit_routes_lrouter(cluster, router_id, routes):
# Update in bulk: delete them all, and add the ones specified
# but keep track of what is been modified to allow roll-backs
# in case of failures
nsx_routes = get_explicit_routes_lrouter(cluster, router_id)
try:
deleted_routes = []
added_routes = []
# omit the default route (0.0.0.0/0) from the processing;
# this must be handled through the nexthop for the router
for route in nsx_routes:
prefix = route.get("destination") or route.get("prefix")
if prefix != '0.0.0.0/0':
delete_explicit_route_lrouter(cluster,
router_id,
route['uuid'])
deleted_routes.append(route)
for route in routes:
prefix = route.get("destination") or route.get("prefix")
if prefix != '0.0.0.0/0':
uuid = create_explicit_route_lrouter(cluster,
router_id, route)
added_routes.append(uuid)
except NvpApiClient.NvpApiException:
LOG.exception(_('Cannot update NSX routes %(routes)s for '
'router %(router_id)s'),
{'routes': routes, 'router_id': router_id})
# Roll back to keep NSX in consistent state
with excutils.save_and_reraise_exception():
if nsx_routes:
if deleted_routes:
for route in deleted_routes:
create_explicit_route_lrouter(cluster,
router_id, route)
if added_routes:
for route_id in added_routes:
delete_explicit_route_lrouter(cluster,
router_id, route_id)
return nsx_routes
def get_default_route_explicit_routing_lrouter_v33(cluster, router_id):
static_filter = {"protocol": "static",
"prefix": "0.0.0.0/0"}
default_route = do_request(
HTTP_GET,
_build_uri_path(LROUTERRIB_RESOURCE,
filters=static_filter,
fields="*",
parent_resource_id=router_id),
cluster=cluster)["results"][0]
return default_route
def get_default_route_explicit_routing_lrouter_v32(cluster, router_id):
# Scan all routes because 3.2 does not support query by prefix
all_routes = get_explicit_routes_lrouter(cluster, router_id)
for route in all_routes:
if route['prefix'] == '0.0.0.0/0':
return route
def update_default_gw_explicit_routing_lrouter(cluster, router_id, next_hop):
default_route = get_default_route_explicit_routing_lrouter(cluster,
router_id)
if next_hop != default_route["next_hop_ip"]:
new_default_route = {"action": "accept",
"next_hop_ip": next_hop,
"prefix": "0.0.0.0/0",
"protocol": "static"}
do_request(HTTP_PUT,
_build_uri_path(LROUTERRIB_RESOURCE,
resource_id=default_route['uuid'],
parent_resource_id=router_id),
jsonutils.dumps(new_default_route),
cluster=cluster)
def update_explicit_routing_lrouter(cluster, router_id,
display_name, next_hop, routes=None):
update_implicit_routing_lrouter(cluster, router_id, display_name, next_hop)
if next_hop:
update_default_gw_explicit_routing_lrouter(cluster,
router_id, next_hop)
if routes is not None:
return update_explicit_routes_lrouter(cluster, router_id, routes)
def query_lrouter_lports(cluster, lr_uuid, fields="*",
filters=None, relations=None):
uri = _build_uri_path(LROUTERPORT_RESOURCE, parent_resource_id=lr_uuid,
fields=fields, filters=filters, relations=relations)
return do_request(HTTP_GET, uri, cluster=cluster)['results']
def create_router_lport(cluster, lrouter_uuid, tenant_id, neutron_port_id,
display_name, admin_status_enabled, ip_addresses,
mac_address=None):
"""Creates a logical port on the assigned logical router."""
lport_obj = dict(
admin_status_enabled=admin_status_enabled,
display_name=display_name,
tags=utils.get_tags(os_tid=tenant_id, q_port_id=neutron_port_id),
ip_addresses=ip_addresses,
type="LogicalRouterPortConfig"
)
# Only add the mac_address to lport_obj if present. This is because
# when creating the fake_ext_gw there is no mac_address present.
if mac_address:
lport_obj['mac_address'] = mac_address
path = _build_uri_path(LROUTERPORT_RESOURCE,
parent_resource_id=lrouter_uuid)
result = do_request(HTTP_POST, path, jsonutils.dumps(lport_obj),
cluster=cluster)
LOG.debug(_("Created logical port %(lport_uuid)s on "
"logical router %(lrouter_uuid)s"),
{'lport_uuid': result['uuid'],
'lrouter_uuid': lrouter_uuid})
return result
def update_router_lport(cluster, lrouter_uuid, lrouter_port_uuid,
tenant_id, neutron_port_id, display_name,
admin_status_enabled, ip_addresses):
"""Updates a logical port on the assigned logical router."""
lport_obj = dict(
admin_status_enabled=admin_status_enabled,
display_name=display_name,
tags=utils.get_tags(os_tid=tenant_id, q_port_id=neutron_port_id),
ip_addresses=ip_addresses,
type="LogicalRouterPortConfig"
)
# Do not pass null items to NSX
for key in lport_obj.keys():
if lport_obj[key] is None:
del lport_obj[key]
path = _build_uri_path(LROUTERPORT_RESOURCE,
lrouter_port_uuid,
parent_resource_id=lrouter_uuid)
result = do_request(HTTP_PUT, path,
jsonutils.dumps(lport_obj),
cluster=cluster)
LOG.debug(_("Updated logical port %(lport_uuid)s on "
"logical router %(lrouter_uuid)s"),
{'lport_uuid': lrouter_port_uuid, 'lrouter_uuid': lrouter_uuid})
return result
def delete_router_lport(cluster, lrouter_uuid, lport_uuid):
"""Creates a logical port on the assigned logical router."""
path = _build_uri_path(LROUTERPORT_RESOURCE, lport_uuid, lrouter_uuid)
do_request(HTTP_DELETE, path, cluster=cluster)
LOG.debug(_("Delete logical router port %(lport_uuid)s on "
"logical router %(lrouter_uuid)s"),
{'lport_uuid': lport_uuid,
'lrouter_uuid': lrouter_uuid})
def delete_peer_router_lport(cluster, lr_uuid, ls_uuid, lp_uuid):
nsx_port = get_port(cluster, ls_uuid, lp_uuid,
relations="LogicalPortAttachment")
relations = nsx_port.get('_relations')
if relations:
att_data = relations.get('LogicalPortAttachment')
if att_data:
lrp_uuid = att_data.get('peer_port_uuid')
if lrp_uuid:
delete_router_lport(cluster, lr_uuid, lrp_uuid)
def find_router_gw_port(context, cluster, router_id):
"""Retrieves the external gateway port for a NSX logical router."""
# Find the uuid of nsx ext gw logical router port
# TODO(salvatore-orlando): Consider storing it in Neutron DB
results = query_lrouter_lports(
cluster, router_id,
relations="LogicalPortAttachment")
for lport in results:
if '_relations' in lport:
attachment = lport['_relations'].get('LogicalPortAttachment')
if attachment and attachment.get('type') == 'L3GatewayAttachment':
return lport
def plug_router_port_attachment(cluster, router_id, port_id,
attachment_uuid, nsx_attachment_type,
attachment_vlan=None):
"""Attach a router port to the given attachment.
Current attachment types:
- PatchAttachment [-> logical switch port uuid]
- L3GatewayAttachment [-> L3GatewayService uuid]
For the latter attachment type a VLAN ID can be specified as well.
"""
uri = _build_uri_path(LROUTERPORT_RESOURCE, port_id, router_id,
is_attachment=True)
attach_obj = {}
attach_obj["type"] = nsx_attachment_type
if nsx_attachment_type == "PatchAttachment":
attach_obj["peer_port_uuid"] = attachment_uuid
elif nsx_attachment_type == "L3GatewayAttachment":
attach_obj["l3_gateway_service_uuid"] = attachment_uuid
if attachment_vlan:
attach_obj['vlan_id'] = attachment_vlan
else:
raise nvp_exc.NvpInvalidAttachmentType(
attachment_type=nsx_attachment_type)
return do_request(
HTTP_PUT, uri, jsonutils.dumps(attach_obj), cluster=cluster)
def _create_nat_match_obj(**kwargs):
nat_match_obj = {'ethertype': 'IPv4'}
delta = set(kwargs.keys()) - set(MATCH_KEYS)
if delta:
raise Exception(_("Invalid keys for NAT match: %s"), delta)
nat_match_obj.update(kwargs)
return nat_match_obj
def _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj):
LOG.debug(_("Creating NAT rule: %s"), nat_rule_obj)
uri = _build_uri_path(LROUTERNAT_RESOURCE, parent_resource_id=router_id)
return do_request(HTTP_POST, uri, jsonutils.dumps(nat_rule_obj),
cluster=cluster)
def _build_snat_rule_obj(min_src_ip, max_src_ip, nat_match_obj):
return {"to_source_ip_address_min": min_src_ip,
"to_source_ip_address_max": max_src_ip,
"type": "SourceNatRule",
"match": nat_match_obj}
def create_lrouter_nosnat_rule_v2(cluster, _router_id, _match_criteria=None):
LOG.info(_("No SNAT rules cannot be applied as they are not available in "
"this version of the NSX platform"))
def create_lrouter_nodnat_rule_v2(cluster, _router_id, _match_criteria=None):
LOG.info(_("No DNAT rules cannot be applied as they are not available in "
"this version of the NSX platform"))
def create_lrouter_snat_rule_v2(cluster, router_id,
min_src_ip, max_src_ip, match_criteria=None):
nat_match_obj = _create_nat_match_obj(**match_criteria)
nat_rule_obj = _build_snat_rule_obj(min_src_ip, max_src_ip, nat_match_obj)
return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
def create_lrouter_dnat_rule_v2(cluster, router_id, dst_ip,
to_dst_port=None, match_criteria=None):
nat_match_obj = _create_nat_match_obj(**match_criteria)
nat_rule_obj = {
"to_destination_ip_address_min": dst_ip,
"to_destination_ip_address_max": dst_ip,
"type": "DestinationNatRule",
"match": nat_match_obj
}
if to_dst_port:
nat_rule_obj['to_destination_port'] = to_dst_port
return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
def create_lrouter_nosnat_rule_v3(cluster, router_id, order=None,
match_criteria=None):
nat_match_obj = _create_nat_match_obj(**match_criteria)
nat_rule_obj = {
"type": "NoSourceNatRule",
"match": nat_match_obj
}
if order:
nat_rule_obj['order'] = order
return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
def create_lrouter_nodnat_rule_v3(cluster, router_id, order=None,
match_criteria=None):
nat_match_obj = _create_nat_match_obj(**match_criteria)
nat_rule_obj = {
"type": "NoDestinationNatRule",
"match": nat_match_obj
}
if order:
nat_rule_obj['order'] = order
return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
def create_lrouter_snat_rule_v3(cluster, router_id, min_src_ip, max_src_ip,
order=None, match_criteria=None):
nat_match_obj = _create_nat_match_obj(**match_criteria)
nat_rule_obj = _build_snat_rule_obj(min_src_ip, max_src_ip, nat_match_obj)
if order:
nat_rule_obj['order'] = order
return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
def create_lrouter_dnat_rule_v3(cluster, router_id, dst_ip, to_dst_port=None,
order=None, match_criteria=None):
nat_match_obj = _create_nat_match_obj(**match_criteria)
nat_rule_obj = {
"to_destination_ip_address": dst_ip,
"type": "DestinationNatRule",
"match": nat_match_obj
}
if to_dst_port:
nat_rule_obj['to_destination_port'] = to_dst_port
if order:
nat_rule_obj['order'] = order
return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
def delete_nat_rules_by_match(cluster, router_id, rule_type,
max_num_expected,
min_num_expected=0,
**kwargs):
# remove nat rules
nat_rules = query_nat_rules(cluster, router_id)
to_delete_ids = []
for r in nat_rules:
if (r['type'] != rule_type):
continue
for key, value in kwargs.iteritems():
if not (key in r['match'] and r['match'][key] == value):
break
else:
to_delete_ids.append(r['uuid'])
if not (len(to_delete_ids) in
range(min_num_expected, max_num_expected + 1)):
raise nvp_exc.NvpNatRuleMismatch(actual_rules=len(to_delete_ids),
min_rules=min_num_expected,
max_rules=max_num_expected)
for rule_id in to_delete_ids:
delete_router_nat_rule(cluster, router_id, rule_id)
def delete_router_nat_rule(cluster, router_id, rule_id):
uri = _build_uri_path(LROUTERNAT_RESOURCE, rule_id, router_id)
do_request(HTTP_DELETE, uri, cluster=cluster)
def query_nat_rules(cluster, router_id, fields="*", filters=None):
uri = _build_uri_path(LROUTERNAT_RESOURCE, parent_resource_id=router_id,
fields=fields, filters=filters)
return get_all_query_pages(uri, cluster)
# NOTE(salvatore-orlando): The following FIXME applies in general to
# each operation on list attributes.
# FIXME(salvatore-orlando): need a lock around the list of IPs on an iface
def update_lrouter_port_ips(cluster, lrouter_id, lport_id,
ips_to_add, ips_to_remove):
uri = _build_uri_path(LROUTERPORT_RESOURCE, lport_id, lrouter_id)
try:
port = do_request(HTTP_GET, uri, cluster=cluster)
# TODO(salvatore-orlando): Enforce ips_to_add intersection with
# ips_to_remove is empty
ip_address_set = set(port['ip_addresses'])
ip_address_set = ip_address_set - set(ips_to_remove)
ip_address_set = ip_address_set | set(ips_to_add)
# Set is not JSON serializable - convert to list
port['ip_addresses'] = list(ip_address_set)
do_request(HTTP_PUT, uri, jsonutils.dumps(port), cluster=cluster)
except exception.NotFound as e:
# FIXME(salv-orlando):avoid raising different exception
data = {'lport_id': lport_id, 'lrouter_id': lrouter_id}
msg = (_("Router Port %(lport_id)s not found on router "
"%(lrouter_id)s") % data)
LOG.exception(msg)
raise nvp_exc.NvpPluginException(err_msg=msg)
except NvpApiClient.NvpApiException as e:
msg = _("An exception occurred while updating IP addresses on a "
"router logical port:%s") % str(e)
LOG.exception(msg)
raise nvp_exc.NvpPluginException(err_msg=msg)
ROUTER_FUNC_DICT = {
'create_lrouter': {
2: {DEFAULT_VERSION: create_implicit_routing_lrouter, },
3: {DEFAULT_VERSION: create_implicit_routing_lrouter,
1: create_implicit_routing_lrouter_with_distribution,
2: create_explicit_routing_lrouter, }, },
'update_lrouter': {
2: {DEFAULT_VERSION: update_implicit_routing_lrouter, },
3: {DEFAULT_VERSION: update_implicit_routing_lrouter,
2: update_explicit_routing_lrouter, }, },
'create_lrouter_dnat_rule': {
2: {DEFAULT_VERSION: create_lrouter_dnat_rule_v2, },
3: {DEFAULT_VERSION: create_lrouter_dnat_rule_v3, }, },
'create_lrouter_snat_rule': {
2: {DEFAULT_VERSION: create_lrouter_snat_rule_v2, },
3: {DEFAULT_VERSION: create_lrouter_snat_rule_v3, }, },
'create_lrouter_nosnat_rule': {
2: {DEFAULT_VERSION: create_lrouter_nosnat_rule_v2, },
3: {DEFAULT_VERSION: create_lrouter_nosnat_rule_v3, }, },
'create_lrouter_nodnat_rule': {
2: {DEFAULT_VERSION: create_lrouter_nodnat_rule_v2, },
3: {DEFAULT_VERSION: create_lrouter_nodnat_rule_v3, }, },
'get_default_route_explicit_routing_lrouter': {
3: {DEFAULT_VERSION: get_default_route_explicit_routing_lrouter_v32,
2: get_default_route_explicit_routing_lrouter_v32, }, },
}
@versioned(ROUTER_FUNC_DICT)
def create_lrouter(cluster, *args, **kwargs):
if kwargs.get('distributed', None):
v = cluster.api_client.get_nvp_version()
if (v.major, v.minor) < (3, 1):
raise nvp_exc.NvpInvalidVersion(version=v)
return v
@versioned(ROUTER_FUNC_DICT)
def get_default_route_explicit_routing_lrouter(cluster, *args, **kwargs):
pass
@versioned(ROUTER_FUNC_DICT)
def update_lrouter(cluster, *args, **kwargs):
if kwargs.get('routes', None):
v = cluster.api_client.get_nvp_version()
if (v.major, v.minor) < (3, 2):
raise nvp_exc.NvpInvalidVersion(version=v)
return v
@versioned(ROUTER_FUNC_DICT)
def create_lrouter_dnat_rule(cluster, *args, **kwargs):
pass
@versioned(ROUTER_FUNC_DICT)
def create_lrouter_snat_rule(cluster, *args, **kwargs):
pass
@versioned(ROUTER_FUNC_DICT)
def create_lrouter_nosnat_rule(cluster, *args, **kwargs):
pass
@versioned(ROUTER_FUNC_DICT)
def create_lrouter_nodnat_rule(cluster, *args, **kwargs):
pass

View File

@ -0,0 +1,66 @@
# Copyright 2014 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.
import inspect
from neutron.plugins.nicira import NvpApiClient
DEFAULT_VERSION = -1
def versioned(func_table):
def versioned_function(wrapped_func):
func_name = wrapped_func.__name__
def dispatch_versioned_function(cluster, *args, **kwargs):
# Call the wrapper function, in case we need to
# run validation checks regarding versions. It
# should return the NVP version
v = (wrapped_func(cluster, *args, **kwargs) or
cluster.api_client.get_nvp_version())
func = get_function_by_version(func_table, func_name, v)
func_kwargs = kwargs
arg_spec = inspect.getargspec(func)
if not arg_spec.keywords and not arg_spec.varargs:
# drop args unknown to function from func_args
arg_set = set(func_kwargs.keys())
for arg in arg_set - set(arg_spec.args):
del func_kwargs[arg]
# NOTE(salvatore-orlando): shall we fail here if a required
# argument is not passed, or let the called function raise?
return func(cluster, *args, **func_kwargs)
return dispatch_versioned_function
return versioned_function
def get_function_by_version(func_table, func_name, ver):
if ver:
if ver.major not in func_table[func_name]:
major = max(func_table[func_name].keys())
minor = max(func_table[func_name][major].keys())
if major > ver.major:
raise NotImplementedError(_("Operation may not be supported"))
else:
major = ver.major
minor = ver.minor
if ver.minor not in func_table[func_name][major]:
minor = DEFAULT_VERSION
return func_table[func_name][major][minor]
else:
msg = _('NSX version is not set. Unable to complete request '
'correctly. Check log for NSX communication errors.')
raise NvpApiClient.ServiceUnavailable(message=msg)

View File

@ -21,14 +21,12 @@
import hashlib
import inspect
import json
#FIXME(danwent): I'd like this file to get to the point where it has
# no neutron-specific logic in it
from neutron.common import constants
from neutron.common import exceptions as exception
from neutron.openstack.common import excutils
from neutron.openstack.common import log
from neutron.plugins.nicira.common import exceptions as nvp_exc
from neutron.plugins.nicira.common import utils
@ -47,23 +45,10 @@ URI_PREFIX = "/ws.v1"
# Resources exposed by NVP API
LSWITCH_RESOURCE = "lswitch"
LSWITCHPORT_RESOURCE = "lport/%s" % LSWITCH_RESOURCE
LROUTER_RESOURCE = "lrouter"
LROUTERPORT_RESOURCE = "lport/%s" % LROUTER_RESOURCE
LROUTERRIB_RESOURCE = "rib/%s" % LROUTER_RESOURCE
LROUTERNAT_RESOURCE = "nat/lrouter"
LQUEUE_RESOURCE = "lqueue"
GWSERVICE_RESOURCE = "gateway-service"
# Current neutron version
NEUTRON_VERSION = version_info.release_string()
# Constants for NAT rules
MATCH_KEYS = ["destination_ip_addresses", "destination_port_max",
"destination_port_min", "source_ip_addresses",
"source_port_max", "source_port_min", "protocol"]
SNAT_KEYS = ["to_src_port_min", "to_src_port_max", "to_src_ip_min",
"to_src_ip_max"]
DNAT_KEYS = ["to_dst_port", "to_dst_ip_min", "to_dst_ip_max"]
# Maximum page size for a single request
# NOTE(salv-orlando): This might become a version-dependent map should the
# limit be raised in future versions
@ -91,30 +76,6 @@ def device_id_to_vm_id(device_id, obfuscate=False):
return device_id
def version_dependent(wrapped_func):
func_name = wrapped_func.__name__
def dispatch_version_dependent_function(cluster, *args, **kwargs):
# Call the wrapper function, in case we need to
# run validation checks regarding versions. It
# should return the NVP version
v = (wrapped_func(cluster, *args, **kwargs) or
cluster.api_client.get_nvp_version())
func = get_function_by_version(func_name, v)
func_kwargs = kwargs
arg_spec = inspect.getargspec(func)
if not arg_spec.keywords and not arg_spec.varargs:
# drop args unknown to function from func_args
arg_set = set(func_kwargs.keys())
for arg in arg_set - set(arg_spec.args):
del func_kwargs[arg]
# NOTE(salvatore-orlando): shall we fail here if a required
# argument is not passed, or let the called function raise?
return func(cluster, *args, **func_kwargs)
return dispatch_version_dependent_function
def _build_uri_path(resource,
resource_id=None,
parent_resource_id=None,
@ -317,122 +278,12 @@ def create_l2_gw_service(cluster, tenant_id, display_name, devices):
json.dumps(gwservice_obj), cluster=cluster)
def _prepare_lrouter_body(name, neutron_router_id, tenant_id, router_type,
distributed=None, **kwargs):
body = {
"display_name": utils.check_and_truncate(name),
"tags": [{"tag": tenant_id, "scope": "os_tid"},
{"tag": neutron_router_id, "scope": "q_router_id"},
{"tag": NEUTRON_VERSION, "scope": "quantum"}],
"routing_config": {
"type": router_type
},
"type": "LogicalRouterConfig"
}
# add the distributed key only if not None (ie: True or False)
if distributed is not None:
body['distributed'] = distributed
if kwargs:
body["routing_config"].update(kwargs)
return body
def _create_implicit_routing_lrouter(cluster, neutron_router_id, tenant_id,
display_name, nexthop, distributed=None):
implicit_routing_config = {
"default_route_next_hop": {
"gateway_ip_address": nexthop,
"type": "RouterNextHop"
},
}
lrouter_obj = _prepare_lrouter_body(
display_name, neutron_router_id, tenant_id,
"SingleDefaultRouteImplicitRoutingConfig",
distributed=distributed,
**implicit_routing_config)
return do_request(HTTP_POST, _build_uri_path(LROUTER_RESOURCE),
json.dumps(lrouter_obj), cluster=cluster)
def create_implicit_routing_lrouter(cluster, neutron_router_id, tenant_id,
display_name, nexthop):
"""Create a NVP logical router on the specified cluster.
:param cluster: The target NVP cluster
:param tenant_id: Identifier of the Openstack tenant for which
the logical router is being created
:param display_name: Descriptive name of this logical router
:param nexthop: External gateway IP address for the logical router
:raise NvpApiException: if there is a problem while communicating
with the NVP controller
"""
return _create_implicit_routing_lrouter(
cluster, neutron_router_id, tenant_id, display_name, nexthop)
def create_implicit_routing_lrouter_with_distribution(
cluster, neutron_router_id, tenant_id,
display_name, nexthop, distributed=None):
"""Create a NVP logical router on the specified cluster.
This function also allows for creating distributed lrouters
:param cluster: The target NVP cluster
:param tenant_id: Identifier of the Openstack tenant for which
the logical router is being created
:param display_name: Descriptive name of this logical router
:param nexthop: External gateway IP address for the logical router
:param distributed: True for distributed logical routers
:raise NvpApiException: if there is a problem while communicating
with the NVP controller
"""
return _create_implicit_routing_lrouter(
cluster, neutron_router_id, tenant_id,
display_name, nexthop, distributed)
def create_explicit_routing_lrouter(cluster, neutron_router_id, tenant_id,
display_name, nexthop,
distributed=None):
lrouter_obj = _prepare_lrouter_body(
display_name, neutron_router_id,
tenant_id, "RoutingTableRoutingConfig",
distributed=distributed)
router = do_request(HTTP_POST, _build_uri_path(LROUTER_RESOURCE),
json.dumps(lrouter_obj), cluster=cluster)
default_gw = {'prefix': '0.0.0.0/0', 'next_hop_ip': nexthop}
create_explicit_route_lrouter(cluster, router['uuid'], default_gw)
return router
@version_dependent
def create_lrouter(cluster, *args, **kwargs):
if kwargs.get('distributed', None):
v = cluster.api_client.get_nvp_version()
if (v.major, v.minor) < (3, 1):
raise nvp_exc.NvpInvalidVersion(version=v)
return v
def delete_lrouter(cluster, lrouter_id):
do_request(HTTP_DELETE, _build_uri_path(LROUTER_RESOURCE,
resource_id=lrouter_id),
cluster=cluster)
def delete_l2_gw_service(cluster, gateway_id):
do_request("DELETE", _build_uri_path(GWSERVICE_RESOURCE,
resource_id=gateway_id),
cluster=cluster)
def get_lrouter(cluster, lrouter_id):
return do_request(HTTP_GET,
_build_uri_path(LROUTER_RESOURCE,
resource_id=lrouter_id,
relations='LogicalRouterStatus'),
cluster=cluster)
def get_l2_gw_service(cluster, gateway_id):
return do_request(
"GET", _build_uri_path(GWSERVICE_RESOURCE,
@ -440,27 +291,6 @@ def get_l2_gw_service(cluster, gateway_id):
cluster=cluster)
def query_lrouters(cluster, fields=None, filters=None):
return get_all_query_pages(
_build_uri_path(LROUTER_RESOURCE,
fields=fields,
relations='LogicalRouterStatus',
filters=filters),
cluster)
def get_lrouters(cluster, tenant_id, fields=None, filters=None):
# FIXME(salv-orlando): Fields parameter is ignored in this routine
actual_filters = {}
if filters:
actual_filters.update(filters)
if tenant_id:
actual_filters['tag'] = tenant_id
actual_filters['tag_scope'] = 'os_tid'
lrouter_fields = "uuid,display_name,fabric_status,tags"
return query_lrouters(cluster, lrouter_fields, actual_filters)
def get_l2_gw_services(cluster, tenant_id=None,
fields=None, filters=None):
actual_filters = dict(filters or {})
@ -485,164 +315,6 @@ def update_l2_gw_service(cluster, gateway_id, display_name):
json.dumps(gwservice_obj), cluster=cluster)
def update_implicit_routing_lrouter(cluster, r_id, display_name, nexthop):
lrouter_obj = get_lrouter(cluster, r_id)
if not display_name and not nexthop:
# Nothing to update
return lrouter_obj
# It seems that this is faster than the doing an if on display_name
lrouter_obj["display_name"] = (utils.check_and_truncate(display_name) or
lrouter_obj["display_name"])
if nexthop:
nh_element = lrouter_obj["routing_config"].get(
"default_route_next_hop")
if nh_element:
nh_element["gateway_ip_address"] = nexthop
return do_request(HTTP_PUT, _build_uri_path(LROUTER_RESOURCE,
resource_id=r_id),
json.dumps(lrouter_obj),
cluster=cluster)
def get_explicit_routes_lrouter(cluster, router_id, protocol_type='static'):
static_filter = {'protocol': protocol_type}
existing_routes = do_request(
HTTP_GET,
_build_uri_path(LROUTERRIB_RESOURCE,
filters=static_filter,
fields="*",
parent_resource_id=router_id),
cluster=cluster)['results']
return existing_routes
def delete_explicit_route_lrouter(cluster, router_id, route_id):
do_request(HTTP_DELETE,
_build_uri_path(LROUTERRIB_RESOURCE,
resource_id=route_id,
parent_resource_id=router_id),
cluster=cluster)
def create_explicit_route_lrouter(cluster, router_id, route):
next_hop_ip = route.get("nexthop") or route.get("next_hop_ip")
prefix = route.get("destination") or route.get("prefix")
uuid = do_request(
HTTP_POST,
_build_uri_path(LROUTERRIB_RESOURCE,
parent_resource_id=router_id),
json.dumps({
"action": "accept",
"next_hop_ip": next_hop_ip,
"prefix": prefix,
"protocol": "static"
}),
cluster=cluster)['uuid']
return uuid
def update_explicit_routes_lrouter(cluster, router_id, routes):
# Update in bulk: delete them all, and add the ones specified
# but keep track of what is been modified to allow roll-backs
# in case of failures
nvp_routes = get_explicit_routes_lrouter(cluster, router_id)
try:
deleted_routes = []
added_routes = []
# omit the default route (0.0.0.0/0) from the processing;
# this must be handled through the nexthop for the router
for route in nvp_routes:
prefix = route.get("destination") or route.get("prefix")
if prefix != '0.0.0.0/0':
delete_explicit_route_lrouter(cluster,
router_id,
route['uuid'])
deleted_routes.append(route)
for route in routes:
prefix = route.get("destination") or route.get("prefix")
if prefix != '0.0.0.0/0':
uuid = create_explicit_route_lrouter(cluster,
router_id, route)
added_routes.append(uuid)
except NvpApiClient.NvpApiException:
LOG.exception(_('Cannot update NVP routes %(routes)s for '
'router %(router_id)s'),
{'routes': routes, 'router_id': router_id})
# Roll back to keep NVP in consistent state
with excutils.save_and_reraise_exception():
if nvp_routes:
if deleted_routes:
for route in deleted_routes:
create_explicit_route_lrouter(cluster,
router_id, route)
if added_routes:
for route_id in added_routes:
delete_explicit_route_lrouter(cluster,
router_id, route_id)
return nvp_routes
@version_dependent
def get_default_route_explicit_routing_lrouter(cluster, *args, **kwargs):
pass
def get_default_route_explicit_routing_lrouter_v33(cluster, router_id):
static_filter = {"protocol": "static",
"prefix": "0.0.0.0/0"}
default_route = do_request(
HTTP_GET,
_build_uri_path(LROUTERRIB_RESOURCE,
filters=static_filter,
fields="*",
parent_resource_id=router_id),
cluster=cluster)["results"][0]
return default_route
def get_default_route_explicit_routing_lrouter_v32(cluster, router_id):
# Scan all routes because 3.2 does not support query by prefix
all_routes = get_explicit_routes_lrouter(cluster, router_id)
for route in all_routes:
if route['prefix'] == '0.0.0.0/0':
return route
def update_default_gw_explicit_routing_lrouter(cluster, router_id, next_hop):
default_route = get_default_route_explicit_routing_lrouter(cluster,
router_id)
if next_hop != default_route["next_hop_ip"]:
new_default_route = {"action": "accept",
"next_hop_ip": next_hop,
"prefix": "0.0.0.0/0",
"protocol": "static"}
do_request(HTTP_PUT,
_build_uri_path(LROUTERRIB_RESOURCE,
resource_id=default_route['uuid'],
parent_resource_id=router_id),
json.dumps(new_default_route),
cluster=cluster)
def update_explicit_routing_lrouter(cluster, router_id,
display_name, next_hop, routes=None):
update_implicit_routing_lrouter(cluster, router_id, display_name, next_hop)
if next_hop:
update_default_gw_explicit_routing_lrouter(cluster,
router_id, next_hop)
if routes is not None:
return update_explicit_routes_lrouter(cluster, router_id, routes)
@version_dependent
def update_lrouter(cluster, *args, **kwargs):
if kwargs.get('routes', None):
v = cluster.api_client.get_nvp_version()
if (v.major, v.minor) < (3, 2):
raise nvp_exc.NvpInvalidVersion(version=v)
return v
def delete_network(cluster, net_id, lswitch_id):
delete_networks(cluster, net_id, [lswitch_id])
@ -669,13 +341,6 @@ def query_lswitch_lports(cluster, ls_uuid, fields="*",
return do_request(HTTP_GET, uri, cluster=cluster)['results']
def query_lrouter_lports(cluster, lr_uuid, fields="*",
filters=None, relations=None):
uri = _build_uri_path(LROUTERPORT_RESOURCE, parent_resource_id=lr_uuid,
fields=fields, filters=filters, relations=relations)
return do_request(HTTP_GET, uri, cluster=cluster)['results']
def delete_port(cluster, switch, port):
uri = "/ws.v1/lswitch/" + switch + "/lport/" + port
try:
@ -884,129 +549,6 @@ def create_lport(cluster, lswitch_uuid, tenant_id, neutron_port_id,
return result
def create_router_lport(cluster, lrouter_uuid, tenant_id, neutron_port_id,
display_name, admin_status_enabled, ip_addresses,
mac_address=None):
"""Creates a logical port on the assigned logical router."""
tags = [dict(scope='os_tid', tag=tenant_id),
dict(scope='q_port_id', tag=neutron_port_id),
dict(scope='quantum', tag=NEUTRON_VERSION)]
lport_obj = dict(
admin_status_enabled=admin_status_enabled,
display_name=display_name,
tags=tags,
ip_addresses=ip_addresses,
type="LogicalRouterPortConfig"
)
# Only add the mac_address to lport_obj if present. This is because
# when creating the fake_ext_gw there is no mac_address present.
if mac_address:
lport_obj['mac_address'] = mac_address
path = _build_uri_path(LROUTERPORT_RESOURCE,
parent_resource_id=lrouter_uuid)
result = do_request(HTTP_POST, path, json.dumps(lport_obj),
cluster=cluster)
LOG.debug(_("Created logical port %(lport_uuid)s on "
"logical router %(lrouter_uuid)s"),
{'lport_uuid': result['uuid'],
'lrouter_uuid': lrouter_uuid})
return result
def update_router_lport(cluster, lrouter_uuid, lrouter_port_uuid,
tenant_id, neutron_port_id, display_name,
admin_status_enabled, ip_addresses):
"""Updates a logical port on the assigned logical router."""
lport_obj = dict(
admin_status_enabled=admin_status_enabled,
display_name=display_name,
tags=[dict(scope='os_tid', tag=tenant_id),
dict(scope='q_port_id', tag=neutron_port_id),
dict(scope='quantum', tag=NEUTRON_VERSION)],
ip_addresses=ip_addresses,
type="LogicalRouterPortConfig"
)
# Do not pass null items to NVP
for key in lport_obj.keys():
if lport_obj[key] is None:
del lport_obj[key]
path = _build_uri_path(LROUTERPORT_RESOURCE,
lrouter_port_uuid,
parent_resource_id=lrouter_uuid)
result = do_request(HTTP_PUT, path,
json.dumps(lport_obj),
cluster=cluster)
LOG.debug(_("Updated logical port %(lport_uuid)s on "
"logical router %(lrouter_uuid)s"),
{'lport_uuid': lrouter_port_uuid, 'lrouter_uuid': lrouter_uuid})
return result
def delete_router_lport(cluster, lrouter_uuid, lport_uuid):
"""Creates a logical port on the assigned logical router."""
path = _build_uri_path(LROUTERPORT_RESOURCE, lport_uuid, lrouter_uuid)
do_request(HTTP_DELETE, path, cluster=cluster)
LOG.debug(_("Delete logical router port %(lport_uuid)s on "
"logical router %(lrouter_uuid)s"),
{'lport_uuid': lport_uuid,
'lrouter_uuid': lrouter_uuid})
def delete_peer_router_lport(cluster, lr_uuid, ls_uuid, lp_uuid):
nvp_port = get_port(cluster, ls_uuid, lp_uuid,
relations="LogicalPortAttachment")
relations = nvp_port.get('_relations')
if relations:
att_data = relations.get('LogicalPortAttachment')
if att_data:
lrp_uuid = att_data.get('peer_port_uuid')
if lrp_uuid:
delete_router_lport(cluster, lr_uuid, lrp_uuid)
def find_router_gw_port(context, cluster, router_id):
"""Retrieves the external gateway port for a NVP logical router."""
# Find the uuid of nvp ext gw logical router port
# TODO(salvatore-orlando): Consider storing it in Neutron DB
results = query_lrouter_lports(
cluster, router_id,
relations="LogicalPortAttachment")
for lport in results:
if '_relations' in lport:
attachment = lport['_relations'].get('LogicalPortAttachment')
if attachment and attachment.get('type') == 'L3GatewayAttachment':
return lport
def plug_router_port_attachment(cluster, router_id, port_id,
attachment_uuid, nvp_attachment_type,
attachment_vlan=None):
"""Attach a router port to the given attachment.
Current attachment types:
- PatchAttachment [-> logical switch port uuid]
- L3GatewayAttachment [-> L3GatewayService uuid]
For the latter attachment type a VLAN ID can be specified as well.
"""
uri = _build_uri_path(LROUTERPORT_RESOURCE, port_id, router_id,
is_attachment=True)
attach_obj = {}
attach_obj["type"] = nvp_attachment_type
if nvp_attachment_type == "PatchAttachment":
attach_obj["peer_port_uuid"] = attachment_uuid
elif nvp_attachment_type == "L3GatewayAttachment":
attach_obj["l3_gateway_service_uuid"] = attachment_uuid
if attachment_vlan:
attach_obj['vlan_id'] = attachment_vlan
else:
raise nvp_exc.NvpInvalidAttachmentType(
attachment_type=nvp_attachment_type)
return do_request(HTTP_PUT, uri, json.dumps(attach_obj), cluster=cluster)
def get_port_status(cluster, lswitch_id, port_id):
"""Retrieve the operational status of the port."""
try:
@ -1176,243 +718,3 @@ def delete_security_profile(cluster, spid):
LOG.warn(_("Unable to find security profile %s on NSX backend"),
spid)
raise
def _create_nat_match_obj(**kwargs):
nat_match_obj = {'ethertype': 'IPv4'}
delta = set(kwargs.keys()) - set(MATCH_KEYS)
if delta:
raise Exception(_("Invalid keys for NAT match: %s"), delta)
nat_match_obj.update(kwargs)
return nat_match_obj
def _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj):
LOG.debug(_("Creating NAT rule: %s"), nat_rule_obj)
uri = _build_uri_path(LROUTERNAT_RESOURCE, parent_resource_id=router_id)
return do_request(HTTP_POST, uri, json.dumps(nat_rule_obj),
cluster=cluster)
def _build_snat_rule_obj(min_src_ip, max_src_ip, nat_match_obj):
return {"to_source_ip_address_min": min_src_ip,
"to_source_ip_address_max": max_src_ip,
"type": "SourceNatRule",
"match": nat_match_obj}
def create_lrouter_nosnat_rule_v2(cluster, _router_id, _match_criteria=None):
LOG.info(_("No SNAT rules cannot be applied as they are not available in "
"this version of the NVP platform"))
def create_lrouter_nodnat_rule_v2(cluster, _router_id, _match_criteria=None):
LOG.info(_("No DNAT rules cannot be applied as they are not available in "
"this version of the NVP platform"))
def create_lrouter_snat_rule_v2(cluster, router_id,
min_src_ip, max_src_ip, match_criteria=None):
nat_match_obj = _create_nat_match_obj(**match_criteria)
nat_rule_obj = _build_snat_rule_obj(min_src_ip, max_src_ip, nat_match_obj)
return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
def create_lrouter_dnat_rule_v2(cluster, router_id, dst_ip,
to_dst_port=None, match_criteria=None):
nat_match_obj = _create_nat_match_obj(**match_criteria)
nat_rule_obj = {
"to_destination_ip_address_min": dst_ip,
"to_destination_ip_address_max": dst_ip,
"type": "DestinationNatRule",
"match": nat_match_obj
}
if to_dst_port:
nat_rule_obj['to_destination_port'] = to_dst_port
return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
def create_lrouter_nosnat_rule_v3(cluster, router_id, order=None,
match_criteria=None):
nat_match_obj = _create_nat_match_obj(**match_criteria)
nat_rule_obj = {
"type": "NoSourceNatRule",
"match": nat_match_obj
}
if order:
nat_rule_obj['order'] = order
return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
def create_lrouter_nodnat_rule_v3(cluster, router_id, order=None,
match_criteria=None):
nat_match_obj = _create_nat_match_obj(**match_criteria)
nat_rule_obj = {
"type": "NoDestinationNatRule",
"match": nat_match_obj
}
if order:
nat_rule_obj['order'] = order
return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
def create_lrouter_snat_rule_v3(cluster, router_id, min_src_ip, max_src_ip,
order=None, match_criteria=None):
nat_match_obj = _create_nat_match_obj(**match_criteria)
nat_rule_obj = _build_snat_rule_obj(min_src_ip, max_src_ip, nat_match_obj)
if order:
nat_rule_obj['order'] = order
return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
def create_lrouter_dnat_rule_v3(cluster, router_id, dst_ip, to_dst_port=None,
order=None, match_criteria=None):
nat_match_obj = _create_nat_match_obj(**match_criteria)
nat_rule_obj = {
"to_destination_ip_address": dst_ip,
"type": "DestinationNatRule",
"match": nat_match_obj
}
if to_dst_port:
nat_rule_obj['to_destination_port'] = to_dst_port
if order:
nat_rule_obj['order'] = order
return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
@version_dependent
def create_lrouter_dnat_rule(cluster, *args, **kwargs):
pass
@version_dependent
def create_lrouter_snat_rule(cluster, *args, **kwargs):
pass
@version_dependent
def create_lrouter_nosnat_rule(cluster, *args, **kwargs):
pass
@version_dependent
def create_lrouter_nodnat_rule(cluster, *args, **kwargs):
pass
def delete_nat_rules_by_match(cluster, router_id, rule_type,
max_num_expected,
min_num_expected=0,
**kwargs):
# remove nat rules
nat_rules = query_nat_rules(cluster, router_id)
to_delete_ids = []
for r in nat_rules:
if (r['type'] != rule_type):
continue
for key, value in kwargs.iteritems():
if not (key in r['match'] and r['match'][key] == value):
break
else:
to_delete_ids.append(r['uuid'])
if not (len(to_delete_ids) in
range(min_num_expected, max_num_expected + 1)):
raise nvp_exc.NvpNatRuleMismatch(actual_rules=len(to_delete_ids),
min_rules=min_num_expected,
max_rules=max_num_expected)
for rule_id in to_delete_ids:
delete_router_nat_rule(cluster, router_id, rule_id)
def delete_router_nat_rule(cluster, router_id, rule_id):
uri = _build_uri_path(LROUTERNAT_RESOURCE, rule_id, router_id)
do_request(HTTP_DELETE, uri, cluster=cluster)
def query_nat_rules(cluster, router_id, fields="*", filters=None):
uri = _build_uri_path(LROUTERNAT_RESOURCE, parent_resource_id=router_id,
fields=fields, filters=filters)
return get_all_query_pages(uri, cluster)
# NOTE(salvatore-orlando): The following FIXME applies in general to
# each operation on list attributes.
# FIXME(salvatore-orlando): need a lock around the list of IPs on an iface
def update_lrouter_port_ips(cluster, lrouter_id, lport_id,
ips_to_add, ips_to_remove):
uri = _build_uri_path(LROUTERPORT_RESOURCE, lport_id, lrouter_id)
try:
port = do_request(HTTP_GET, uri, cluster=cluster)
# TODO(salvatore-orlando): Enforce ips_to_add intersection with
# ips_to_remove is empty
ip_address_set = set(port['ip_addresses'])
ip_address_set = ip_address_set - set(ips_to_remove)
ip_address_set = ip_address_set | set(ips_to_add)
# Set is not JSON serializable - convert to list
port['ip_addresses'] = list(ip_address_set)
do_request(HTTP_PUT, uri, json.dumps(port), cluster=cluster)
except exception.NotFound as e:
# FIXME(salv-orlando):avoid raising different exception
data = {'lport_id': lport_id, 'lrouter_id': lrouter_id}
msg = (_("Router Port %(lport_id)s not found on router "
"%(lrouter_id)s") % data)
LOG.exception(msg)
raise nvp_exc.NvpPluginException(err_msg=msg)
except NvpApiClient.NvpApiException as e:
msg = _("An exception occurred while updating IP addresses on a "
"router logical port:%s") % str(e)
LOG.exception(msg)
raise nvp_exc.NvpPluginException(err_msg=msg)
DEFAULT = -1
NVPLIB_FUNC_DICT = {
'create_lrouter': {
2: {DEFAULT: create_implicit_routing_lrouter, },
3: {DEFAULT: create_implicit_routing_lrouter,
1: create_implicit_routing_lrouter_with_distribution,
2: create_explicit_routing_lrouter, }, },
'update_lrouter': {
2: {DEFAULT: update_implicit_routing_lrouter, },
3: {DEFAULT: update_implicit_routing_lrouter,
2: update_explicit_routing_lrouter, }, },
'create_lrouter_dnat_rule': {
2: {DEFAULT: create_lrouter_dnat_rule_v2, },
3: {DEFAULT: create_lrouter_dnat_rule_v3, }, },
'create_lrouter_snat_rule': {
2: {DEFAULT: create_lrouter_snat_rule_v2, },
3: {DEFAULT: create_lrouter_snat_rule_v3, }, },
'create_lrouter_nosnat_rule': {
2: {DEFAULT: create_lrouter_nosnat_rule_v2, },
3: {DEFAULT: create_lrouter_nosnat_rule_v3, }, },
'create_lrouter_nodnat_rule': {
2: {DEFAULT: create_lrouter_nodnat_rule_v2, },
3: {DEFAULT: create_lrouter_nodnat_rule_v3, }, },
'get_default_route_explicit_routing_lrouter': {
3: {DEFAULT: get_default_route_explicit_routing_lrouter_v32,
2: get_default_route_explicit_routing_lrouter_v32, }, },
}
def get_function_by_version(func_name, nvp_ver):
if nvp_ver:
if nvp_ver.major not in NVPLIB_FUNC_DICT[func_name]:
major = max(NVPLIB_FUNC_DICT[func_name].keys())
minor = max(NVPLIB_FUNC_DICT[func_name][major].keys())
if major > nvp_ver.major:
raise NotImplementedError(_("Operation may not be supported"))
else:
major = nvp_ver.major
minor = nvp_ver.minor
if nvp_ver.minor not in NVPLIB_FUNC_DICT[func_name][major]:
minor = DEFAULT
return NVPLIB_FUNC_DICT[func_name][major][minor]
else:
msg = _('NVP version is not set. Unable to complete request '
'correctly. Check log for NVP communication errors.')
raise NvpApiClient.ServiceUnavailable(message=msg)

View File

@ -0,0 +1,922 @@
# Copyright (c) 2014 VMware, Inc.
#
# 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.
#
import mock
from neutron.common import exceptions
from neutron.openstack.common import uuidutils
from neutron.plugins.nicira.common import exceptions as nvp_exc
from neutron.plugins.nicira.nsxlib import router as routerlib
from neutron.plugins.nicira import NvpApiClient
from neutron.plugins.nicira import nvplib
from neutron.tests.unit.nicira.test_nvplib import NsxlibNegativeBaseTestCase
from neutron.tests.unit.nicira.test_nvplib import NvplibTestCase
from neutron.tests.unit import test_api_v2
_uuid = test_api_v2._uuid
class TestNatRules(NvplibTestCase):
def _test_create_lrouter_dnat_rule(self, version):
with mock.patch.object(self.fake_cluster.api_client,
'get_nvp_version',
new=lambda: NvpApiClient.NVPVersion(version)):
tenant_id = 'pippo'
lrouter = routerlib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
tenant_id,
'fake_router',
'192.168.0.1')
nat_rule = routerlib.create_lrouter_dnat_rule(
self.fake_cluster, lrouter['uuid'], '10.0.0.99',
match_criteria={'destination_ip_addresses':
'192.168.0.5'})
uri = nvplib._build_uri_path(routerlib.LROUTERNAT_RESOURCE,
nat_rule['uuid'],
lrouter['uuid'])
resp_obj = nvplib.do_request("GET", uri, cluster=self.fake_cluster)
self.assertEqual('DestinationNatRule', resp_obj['type'])
self.assertEqual('192.168.0.5',
resp_obj['match']['destination_ip_addresses'])
def test_create_lrouter_dnat_rule_v2(self):
self._test_create_lrouter_dnat_rule('2.9')
def test_create_lrouter_dnat_rule_v31(self):
self._test_create_lrouter_dnat_rule('3.1')
class TestExplicitLRouters(NvplibTestCase):
def setUp(self):
self.fake_version = '3.2'
super(TestExplicitLRouters, self).setUp()
def _get_lrouter(self, tenant_id, router_name, router_id, relations=None):
schema = '/ws.v1/schema/RoutingTableRoutingConfig'
router = {'display_name': router_name,
'uuid': router_id,
'tags': [{'scope': 'quantum', 'tag': nvplib.NEUTRON_VERSION},
{'scope': 'os_tid', 'tag': '%s' % tenant_id}],
'distributed': False,
'routing_config': {'type': 'RoutingTableRoutingConfig',
'_schema': schema},
'_schema': schema,
'nat_synchronization_enabled': True,
'replication_mode': 'service',
'type': 'LogicalRouterConfig',
'_href': '/ws.v1/lrouter/%s' % router_id, }
if relations:
router['_relations'] = relations
return router
def _get_single_route(self, router_id, route_id='fake_route_id_0',
prefix='0.0.0.0/0', next_hop_ip='1.1.1.1'):
return {'protocol': 'static',
'_href': '/ws.v1/lrouter/%s/rib/%s' % (router_id, route_id),
'prefix': prefix,
'_schema': '/ws.v1/schema/RoutingTableEntry',
'next_hop_ip': next_hop_ip,
'action': 'accept',
'uuid': route_id}
def test_prepare_body_with_implicit_routing_config(self):
router_name = 'fake_router_name'
tenant_id = 'fake_tenant_id'
neutron_router_id = 'pipita_higuain'
router_type = 'SingleDefaultRouteImplicitRoutingConfig'
route_config = {
'default_route_next_hop': {'gateway_ip_address': 'fake_address',
'type': 'RouterNextHop'}, }
body = routerlib._prepare_lrouter_body(router_name, neutron_router_id,
tenant_id, router_type,
**route_config)
expected = {'display_name': 'fake_router_name',
'routing_config': {
'default_route_next_hop':
{'gateway_ip_address': 'fake_address',
'type': 'RouterNextHop'},
'type': 'SingleDefaultRouteImplicitRoutingConfig'},
'tags': [{'scope': 'os_tid', 'tag': 'fake_tenant_id'},
{'scope': 'q_router_id', 'tag': 'pipita_higuain'},
{'scope': 'quantum',
'tag': nvplib.NEUTRON_VERSION}],
'type': 'LogicalRouterConfig'}
self.assertEqual(expected, body)
def test_prepare_body_without_routing_config(self):
router_name = 'fake_router_name'
tenant_id = 'fake_tenant_id'
neutron_router_id = 'marekiaro_hamsik'
router_type = 'RoutingTableRoutingConfig'
body = routerlib._prepare_lrouter_body(router_name, neutron_router_id,
tenant_id, router_type)
expected = {'display_name': 'fake_router_name',
'routing_config': {'type': 'RoutingTableRoutingConfig'},
'tags': [{'scope': 'os_tid', 'tag': 'fake_tenant_id'},
{'scope': 'q_router_id',
'tag': 'marekiaro_hamsik'},
{'scope': 'quantum',
'tag': nvplib.NEUTRON_VERSION}],
'type': 'LogicalRouterConfig'}
self.assertEqual(expected, body)
def test_get_lrouter(self):
tenant_id = 'fake_tenant_id'
router_name = 'fake_router_name'
router_id = 'fake_router_id'
relations = {
'LogicalRouterStatus':
{'_href': '/ws.v1/lrouter/%s/status' % router_id,
'lport_admin_up_count': 1,
'_schema': '/ws.v1/schema/LogicalRouterStatus',
'lport_count': 1,
'fabric_status': True,
'type': 'LogicalRouterStatus',
'lport_link_up_count': 0, }, }
with mock.patch.object(routerlib, 'do_request',
return_value=self._get_lrouter(tenant_id,
router_name,
router_id,
relations)):
lrouter = routerlib.get_lrouter(self.fake_cluster, router_id)
self.assertTrue(
lrouter['_relations']['LogicalRouterStatus']['fabric_status'])
def test_create_lrouter(self):
tenant_id = 'fake_tenant_id'
router_name = 'fake_router_name'
router_id = 'fake_router_id'
nexthop_ip = '10.0.0.1'
with mock.patch.object(
routerlib, 'do_request',
return_value=self._get_lrouter(tenant_id,
router_name,
router_id)):
lrouter = routerlib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
tenant_id,
router_name, nexthop_ip)
self.assertEqual(lrouter['routing_config']['type'],
'RoutingTableRoutingConfig')
self.assertNotIn('default_route_next_hop',
lrouter['routing_config'])
def test_update_lrouter_with_no_routes(self):
router_id = 'fake_router_id'
new_routes = [{"nexthop": "10.0.0.2",
"destination": "169.254.169.0/30"}, ]
nvp_routes = [self._get_single_route(router_id)]
with mock.patch.object(routerlib, 'get_explicit_routes_lrouter',
return_value=nvp_routes):
with mock.patch.object(routerlib, 'create_explicit_route_lrouter',
return_value='fake_uuid'):
old_routes = routerlib.update_explicit_routes_lrouter(
self.fake_cluster, router_id, new_routes)
self.assertEqual(old_routes, nvp_routes)
def test_update_lrouter_with_no_routes_raise_nsx_exception(self):
router_id = 'fake_router_id'
new_routes = [{"nexthop": "10.0.0.2",
"destination": "169.254.169.0/30"}, ]
nsx_routes = [self._get_single_route(router_id)]
with mock.patch.object(routerlib, 'get_explicit_routes_lrouter',
return_value=nsx_routes):
with mock.patch.object(routerlib, 'create_explicit_route_lrouter',
side_effect=NvpApiClient.NvpApiException):
self.assertRaises(NvpApiClient.NvpApiException,
routerlib.update_explicit_routes_lrouter,
self.fake_cluster, router_id, new_routes)
def test_update_lrouter_with_routes(self):
router_id = 'fake_router_id'
new_routes = [{"next_hop_ip": "10.0.0.2",
"prefix": "169.254.169.0/30"}, ]
nsx_routes = [self._get_single_route(router_id),
self._get_single_route(router_id, 'fake_route_id_1',
'0.0.0.1/24', '10.0.0.3'),
self._get_single_route(router_id, 'fake_route_id_2',
'0.0.0.2/24', '10.0.0.4'), ]
with mock.patch.object(routerlib, 'get_explicit_routes_lrouter',
return_value=nsx_routes):
with mock.patch.object(routerlib, 'delete_explicit_route_lrouter',
return_value=None):
with mock.patch.object(routerlib,
'create_explicit_route_lrouter',
return_value='fake_uuid'):
old_routes = routerlib.update_explicit_routes_lrouter(
self.fake_cluster, router_id, new_routes)
self.assertEqual(old_routes, nsx_routes)
def test_update_lrouter_with_routes_raises_nsx_expception(self):
router_id = 'fake_router_id'
new_routes = [{"nexthop": "10.0.0.2",
"destination": "169.254.169.0/30"}, ]
nsx_routes = [self._get_single_route(router_id),
self._get_single_route(router_id, 'fake_route_id_1',
'0.0.0.1/24', '10.0.0.3'),
self._get_single_route(router_id, 'fake_route_id_2',
'0.0.0.2/24', '10.0.0.4'), ]
with mock.patch.object(routerlib, 'get_explicit_routes_lrouter',
return_value=nsx_routes):
with mock.patch.object(routerlib, 'delete_explicit_route_lrouter',
side_effect=NvpApiClient.NvpApiException):
with mock.patch.object(
routerlib, 'create_explicit_route_lrouter',
return_value='fake_uuid'):
self.assertRaises(
NvpApiClient.NvpApiException,
routerlib.update_explicit_routes_lrouter,
self.fake_cluster, router_id, new_routes)
class RouterNegativeTestCase(NsxlibNegativeBaseTestCase):
def test_create_lrouter_on_failure(self):
self.assertRaises(nvplib.NvpApiClient.NvpApiException,
routerlib.create_lrouter,
self.fake_cluster,
uuidutils.generate_uuid(),
'pluto',
'fake_router',
'my_hop')
def test_delete_lrouter_on_failure(self):
self.assertRaises(nvplib.NvpApiClient.NvpApiException,
routerlib.delete_lrouter,
self.fake_cluster,
'fake_router')
def test_get_lrouter_on_failure(self):
self.assertRaises(nvplib.NvpApiClient.NvpApiException,
routerlib.get_lrouter,
self.fake_cluster,
'fake_router')
def test_update_lrouter_on_failure(self):
self.assertRaises(nvplib.NvpApiClient.NvpApiException,
routerlib.update_lrouter,
self.fake_cluster,
'fake_router',
'pluto',
'new_hop')
class TestLogicalRouters(NvplibTestCase):
def _verify_lrouter(self, res_lrouter,
expected_uuid,
expected_display_name,
expected_nexthop,
expected_tenant_id,
expected_neutron_id=None,
expected_distributed=None):
self.assertEqual(res_lrouter['uuid'], expected_uuid)
nexthop = (res_lrouter['routing_config']
['default_route_next_hop']['gateway_ip_address'])
self.assertEqual(nexthop, expected_nexthop)
router_tags = self._build_tag_dict(res_lrouter['tags'])
self.assertIn('os_tid', router_tags)
self.assertEqual(res_lrouter['display_name'], expected_display_name)
self.assertEqual(expected_tenant_id, router_tags['os_tid'])
if expected_distributed is not None:
self.assertEqual(expected_distributed,
res_lrouter['distributed'])
if expected_neutron_id:
self.assertIn('q_router_id', router_tags)
self.assertEqual(expected_neutron_id, router_tags['q_router_id'])
def test_get_lrouters(self):
lrouter_uuids = [routerlib.create_lrouter(
self.fake_cluster, 'whatever', 'pippo', 'fake-lrouter-%s' % k,
'10.0.0.1')['uuid'] for k in range(3)]
routers = routerlib.get_lrouters(self.fake_cluster, 'pippo')
for router in routers:
self.assertIn(router['uuid'], lrouter_uuids)
def _create_lrouter(self, version, neutron_id=None, distributed=None):
with mock.patch.object(
self.fake_cluster.api_client, 'get_nvp_version',
return_value=NvpApiClient.NVPVersion(version)):
if not neutron_id:
neutron_id = uuidutils.generate_uuid()
lrouter = routerlib.create_lrouter(
self.fake_cluster, neutron_id, 'pippo',
'fake-lrouter', '10.0.0.1', distributed=distributed)
return routerlib.get_lrouter(self.fake_cluster,
lrouter['uuid'])
def test_create_and_get_lrouter_v30(self):
neutron_id = uuidutils.generate_uuid()
res_lrouter = self._create_lrouter('3.0', neutron_id=neutron_id)
self._verify_lrouter(res_lrouter, res_lrouter['uuid'],
'fake-lrouter', '10.0.0.1', 'pippo',
expected_neutron_id=neutron_id)
def test_create_and_get_lrouter_v31_centralized(self):
neutron_id = uuidutils.generate_uuid()
res_lrouter = self._create_lrouter('3.1', neutron_id=neutron_id,
distributed=False)
self._verify_lrouter(res_lrouter, res_lrouter['uuid'],
'fake-lrouter', '10.0.0.1', 'pippo',
expected_neutron_id=neutron_id,
expected_distributed=False)
def test_create_and_get_lrouter_v31_distributed(self):
neutron_id = uuidutils.generate_uuid()
res_lrouter = self._create_lrouter('3.1', neutron_id=neutron_id,
distributed=True)
self._verify_lrouter(res_lrouter, res_lrouter['uuid'],
'fake-lrouter', '10.0.0.1', 'pippo',
expected_neutron_id=neutron_id,
expected_distributed=True)
def test_create_and_get_lrouter_name_exceeds_40chars(self):
neutron_id = uuidutils.generate_uuid()
display_name = '*' * 50
lrouter = routerlib.create_lrouter(self.fake_cluster,
neutron_id,
'pippo',
display_name,
'10.0.0.1')
res_lrouter = routerlib.get_lrouter(self.fake_cluster,
lrouter['uuid'])
self._verify_lrouter(res_lrouter, lrouter['uuid'],
'*' * 40, '10.0.0.1', 'pippo',
expected_neutron_id=neutron_id)
def _test_version_dependent_update_lrouter(self, version):
def foo(*args, **kwargs):
return version
foo_func_dict = {
'update_lrouter': {
2: {-1: foo},
3: {-1: foo, 2: foo}
}
}
with mock.patch.object(self.fake_cluster.api_client,
'get_nvp_version',
return_value=NvpApiClient.NVPVersion(version)):
with mock.patch.dict(routerlib.ROUTER_FUNC_DICT,
foo_func_dict, clear=True):
return routerlib.update_lrouter(
self.fake_cluster, 'foo_router_id', 'foo_router_name',
'foo_nexthop', routes={'foo_destination': 'foo_address'})
def test_version_dependent_update_lrouter_old_versions(self):
self.assertRaises(nvp_exc.NvpInvalidVersion,
self._test_version_dependent_update_lrouter,
"2.9")
self.assertRaises(nvp_exc.NvpInvalidVersion,
self._test_version_dependent_update_lrouter,
"3.0")
self.assertRaises(nvp_exc.NvpInvalidVersion,
self._test_version_dependent_update_lrouter,
"3.1")
def test_version_dependent_update_lrouter_new_versions(self):
self.assertEqual("3.2",
self._test_version_dependent_update_lrouter("3.2"))
self.assertEqual("4.0",
self._test_version_dependent_update_lrouter("4.0"))
self.assertEqual("4.1",
self._test_version_dependent_update_lrouter("4.1"))
def test_update_lrouter_no_nexthop(self):
neutron_id = uuidutils.generate_uuid()
lrouter = routerlib.create_lrouter(self.fake_cluster,
neutron_id,
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter = routerlib.update_lrouter(self.fake_cluster,
lrouter['uuid'],
'new_name',
None)
res_lrouter = routerlib.get_lrouter(self.fake_cluster,
lrouter['uuid'])
self._verify_lrouter(res_lrouter, lrouter['uuid'],
'new_name', '10.0.0.1', 'pippo',
expected_neutron_id=neutron_id)
def test_update_lrouter(self):
neutron_id = uuidutils.generate_uuid()
lrouter = routerlib.create_lrouter(self.fake_cluster,
neutron_id,
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter = routerlib.update_lrouter(self.fake_cluster,
lrouter['uuid'],
'new_name',
'192.168.0.1')
res_lrouter = routerlib.get_lrouter(self.fake_cluster,
lrouter['uuid'])
self._verify_lrouter(res_lrouter, lrouter['uuid'],
'new_name', '192.168.0.1', 'pippo',
expected_neutron_id=neutron_id)
def test_update_nonexistent_lrouter_raises(self):
self.assertRaises(exceptions.NotFound,
routerlib.update_lrouter,
self.fake_cluster,
'whatever',
'foo', '9.9.9.9')
def test_delete_lrouter(self):
lrouter = routerlib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
routerlib.delete_lrouter(self.fake_cluster, lrouter['uuid'])
self.assertRaises(exceptions.NotFound,
routerlib.get_lrouter,
self.fake_cluster,
lrouter['uuid'])
def test_query_lrouter_ports(self):
lrouter = routerlib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
router_port_uuids = [routerlib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo',
'qp_id_%s' % k, 'port-%s' % k, True,
['192.168.0.%s' % k], '00:11:22:33:44:55')['uuid']
for k in range(3)]
ports = routerlib.query_lrouter_lports(
self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(ports), 3)
for res_port in ports:
self.assertIn(res_port['uuid'], router_port_uuids)
def test_query_lrouter_lports_nonexistent_lrouter_raises(self):
self.assertRaises(
exceptions.NotFound, routerlib.create_router_lport,
self.fake_cluster, 'booo', 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
def test_create_and_get_lrouter_port(self):
lrouter = routerlib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
routerlib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
ports = routerlib.query_lrouter_lports(
self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(ports), 1)
res_port = ports[0]
port_tags = self._build_tag_dict(res_port['tags'])
self.assertEqual(['192.168.0.1'], res_port['ip_addresses'])
self.assertIn('os_tid', port_tags)
self.assertIn('q_port_id', port_tags)
self.assertEqual('pippo', port_tags['os_tid'])
self.assertEqual('neutron_port_id', port_tags['q_port_id'])
def test_create_lrouter_port_nonexistent_router_raises(self):
self.assertRaises(
exceptions.NotFound, routerlib.create_router_lport,
self.fake_cluster, 'booo', 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
def test_update_lrouter_port(self):
lrouter = routerlib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter_port = routerlib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
routerlib.update_router_lport(
self.fake_cluster, lrouter['uuid'], lrouter_port['uuid'],
'pippo', 'another_port_id', 'name', False,
['192.168.0.1', '10.10.10.254'])
ports = routerlib.query_lrouter_lports(
self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(ports), 1)
res_port = ports[0]
port_tags = self._build_tag_dict(res_port['tags'])
self.assertEqual(['192.168.0.1', '10.10.10.254'],
res_port['ip_addresses'])
self.assertEqual('False', res_port['admin_status_enabled'])
self.assertIn('os_tid', port_tags)
self.assertIn('q_port_id', port_tags)
self.assertEqual('pippo', port_tags['os_tid'])
self.assertEqual('another_port_id', port_tags['q_port_id'])
def test_update_lrouter_port_nonexistent_router_raises(self):
self.assertRaises(
exceptions.NotFound, routerlib.update_router_lport,
self.fake_cluster, 'boo-router', 'boo-port', 'pippo',
'neutron_port_id', 'name', True, ['192.168.0.1'])
def test_update_lrouter_port_nonexistent_port_raises(self):
lrouter = routerlib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
self.assertRaises(
exceptions.NotFound, routerlib.update_router_lport,
self.fake_cluster, lrouter['uuid'], 'boo-port', 'pippo',
'neutron_port_id', 'name', True, ['192.168.0.1'])
def test_delete_lrouter_port(self):
lrouter = routerlib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter_port = routerlib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'x', 'y', True, [],
'00:11:22:33:44:55')
ports = routerlib.query_lrouter_lports(
self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(ports), 1)
routerlib.delete_router_lport(self.fake_cluster, lrouter['uuid'],
lrouter_port['uuid'])
ports = routerlib.query_lrouter_lports(
self.fake_cluster, lrouter['uuid'])
self.assertFalse(len(ports))
def test_delete_lrouter_port_nonexistent_router_raises(self):
self.assertRaises(exceptions.NotFound,
routerlib.delete_router_lport,
self.fake_cluster, 'xyz', 'abc')
def test_delete_lrouter_port_nonexistent_port_raises(self):
lrouter = routerlib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
self.assertRaises(exceptions.NotFound,
routerlib.delete_router_lport,
self.fake_cluster, lrouter['uuid'], 'abc')
def test_delete_peer_lrouter_port(self):
lrouter = routerlib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter_port = routerlib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'x', 'y', True, [],
'00:11:22:33:44:55')
def fakegetport(*args, **kwargs):
return {'_relations': {'LogicalPortAttachment':
{'peer_port_uuid': lrouter_port['uuid']}}}
# mock get_port
with mock.patch.object(routerlib, 'get_port', new=fakegetport):
routerlib.delete_peer_router_lport(self.fake_cluster,
lrouter_port['uuid'],
'whatwever', 'whatever')
def test_update_lrouter_port_ips_add_only(self):
lrouter = routerlib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter_port = routerlib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
routerlib.update_lrouter_port_ips(
self.fake_cluster, lrouter['uuid'], lrouter_port['uuid'],
['10.10.10.254'], [])
ports = routerlib.query_lrouter_lports(
self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(ports), 1)
res_port = ports[0]
self.assertEqual(['10.10.10.254', '192.168.0.1'],
res_port['ip_addresses'])
def test_update_lrouter_port_ips_remove_only(self):
lrouter = routerlib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter_port = routerlib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1', '10.10.10.254'],
'00:11:22:33:44:55')
routerlib.update_lrouter_port_ips(
self.fake_cluster, lrouter['uuid'], lrouter_port['uuid'],
[], ['10.10.10.254'])
ports = routerlib.query_lrouter_lports(
self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(ports), 1)
res_port = ports[0]
self.assertEqual(['192.168.0.1'], res_port['ip_addresses'])
def test_update_lrouter_port_ips_add_and_remove(self):
lrouter = routerlib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter_port = routerlib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
routerlib.update_lrouter_port_ips(
self.fake_cluster, lrouter['uuid'], lrouter_port['uuid'],
['10.10.10.254'], ['192.168.0.1'])
ports = routerlib.query_lrouter_lports(
self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(ports), 1)
res_port = ports[0]
self.assertEqual(['10.10.10.254'], res_port['ip_addresses'])
def test_update_lrouter_port_ips_nonexistent_router_raises(self):
self.assertRaises(
nvp_exc.NvpPluginException, routerlib.update_lrouter_port_ips,
self.fake_cluster, 'boo-router', 'boo-port', [], [])
def test_update_lrouter_port_ips_nsx_exception_raises(self):
lrouter = routerlib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter_port = routerlib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
def raise_nsx_exc(*args, **kwargs):
raise NvpApiClient.NvpApiException()
with mock.patch.object(routerlib, 'do_request', new=raise_nsx_exc):
self.assertRaises(
nvp_exc.NvpPluginException, routerlib.update_lrouter_port_ips,
self.fake_cluster, lrouter['uuid'],
lrouter_port['uuid'], [], [])
def test_plug_lrouter_port_patch_attachment(self):
tenant_id = 'pippo'
transport_zones_config = [{'zone_uuid': _uuid(),
'transport_type': 'stt'}]
lswitch = nvplib.create_lswitch(self.fake_cluster,
_uuid(),
tenant_id, 'fake-switch',
transport_zones_config)
lport = nvplib.create_lport(self.fake_cluster, lswitch['uuid'],
tenant_id, 'xyz',
'name', 'device_id', True)
lrouter = routerlib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
tenant_id,
'fake-lrouter',
'10.0.0.1')
lrouter_port = routerlib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1'], '00:11:22:33:44:55:66')
result = routerlib.plug_router_port_attachment(
self.fake_cluster, lrouter['uuid'],
lrouter_port['uuid'],
lport['uuid'], 'PatchAttachment')
self.assertEqual(lport['uuid'],
result['LogicalPortAttachment']['peer_port_uuid'])
def test_plug_lrouter_port_l3_gw_attachment(self):
lrouter = routerlib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter_port = routerlib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1'], '00:11:22:33:44:55:66')
result = routerlib.plug_router_port_attachment(
self.fake_cluster, lrouter['uuid'],
lrouter_port['uuid'],
'gw_att', 'L3GatewayAttachment')
self.assertEqual(
'gw_att',
result['LogicalPortAttachment']['l3_gateway_service_uuid'])
def test_plug_lrouter_port_l3_gw_attachment_with_vlan(self):
lrouter = routerlib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter_port = routerlib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
result = routerlib.plug_router_port_attachment(
self.fake_cluster, lrouter['uuid'],
lrouter_port['uuid'],
'gw_att', 'L3GatewayAttachment', 123)
self.assertEqual(
'gw_att',
result['LogicalPortAttachment']['l3_gateway_service_uuid'])
self.assertEqual(
'123',
result['LogicalPortAttachment']['vlan_id'])
def test_plug_lrouter_port_invalid_attachment_type_raises(self):
lrouter = routerlib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter_port = routerlib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
self.assertRaises(nvp_exc.NvpInvalidAttachmentType,
routerlib.plug_router_port_attachment,
self.fake_cluster, lrouter['uuid'],
lrouter_port['uuid'], 'gw_att', 'BadType')
def _test_create_router_snat_rule(self, version):
lrouter = routerlib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
with mock.patch.object(self.fake_cluster.api_client,
'get_nvp_version',
new=lambda: NvpApiClient.NVPVersion(version)):
routerlib.create_lrouter_snat_rule(
self.fake_cluster, lrouter['uuid'],
'10.0.0.2', '10.0.0.2', order=200,
match_criteria={'source_ip_addresses': '192.168.0.24'})
rules = routerlib.query_nat_rules(
self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(rules), 1)
def test_create_router_snat_rule_v3(self):
self._test_create_router_snat_rule('3.0')
def test_create_router_snat_rule_v2(self):
self._test_create_router_snat_rule('2.0')
def _test_create_router_dnat_rule(self, version, dest_port=None):
lrouter = routerlib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
with mock.patch.object(self.fake_cluster.api_client,
'get_nvp_version',
return_value=NvpApiClient.NVPVersion(version)):
routerlib.create_lrouter_dnat_rule(
self.fake_cluster, lrouter['uuid'], '192.168.0.2', order=200,
dest_port=dest_port,
match_criteria={'destination_ip_addresses': '10.0.0.3'})
rules = routerlib.query_nat_rules(
self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(rules), 1)
def test_create_router_dnat_rule_v3(self):
self._test_create_router_dnat_rule('3.0')
def test_create_router_dnat_rule_v2(self):
self._test_create_router_dnat_rule('2.0')
def test_create_router_dnat_rule_v2_with_destination_port(self):
self._test_create_router_dnat_rule('2.0', 8080)
def test_create_router_dnat_rule_v3_with_destination_port(self):
self._test_create_router_dnat_rule('3.0', 8080)
def test_create_router_snat_rule_invalid_match_keys_raises(self):
# In this case the version does not make a difference
lrouter = routerlib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
with mock.patch.object(self.fake_cluster.api_client,
'get_nvp_version',
new=lambda: '2.0'):
self.assertRaises(AttributeError,
routerlib.create_lrouter_snat_rule,
self.fake_cluster, lrouter['uuid'],
'10.0.0.2', '10.0.0.2', order=200,
match_criteria={'foo': 'bar'})
def _test_create_router_nosnat_rule(self, version, expected=1):
lrouter = routerlib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
with mock.patch.object(self.fake_cluster.api_client,
'get_nvp_version',
new=lambda: NvpApiClient.NVPVersion(version)):
routerlib.create_lrouter_nosnat_rule(
self.fake_cluster, lrouter['uuid'],
order=100,
match_criteria={'destination_ip_addresses': '192.168.0.0/24'})
rules = routerlib.query_nat_rules(
self.fake_cluster, lrouter['uuid'])
# NoSNAT rules do not exist in V2
self.assertEqual(len(rules), expected)
def test_create_router_nosnat_rule_v2(self):
self._test_create_router_nosnat_rule('2.0', expected=0)
def test_create_router_nosnat_rule_v3(self):
self._test_create_router_nosnat_rule('3.0')
def _prepare_nat_rules_for_delete_tests(self):
lrouter = routerlib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
# v2 or v3 makes no difference for this test
with mock.patch.object(self.fake_cluster.api_client,
'get_nvp_version',
new=lambda: NvpApiClient.NVPVersion('2.0')):
routerlib.create_lrouter_snat_rule(
self.fake_cluster, lrouter['uuid'],
'10.0.0.2', '10.0.0.2', order=220,
match_criteria={'source_ip_addresses': '192.168.0.0/24'})
routerlib.create_lrouter_snat_rule(
self.fake_cluster, lrouter['uuid'],
'10.0.0.3', '10.0.0.3', order=200,
match_criteria={'source_ip_addresses': '192.168.0.2/32'})
routerlib.create_lrouter_dnat_rule(
self.fake_cluster, lrouter['uuid'], '192.168.0.2', order=200,
match_criteria={'destination_ip_addresses': '10.0.0.3'})
return lrouter
def test_delete_router_nat_rules_by_match_on_destination_ip(self):
lrouter = self._prepare_nat_rules_for_delete_tests()
rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(rules), 3)
routerlib.delete_nat_rules_by_match(
self.fake_cluster, lrouter['uuid'], 'DestinationNatRule', 1, 1,
destination_ip_addresses='10.0.0.3')
rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(rules), 2)
def test_delete_router_nat_rules_by_match_on_source_ip(self):
lrouter = self._prepare_nat_rules_for_delete_tests()
rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(rules), 3)
routerlib.delete_nat_rules_by_match(
self.fake_cluster, lrouter['uuid'], 'SourceNatRule', 1, 1,
source_ip_addresses='192.168.0.2/32')
rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(rules), 2)
def test_delete_router_nat_rules_by_match_no_match_expected(self):
lrouter = self._prepare_nat_rules_for_delete_tests()
rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(rules), 3)
routerlib.delete_nat_rules_by_match(
self.fake_cluster, lrouter['uuid'], 'SomeWeirdType', 0)
rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(rules), 3)
routerlib.delete_nat_rules_by_match(
self.fake_cluster, lrouter['uuid'], 'DestinationNatRule', 0,
destination_ip_addresses='99.99.99.99')
rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(rules), 3)
def test_delete_router_nat_rules_by_match_no_match_raises(self):
lrouter = self._prepare_nat_rules_for_delete_tests()
rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(rules), 3)
self.assertRaises(
nvp_exc.NvpNatRuleMismatch,
routerlib.delete_nat_rules_by_match,
self.fake_cluster, lrouter['uuid'],
'SomeWeirdType', 1, 1)

View File

@ -0,0 +1,57 @@
# Copyright (c) 2014 VMware, Inc.
#
# 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.
#
from neutron.plugins.nicira.nsxlib import router as routerlib
from neutron.plugins.nicira.nsxlib import versioning
from neutron.plugins.nicira import NvpApiClient
from neutron.tests import base
class TestVersioning(base.BaseTestCase):
def test_function_handling_missing_minor(self):
version = NvpApiClient.NVPVersion('2.0')
function = versioning.get_function_by_version(
routerlib.ROUTER_FUNC_DICT, 'create_lrouter', version)
self.assertEqual(routerlib.create_implicit_routing_lrouter,
function)
def test_function_handling_with_both_major_and_minor(self):
version = NvpApiClient.NVPVersion('3.2')
function = versioning.get_function_by_version(
routerlib.ROUTER_FUNC_DICT, 'create_lrouter', version)
self.assertEqual(routerlib.create_explicit_routing_lrouter,
function)
def test_function_handling_with_newer_major(self):
version = NvpApiClient.NVPVersion('5.2')
function = versioning.get_function_by_version(
routerlib.ROUTER_FUNC_DICT, 'create_lrouter', version)
self.assertEqual(routerlib.create_explicit_routing_lrouter,
function)
def test_function_handling_with_obsolete_major(self):
version = NvpApiClient.NVPVersion('1.2')
self.assertRaises(NotImplementedError,
versioning.get_function_by_version,
routerlib.ROUTER_FUNC_DICT,
'create_lrouter', version)
def test_function_handling_with_unknown_version(self):
self.assertRaises(NvpApiClient.ServiceUnavailable,
versioning.get_function_by_version,
routerlib.ROUTER_FUNC_DICT,
'create_lrouter', None)

View File

@ -638,7 +638,7 @@ class TestNiciraL3NatTestCase(NiciraL3NatTest,
self._test_router_create_with_distributed(True, True)
def test_router_create_distributed_with_new_nvp_versions(self):
with mock.patch.object(nvplib, 'create_explicit_route_lrouter'):
with mock.patch.object(nsxlib.router, 'create_explicit_route_lrouter'):
self._test_router_create_with_distributed(True, True, '3.2')
self._test_router_create_with_distributed(True, True, '4.0')
self._test_router_create_with_distributed(True, True, '4.1')
@ -655,12 +655,13 @@ class TestNiciraL3NatTestCase(NiciraL3NatTest,
def test_router_create_on_obsolete_platform(self):
def obsolete_response(*args, **kwargs):
response = nvplib._create_implicit_routing_lrouter(*args, **kwargs)
response = (nsxlib.router.
_create_implicit_routing_lrouter(*args, **kwargs))
response.pop('distributed')
return response
with mock.patch.object(
nvplib, 'create_lrouter', new=obsolete_response):
nsxlib.router, 'create_lrouter', new=obsolete_response):
self._test_router_create_with_distributed(None, False, '2.2')
def _create_router_with_gw_info_for_test(self, subnet):
@ -673,7 +674,7 @@ class TestNiciraL3NatTestCase(NiciraL3NatTest,
return router_req.get_response(self.ext_api)
def test_router_create_nvp_error_returns_500(self, vlan_id=None):
with mock.patch.object(nvplib,
with mock.patch.object(nsxlib.router,
'create_router_lport',
side_effect=NvpApiClient.NvpApiException):
with self._create_l3_ext_network(vlan_id) as net:
@ -1019,7 +1020,7 @@ class TestNiciraL3NatTestCase(NiciraL3NatTest,
with self._create_l3_ext_network() as net:
with self.subnet(network=net) as s:
with mock.patch.object(
nvplib,
nsxlib.router,
'do_request',
side_effect=nvp_exc.MaintenanceInProgress):
data = {'router': {'tenant_id': 'whatever'}}

View File

@ -171,7 +171,8 @@ class NsxUtilsTestCase(base.BaseTestCase):
# found for a given port identifier
exp_lr_uuid = uuidutils.generate_uuid()
self._mock_router_mapping_db_calls(None)
with mock.patch(nicira_method('query_lrouters'),
with mock.patch(nicira_method('query_lrouters',
module_name='nsxlib.router'),
return_value=[{'uuid': exp_lr_uuid}]):
self._verify_get_nsx_router_id(exp_lr_uuid)
@ -179,6 +180,7 @@ class NsxUtilsTestCase(base.BaseTestCase):
# This test verifies that the function returns None if the mapping
# are not found both in the db and in the backend
self._mock_router_mapping_db_calls(None)
with mock.patch(nicira_method('query_lrouters'),
with mock.patch(nicira_method('query_lrouters',
module_name='nsxlib.router'),
return_value=[]):
self._verify_get_nsx_router_id(None)

View File

@ -22,7 +22,6 @@ import mock
from neutron.common import constants
from neutron.common import exceptions
from neutron.openstack.common import uuidutils
from neutron.plugins.nicira.common import config # noqa
from neutron.plugins.nicira.common import exceptions as nvp_exc
from neutron.plugins.nicira.common import utils
@ -31,7 +30,6 @@ from neutron.plugins.nicira import NvpApiClient
from neutron.plugins.nicira import nvplib
from neutron.tests import base
from neutron.tests.unit.nicira import fake_nvpapiclient
from neutron.tests.unit.nicira import nicira_method
from neutron.tests.unit.nicira import NVPAPI_NAME
from neutron.tests.unit.nicira import STUBS_PATH
from neutron.tests.unit import test_api_v2
@ -74,38 +72,7 @@ class NvplibTestCase(base.BaseTestCase):
return dict((t['scope'], t['tag']) for t in tags)
class TestNvplibNatRules(NvplibTestCase):
def _test_create_lrouter_dnat_rule(self, version):
with mock.patch.object(self.fake_cluster.api_client,
'get_nvp_version',
new=lambda: NvpApiClient.NVPVersion(version)):
tenant_id = 'pippo'
lrouter = nvplib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
tenant_id,
'fake_router',
'192.168.0.1')
nat_rule = nvplib.create_lrouter_dnat_rule(
self.fake_cluster, lrouter['uuid'], '10.0.0.99',
match_criteria={'destination_ip_addresses':
'192.168.0.5'})
uri = nvplib._build_uri_path(nvplib.LROUTERNAT_RESOURCE,
nat_rule['uuid'],
lrouter['uuid'])
resp_obj = nvplib.do_request("GET", uri, cluster=self.fake_cluster)
self.assertEqual('DestinationNatRule', resp_obj['type'])
self.assertEqual('192.168.0.5',
resp_obj['match']['destination_ip_addresses'])
def test_create_lrouter_dnat_rule_v2(self):
self._test_create_lrouter_dnat_rule('2.9')
def test_create_lrouter_dnat_rule_v31(self):
self._test_create_lrouter_dnat_rule('3.1')
class NvplibNegativeTests(base.BaseTestCase):
class NsxlibNegativeBaseTestCase(base.BaseTestCase):
def setUp(self):
# mock nvp api client
@ -132,10 +99,13 @@ class NvplibNegativeTests(base.BaseTestCase):
self.fake_cluster.req_timeout, self.fake_cluster.http_timeout,
self.fake_cluster.retries, self.fake_cluster.redirects)
super(NvplibNegativeTests, self).setUp()
super(NsxlibNegativeBaseTestCase, self).setUp()
self.addCleanup(self.fc.reset_all)
self.addCleanup(self.mock_nvpapi.stop)
class L2GatewayNegativeTestCase(NsxlibNegativeBaseTestCase):
def test_create_l2_gw_service_on_failure(self):
self.assertRaises(nvplib.NvpApiClient.NvpApiException,
nvplib.create_l2_gw_service,
@ -164,35 +134,6 @@ class NvplibNegativeTests(base.BaseTestCase):
'fake-gateway',
'pluto')
def test_create_lrouter_on_failure(self):
self.assertRaises(nvplib.NvpApiClient.NvpApiException,
nvplib.create_lrouter,
self.fake_cluster,
uuidutils.generate_uuid(),
'pluto',
'fake_router',
'my_hop')
def test_delete_lrouter_on_failure(self):
self.assertRaises(nvplib.NvpApiClient.NvpApiException,
nvplib.delete_lrouter,
self.fake_cluster,
'fake_router')
def test_get_lrouter_on_failure(self):
self.assertRaises(nvplib.NvpApiClient.NvpApiException,
nvplib.get_lrouter,
self.fake_cluster,
'fake_router')
def test_update_lrouter_on_failure(self):
self.assertRaises(nvplib.NvpApiClient.NvpApiException,
nvplib.update_lrouter,
self.fake_cluster,
'fake_router',
'pluto',
'new_hop')
class TestNvplibL2Gateway(NvplibTestCase):
@ -404,824 +345,6 @@ class TestNvplibLogicalSwitches(NvplibTestCase):
self.fake_cluster, 'whatever', ['whatever'])
class TestNvplibExplicitLRouters(NvplibTestCase):
def setUp(self):
self.fake_version = '3.2'
super(TestNvplibExplicitLRouters, self).setUp()
def _get_lrouter(self, tenant_id, router_name, router_id, relations=None):
schema = '/ws.v1/schema/RoutingTableRoutingConfig'
router = {'display_name': router_name,
'uuid': router_id,
'tags': [{'scope': 'quantum', 'tag': nvplib.NEUTRON_VERSION},
{'scope': 'os_tid', 'tag': '%s' % tenant_id}],
'distributed': False,
'routing_config': {'type': 'RoutingTableRoutingConfig',
'_schema': schema},
'_schema': schema,
'nat_synchronization_enabled': True,
'replication_mode': 'service',
'type': 'LogicalRouterConfig',
'_href': '/ws.v1/lrouter/%s' % router_id, }
if relations:
router['_relations'] = relations
return router
def _get_single_route(self, router_id, route_id='fake_route_id_0',
prefix='0.0.0.0/0', next_hop_ip='1.1.1.1'):
return {'protocol': 'static',
'_href': '/ws.v1/lrouter/%s/rib/%s' % (router_id, route_id),
'prefix': prefix,
'_schema': '/ws.v1/schema/RoutingTableEntry',
'next_hop_ip': next_hop_ip,
'action': 'accept',
'uuid': route_id}
def test_prepare_body_with_implicit_routing_config(self):
router_name = 'fake_router_name'
tenant_id = 'fake_tenant_id'
neutron_router_id = 'pipita_higuain'
router_type = 'SingleDefaultRouteImplicitRoutingConfig'
route_config = {
'default_route_next_hop': {'gateway_ip_address': 'fake_address',
'type': 'RouterNextHop'}, }
body = nvplib._prepare_lrouter_body(router_name, neutron_router_id,
tenant_id, router_type,
**route_config)
expected = {'display_name': 'fake_router_name',
'routing_config': {
'default_route_next_hop':
{'gateway_ip_address': 'fake_address',
'type': 'RouterNextHop'},
'type': 'SingleDefaultRouteImplicitRoutingConfig'},
'tags': [{'scope': 'os_tid', 'tag': 'fake_tenant_id'},
{'scope': 'q_router_id', 'tag': 'pipita_higuain'},
{'scope': 'quantum',
'tag': nvplib.NEUTRON_VERSION}],
'type': 'LogicalRouterConfig'}
self.assertEqual(expected, body)
def test_prepare_body_without_routing_config(self):
router_name = 'fake_router_name'
tenant_id = 'fake_tenant_id'
router_type = 'RoutingTableRoutingConfig'
neutron_router_id = 'marekiaro_hamsik'
body = nvplib._prepare_lrouter_body(router_name, neutron_router_id,
tenant_id, router_type)
expected = {'display_name': 'fake_router_name',
'routing_config': {'type': 'RoutingTableRoutingConfig'},
'tags': [{'scope': 'os_tid', 'tag': 'fake_tenant_id'},
{'scope': 'q_router_id',
'tag': 'marekiaro_hamsik'},
{'scope': 'quantum',
'tag': nvplib.NEUTRON_VERSION}],
'type': 'LogicalRouterConfig'}
self.assertEqual(expected, body)
def test_get_lrouter(self):
tenant_id = 'fake_tenant_id'
router_name = 'fake_router_name'
router_id = 'fake_router_id'
relations = {
'LogicalRouterStatus':
{'_href': '/ws.v1/lrouter/%s/status' % router_id,
'lport_admin_up_count': 1,
'_schema': '/ws.v1/schema/LogicalRouterStatus',
'lport_count': 1,
'fabric_status': True,
'type': 'LogicalRouterStatus',
'lport_link_up_count': 0, }, }
with mock.patch(nicira_method('do_request'),
return_value=self._get_lrouter(tenant_id,
router_name,
router_id,
relations)):
lrouter = nvplib.get_lrouter(self.fake_cluster, router_id)
self.assertTrue(
lrouter['_relations']['LogicalRouterStatus']['fabric_status'])
def test_create_lrouter(self):
tenant_id = 'fake_tenant_id'
router_name = 'fake_router_name'
router_id = 'fake_router_id'
nexthop_ip = '10.0.0.1'
with mock.patch(nicira_method('do_request'),
return_value=self._get_lrouter(tenant_id,
router_name,
router_id)):
lrouter = nvplib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
tenant_id,
router_name, nexthop_ip)
self.assertEqual(lrouter['routing_config']['type'],
'RoutingTableRoutingConfig')
self.assertNotIn('default_route_next_hop',
lrouter['routing_config'])
def test_update_lrouter_nvp_with_no_routes(self):
router_id = 'fake_router_id'
new_routes = [{"nexthop": "10.0.0.2",
"destination": "169.254.169.0/30"}, ]
nvp_routes = [self._get_single_route(router_id)]
with mock.patch(nicira_method('get_explicit_routes_lrouter'),
return_value=nvp_routes):
with mock.patch(nicira_method('create_explicit_route_lrouter'),
return_value='fake_uuid'):
old_routes = nvplib.update_explicit_routes_lrouter(
self.fake_cluster, router_id, new_routes)
self.assertEqual(old_routes, nvp_routes)
def test_update_lrouter_nvp_with_no_routes_raise_nvp_exception(self):
router_id = 'fake_router_id'
new_routes = [{"nexthop": "10.0.0.2",
"destination": "169.254.169.0/30"}, ]
nvp_routes = [self._get_single_route(router_id)]
with mock.patch(nicira_method('get_explicit_routes_lrouter'),
return_value=nvp_routes):
with mock.patch(nicira_method('create_explicit_route_lrouter'),
side_effect=NvpApiClient.NvpApiException):
self.assertRaises(NvpApiClient.NvpApiException,
nvplib.update_explicit_routes_lrouter,
self.fake_cluster, router_id, new_routes)
def test_update_lrouter_with_routes(self):
router_id = 'fake_router_id'
new_routes = [{"next_hop_ip": "10.0.0.2",
"prefix": "169.254.169.0/30"}, ]
nvp_routes = [self._get_single_route(router_id),
self._get_single_route(router_id, 'fake_route_id_1',
'0.0.0.1/24', '10.0.0.3'),
self._get_single_route(router_id, 'fake_route_id_2',
'0.0.0.2/24', '10.0.0.4'), ]
with mock.patch(nicira_method('get_explicit_routes_lrouter'),
return_value=nvp_routes):
with mock.patch(nicira_method('delete_explicit_route_lrouter'),
return_value=None):
with mock.patch(nicira_method(
'create_explicit_route_lrouter'),
return_value='fake_uuid'):
old_routes = nvplib.update_explicit_routes_lrouter(
self.fake_cluster, router_id, new_routes)
self.assertEqual(old_routes, nvp_routes)
def test_update_lrouter_with_routes_raises_nvp_expception(self):
router_id = 'fake_router_id'
new_routes = [{"nexthop": "10.0.0.2",
"destination": "169.254.169.0/30"}, ]
nvp_routes = [self._get_single_route(router_id),
self._get_single_route(router_id, 'fake_route_id_1',
'0.0.0.1/24', '10.0.0.3'),
self._get_single_route(router_id, 'fake_route_id_2',
'0.0.0.2/24', '10.0.0.4'), ]
with mock.patch(nicira_method('get_explicit_routes_lrouter'),
return_value=nvp_routes):
with mock.patch(nicira_method('delete_explicit_route_lrouter'),
side_effect=NvpApiClient.NvpApiException):
with mock.patch(
nicira_method('create_explicit_route_lrouter'),
return_value='fake_uuid'):
self.assertRaises(
NvpApiClient.NvpApiException,
nvplib.update_explicit_routes_lrouter,
self.fake_cluster, router_id, new_routes)
class TestNvplibLogicalRouters(NvplibTestCase):
def _verify_lrouter(self, res_lrouter,
expected_uuid,
expected_display_name,
expected_nexthop,
expected_tenant_id,
expected_neutron_id=None,
expected_distributed=None):
self.assertEqual(res_lrouter['uuid'], expected_uuid)
nexthop = (res_lrouter['routing_config']
['default_route_next_hop']['gateway_ip_address'])
self.assertEqual(nexthop, expected_nexthop)
router_tags = self._build_tag_dict(res_lrouter['tags'])
self.assertIn('os_tid', router_tags)
self.assertEqual(res_lrouter['display_name'], expected_display_name)
self.assertEqual(expected_tenant_id, router_tags['os_tid'])
if expected_distributed is not None:
self.assertEqual(expected_distributed,
res_lrouter['distributed'])
if expected_neutron_id:
self.assertIn('q_router_id', router_tags)
self.assertEqual(expected_neutron_id, router_tags['q_router_id'])
def test_get_lrouters(self):
lrouter_uuids = [nvplib.create_lrouter(
self.fake_cluster, 'whatever', 'pippo', 'fake-lrouter-%s' % k,
'10.0.0.1')['uuid'] for k in range(3)]
routers = nvplib.get_lrouters(self.fake_cluster, 'pippo')
for router in routers:
self.assertIn(router['uuid'], lrouter_uuids)
def _create_lrouter(self, version, neutron_id=None, distributed=None):
with mock.patch.object(
self.fake_cluster.api_client, 'get_nvp_version',
return_value=NvpApiClient.NVPVersion(version)):
if not neutron_id:
neutron_id = uuidutils.generate_uuid()
lrouter = nvplib.create_lrouter(
self.fake_cluster, neutron_id, 'pippo',
'fake-lrouter', '10.0.0.1', distributed=distributed)
return nvplib.get_lrouter(self.fake_cluster,
lrouter['uuid'])
def test_create_and_get_lrouter_v30(self):
neutron_id = uuidutils.generate_uuid()
res_lrouter = self._create_lrouter('3.0', neutron_id=neutron_id)
self._verify_lrouter(res_lrouter, res_lrouter['uuid'],
'fake-lrouter', '10.0.0.1', 'pippo',
neutron_id)
def test_create_and_get_lrouter_v31_centralized(self):
neutron_id = uuidutils.generate_uuid()
res_lrouter = self._create_lrouter('3.1', neutron_id=neutron_id,
distributed=False)
self._verify_lrouter(res_lrouter, res_lrouter['uuid'],
'fake-lrouter', '10.0.0.1', 'pippo',
expected_neutron_id=neutron_id,
expected_distributed=False)
def test_create_and_get_lrouter_v31_distributed(self):
neutron_id = uuidutils.generate_uuid()
res_lrouter = self._create_lrouter('3.1', neutron_id=neutron_id,
distributed=True)
self._verify_lrouter(res_lrouter, res_lrouter['uuid'],
'fake-lrouter', '10.0.0.1', 'pippo',
expected_neutron_id=neutron_id,
expected_distributed=True)
def test_create_and_get_lrouter_name_exceeds_40chars(self):
neutron_id = uuidutils.generate_uuid()
display_name = '*' * 50
lrouter = nvplib.create_lrouter(self.fake_cluster,
neutron_id,
'pippo',
display_name,
'10.0.0.1')
res_lrouter = nvplib.get_lrouter(self.fake_cluster,
lrouter['uuid'])
self._verify_lrouter(res_lrouter, lrouter['uuid'],
'*' * 40, '10.0.0.1', 'pippo',
expected_neutron_id=neutron_id)
def _test_version_dependent_update_lrouter(self, version):
def foo(*args, **kwargs):
return version
foo_func_dict = {
'update_lrouter': {
2: {-1: foo},
3: {-1: foo, 2: foo}
}
}
with mock.patch.object(self.fake_cluster.api_client,
'get_nvp_version',
return_value=NvpApiClient.NVPVersion(version)):
with mock.patch.dict(nvplib.NVPLIB_FUNC_DICT,
foo_func_dict, clear=True):
return nvplib.update_lrouter(
self.fake_cluster, 'foo_router_id', 'foo_router_name',
'foo_nexthop', routes={'foo_destination': 'foo_address'})
def test_version_dependent_update_lrouter_old_versions(self):
self.assertRaises(nvp_exc.NvpInvalidVersion,
self._test_version_dependent_update_lrouter,
"2.9")
self.assertRaises(nvp_exc.NvpInvalidVersion,
self._test_version_dependent_update_lrouter,
"3.0")
self.assertRaises(nvp_exc.NvpInvalidVersion,
self._test_version_dependent_update_lrouter,
"3.1")
def test_version_dependent_update_lrouter_new_versions(self):
self.assertEqual("3.2",
self._test_version_dependent_update_lrouter("3.2"))
self.assertEqual("4.0",
self._test_version_dependent_update_lrouter("4.0"))
self.assertEqual("4.1",
self._test_version_dependent_update_lrouter("4.1"))
def test_update_lrouter_no_nexthop(self):
neutron_id = uuidutils.generate_uuid()
lrouter = nvplib.create_lrouter(self.fake_cluster,
neutron_id,
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter = nvplib.update_lrouter(self.fake_cluster,
lrouter['uuid'],
'new_name',
None)
res_lrouter = nvplib.get_lrouter(self.fake_cluster,
lrouter['uuid'])
self._verify_lrouter(res_lrouter, lrouter['uuid'],
'new_name', '10.0.0.1', 'pippo',
expected_neutron_id=neutron_id)
def test_update_lrouter(self):
neutron_id = uuidutils.generate_uuid()
lrouter = nvplib.create_lrouter(self.fake_cluster,
neutron_id,
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter = nvplib.update_lrouter(self.fake_cluster,
lrouter['uuid'],
'new_name',
'192.168.0.1')
res_lrouter = nvplib.get_lrouter(self.fake_cluster,
lrouter['uuid'])
self._verify_lrouter(res_lrouter, lrouter['uuid'],
'new_name', '192.168.0.1', 'pippo',
expected_neutron_id=neutron_id)
def test_update_nonexistent_lrouter_raises(self):
self.assertRaises(exceptions.NotFound,
nvplib.update_lrouter,
self.fake_cluster,
'whatever',
'foo', '9.9.9.9')
def test_delete_lrouter(self):
lrouter = nvplib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
nvplib.delete_lrouter(self.fake_cluster, lrouter['uuid'])
self.assertRaises(exceptions.NotFound,
nvplib.get_lrouter,
self.fake_cluster,
lrouter['uuid'])
def test_query_lrouter_ports(self):
lrouter = nvplib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
router_port_uuids = [nvplib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo',
'qp_id_%s' % k, 'port-%s' % k, True,
['192.168.0.%s' % k], '00:11:22:33:44:55')['uuid']
for k in range(3)]
ports = nvplib.query_lrouter_lports(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(ports), 3)
for res_port in ports:
self.assertIn(res_port['uuid'], router_port_uuids)
def test_query_lrouter_lports_nonexistent_lrouter_raises(self):
self.assertRaises(
exceptions.NotFound, nvplib.create_router_lport,
self.fake_cluster, 'booo', 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
def test_create_and_get_lrouter_port(self):
lrouter = nvplib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
nvplib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
ports = nvplib.query_lrouter_lports(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(ports), 1)
res_port = ports[0]
port_tags = self._build_tag_dict(res_port['tags'])
self.assertEqual(['192.168.0.1'], res_port['ip_addresses'])
self.assertIn('os_tid', port_tags)
self.assertIn('q_port_id', port_tags)
self.assertEqual('pippo', port_tags['os_tid'])
self.assertEqual('neutron_port_id', port_tags['q_port_id'])
def test_create_lrouter_port_nonexistent_router_raises(self):
self.assertRaises(
exceptions.NotFound, nvplib.create_router_lport,
self.fake_cluster, 'booo', 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
def test_update_lrouter_port(self):
lrouter = nvplib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter_port = nvplib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
nvplib.update_router_lport(
self.fake_cluster, lrouter['uuid'], lrouter_port['uuid'],
'pippo', 'another_port_id', 'name', False,
['192.168.0.1', '10.10.10.254'])
ports = nvplib.query_lrouter_lports(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(ports), 1)
res_port = ports[0]
port_tags = self._build_tag_dict(res_port['tags'])
self.assertEqual(['192.168.0.1', '10.10.10.254'],
res_port['ip_addresses'])
self.assertEqual('False', res_port['admin_status_enabled'])
self.assertIn('os_tid', port_tags)
self.assertIn('q_port_id', port_tags)
self.assertEqual('pippo', port_tags['os_tid'])
self.assertEqual('another_port_id', port_tags['q_port_id'])
def test_update_lrouter_port_nonexistent_router_raises(self):
self.assertRaises(
exceptions.NotFound, nvplib.update_router_lport,
self.fake_cluster, 'boo-router', 'boo-port', 'pippo',
'neutron_port_id', 'name', True, ['192.168.0.1'])
def test_update_lrouter_port_nonexistent_port_raises(self):
lrouter = nvplib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
self.assertRaises(
exceptions.NotFound, nvplib.update_router_lport,
self.fake_cluster, lrouter['uuid'], 'boo-port', 'pippo',
'neutron_port_id', 'name', True, ['192.168.0.1'])
def test_delete_lrouter_port(self):
lrouter = nvplib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter_port = nvplib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'x', 'y', True, [],
'00:11:22:33:44:55')
ports = nvplib.query_lrouter_lports(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(ports), 1)
nvplib.delete_router_lport(self.fake_cluster, lrouter['uuid'],
lrouter_port['uuid'])
ports = nvplib.query_lrouter_lports(self.fake_cluster, lrouter['uuid'])
self.assertFalse(len(ports))
def test_delete_lrouter_port_nonexistent_router_raises(self):
self.assertRaises(exceptions.NotFound,
nvplib.delete_router_lport,
self.fake_cluster, 'xyz', 'abc')
def test_delete_lrouter_port_nonexistent_port_raises(self):
lrouter = nvplib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
self.assertRaises(exceptions.NotFound,
nvplib.delete_router_lport,
self.fake_cluster, lrouter['uuid'], 'abc')
def test_delete_peer_lrouter_port(self):
lrouter = nvplib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter_port = nvplib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'x', 'y', True, [],
'00:11:22:33:44:55')
def fakegetport(*args, **kwargs):
return {'_relations': {'LogicalPortAttachment':
{'peer_port_uuid': lrouter_port['uuid']}}}
# mock get_port
with mock.patch.object(nvplib, 'get_port', new=fakegetport):
nvplib.delete_peer_router_lport(self.fake_cluster,
lrouter_port['uuid'],
'whatwever', 'whatever')
def test_update_lrouter_port_ips_add_only(self):
lrouter = nvplib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter_port = nvplib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
nvplib.update_lrouter_port_ips(
self.fake_cluster, lrouter['uuid'], lrouter_port['uuid'],
['10.10.10.254'], [])
ports = nvplib.query_lrouter_lports(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(ports), 1)
res_port = ports[0]
self.assertEqual(['10.10.10.254', '192.168.0.1'],
res_port['ip_addresses'])
def test_update_lrouter_port_ips_remove_only(self):
lrouter = nvplib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter_port = nvplib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1', '10.10.10.254'],
'00:11:22:33:44:55')
nvplib.update_lrouter_port_ips(
self.fake_cluster, lrouter['uuid'], lrouter_port['uuid'],
[], ['10.10.10.254'])
ports = nvplib.query_lrouter_lports(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(ports), 1)
res_port = ports[0]
self.assertEqual(['192.168.0.1'], res_port['ip_addresses'])
def test_update_lrouter_port_ips_add_and_remove(self):
lrouter = nvplib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter_port = nvplib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
nvplib.update_lrouter_port_ips(
self.fake_cluster, lrouter['uuid'], lrouter_port['uuid'],
['10.10.10.254'], ['192.168.0.1'])
ports = nvplib.query_lrouter_lports(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(ports), 1)
res_port = ports[0]
self.assertEqual(['10.10.10.254'], res_port['ip_addresses'])
def test_update_lrouter_port_ips_nonexistent_router_raises(self):
self.assertRaises(
nvp_exc.NvpPluginException, nvplib.update_lrouter_port_ips,
self.fake_cluster, 'boo-router', 'boo-port', [], [])
def test_update_lrouter_port_ips_nvp_exception_raises(self):
lrouter = nvplib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter_port = nvplib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
def raise_nvp_exc(*args, **kwargs):
raise NvpApiClient.NvpApiException()
with mock.patch.object(nvplib, 'do_request', new=raise_nvp_exc):
self.assertRaises(
nvp_exc.NvpPluginException, nvplib.update_lrouter_port_ips,
self.fake_cluster, lrouter['uuid'],
lrouter_port['uuid'], [], [])
def test_plug_lrouter_port_patch_attachment(self):
tenant_id = 'pippo'
transport_zones_config = [{'zone_uuid': _uuid(),
'transport_type': 'stt'}]
lswitch = nvplib.create_lswitch(self.fake_cluster,
_uuid(),
tenant_id, 'fake-switch',
transport_zones_config)
lport = nvplib.create_lport(self.fake_cluster, lswitch['uuid'],
tenant_id, 'xyz',
'name', 'device_id', True)
lrouter = nvplib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
tenant_id,
'fake-lrouter',
'10.0.0.1')
lrouter_port = nvplib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1'], '00:11:22:33:44:55:66')
result = nvplib.plug_router_port_attachment(
self.fake_cluster, lrouter['uuid'],
lrouter_port['uuid'],
lport['uuid'], 'PatchAttachment')
self.assertEqual(lport['uuid'],
result['LogicalPortAttachment']['peer_port_uuid'])
def test_plug_lrouter_port_l3_gw_attachment(self):
lrouter = nvplib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter_port = nvplib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1'], '00:11:22:33:44:55:66')
result = nvplib.plug_router_port_attachment(
self.fake_cluster, lrouter['uuid'],
lrouter_port['uuid'],
'gw_att', 'L3GatewayAttachment')
self.assertEqual(
'gw_att',
result['LogicalPortAttachment']['l3_gateway_service_uuid'])
def test_plug_lrouter_port_l3_gw_attachment_with_vlan(self):
lrouter = nvplib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter_port = nvplib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
result = nvplib.plug_router_port_attachment(
self.fake_cluster, lrouter['uuid'],
lrouter_port['uuid'],
'gw_att', 'L3GatewayAttachment', 123)
self.assertEqual(
'gw_att',
result['LogicalPortAttachment']['l3_gateway_service_uuid'])
self.assertEqual(
'123',
result['LogicalPortAttachment']['vlan_id'])
def test_plug_lrouter_port_invalid_attachment_type_raises(self):
lrouter = nvplib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
lrouter_port = nvplib.create_router_lport(
self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
self.assertRaises(nvp_exc.NvpInvalidAttachmentType,
nvplib.plug_router_port_attachment,
self.fake_cluster, lrouter['uuid'],
lrouter_port['uuid'], 'gw_att', 'BadType')
def _test_create_router_snat_rule(self, version):
lrouter = nvplib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
with mock.patch.object(self.fake_cluster.api_client,
'get_nvp_version',
new=lambda: NvpApiClient.NVPVersion(version)):
nvplib.create_lrouter_snat_rule(
self.fake_cluster, lrouter['uuid'],
'10.0.0.2', '10.0.0.2', order=200,
match_criteria={'source_ip_addresses': '192.168.0.24'})
rules = nvplib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(rules), 1)
def test_create_router_snat_rule_v3(self):
self._test_create_router_snat_rule('3.0')
def test_create_router_snat_rule_v2(self):
self._test_create_router_snat_rule('2.0')
def _test_create_router_dnat_rule(self, version, dest_port=None):
lrouter = nvplib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
with mock.patch.object(self.fake_cluster.api_client,
'get_nvp_version',
return_value=NvpApiClient.NVPVersion(version)):
nvplib.create_lrouter_dnat_rule(
self.fake_cluster, lrouter['uuid'], '192.168.0.2', order=200,
dest_port=dest_port,
match_criteria={'destination_ip_addresses': '10.0.0.3'})
rules = nvplib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(rules), 1)
def test_create_router_dnat_rule_v3(self):
self._test_create_router_dnat_rule('3.0')
def test_create_router_dnat_rule_v2(self):
self._test_create_router_dnat_rule('2.0')
def test_create_router_dnat_rule_v2_with_destination_port(self):
self._test_create_router_dnat_rule('2.0', 8080)
def test_create_router_dnat_rule_v3_with_destination_port(self):
self._test_create_router_dnat_rule('3.0', 8080)
def test_create_router_snat_rule_invalid_match_keys_raises(self):
# In this case the version does not make a difference
lrouter = nvplib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
with mock.patch.object(self.fake_cluster.api_client,
'get_nvp_version',
new=lambda: '2.0'):
self.assertRaises(AttributeError,
nvplib.create_lrouter_snat_rule,
self.fake_cluster, lrouter['uuid'],
'10.0.0.2', '10.0.0.2', order=200,
match_criteria={'foo': 'bar'})
def _test_create_router_nosnat_rule(self, version, expected=1):
lrouter = nvplib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
with mock.patch.object(self.fake_cluster.api_client,
'get_nvp_version',
new=lambda: NvpApiClient.NVPVersion(version)):
nvplib.create_lrouter_nosnat_rule(
self.fake_cluster, lrouter['uuid'],
order=100,
match_criteria={'destination_ip_addresses': '192.168.0.0/24'})
rules = nvplib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
# NoSNAT rules do not exist in V2
self.assertEqual(len(rules), expected)
def test_create_router_nosnat_rule_v2(self):
self._test_create_router_nosnat_rule('2.0', expected=0)
def test_create_router_nosnat_rule_v3(self):
self._test_create_router_nosnat_rule('3.0')
def _prepare_nat_rules_for_delete_tests(self):
lrouter = nvplib.create_lrouter(self.fake_cluster,
uuidutils.generate_uuid(),
'pippo',
'fake-lrouter',
'10.0.0.1')
# v2 or v3 makes no difference for this test
with mock.patch.object(self.fake_cluster.api_client,
'get_nvp_version',
new=lambda: NvpApiClient.NVPVersion('2.0')):
nvplib.create_lrouter_snat_rule(
self.fake_cluster, lrouter['uuid'],
'10.0.0.2', '10.0.0.2', order=220,
match_criteria={'source_ip_addresses': '192.168.0.0/24'})
nvplib.create_lrouter_snat_rule(
self.fake_cluster, lrouter['uuid'],
'10.0.0.3', '10.0.0.3', order=200,
match_criteria={'source_ip_addresses': '192.168.0.2/32'})
nvplib.create_lrouter_dnat_rule(
self.fake_cluster, lrouter['uuid'], '192.168.0.2', order=200,
match_criteria={'destination_ip_addresses': '10.0.0.3'})
return lrouter
def test_delete_router_nat_rules_by_match_on_destination_ip(self):
lrouter = self._prepare_nat_rules_for_delete_tests()
rules = nvplib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(rules), 3)
nvplib.delete_nat_rules_by_match(
self.fake_cluster, lrouter['uuid'], 'DestinationNatRule', 1, 1,
destination_ip_addresses='10.0.0.3')
rules = nvplib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(rules), 2)
def test_delete_router_nat_rules_by_match_on_source_ip(self):
lrouter = self._prepare_nat_rules_for_delete_tests()
rules = nvplib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(rules), 3)
nvplib.delete_nat_rules_by_match(
self.fake_cluster, lrouter['uuid'], 'SourceNatRule', 1, 1,
source_ip_addresses='192.168.0.2/32')
rules = nvplib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(rules), 2)
def test_delete_router_nat_rules_by_match_no_match_expected(self):
lrouter = self._prepare_nat_rules_for_delete_tests()
rules = nvplib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(rules), 3)
nvplib.delete_nat_rules_by_match(
self.fake_cluster, lrouter['uuid'], 'SomeWeirdType', 0)
rules = nvplib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(rules), 3)
nvplib.delete_nat_rules_by_match(
self.fake_cluster, lrouter['uuid'], 'DestinationNatRule', 0,
destination_ip_addresses='99.99.99.99')
rules = nvplib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(rules), 3)
def test_delete_router_nat_rules_by_match_no_match_raises(self):
lrouter = self._prepare_nat_rules_for_delete_tests()
rules = nvplib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
self.assertEqual(len(rules), 3)
self.assertRaises(
nvp_exc.NvpNatRuleMismatch,
nvplib.delete_nat_rules_by_match,
self.fake_cluster, lrouter['uuid'],
'SomeWeirdType', 1, 1)
class TestNvplibSecurityProfile(NvplibTestCase):
def test_create_and_get_security_profile(self):
@ -1515,38 +638,6 @@ class TestNvplibClusterManagement(NvplibTestCase):
cluster=self.fake_cluster)
class TestNvplibVersioning(base.BaseTestCase):
def test_function_handling_missing_minor(self):
version = NvpApiClient.NVPVersion('2.0')
function = nvplib.get_function_by_version('create_lrouter', version)
self.assertEqual(nvplib.create_implicit_routing_lrouter,
function)
def test_function_handling_with_both_major_and_minor(self):
version = NvpApiClient.NVPVersion('3.2')
function = nvplib.get_function_by_version('create_lrouter', version)
self.assertEqual(nvplib.create_explicit_routing_lrouter,
function)
def test_function_handling_with_newer_major(self):
version = NvpApiClient.NVPVersion('5.2')
function = nvplib.get_function_by_version('create_lrouter', version)
self.assertEqual(nvplib.create_explicit_routing_lrouter,
function)
def test_function_handling_with_obsolete_major(self):
version = NvpApiClient.NVPVersion('1.2')
self.assertRaises(NotImplementedError,
nvplib.get_function_by_version,
'create_lrouter', version)
def test_function_handling_with_unknown_version(self):
self.assertRaises(NvpApiClient.ServiceUnavailable,
nvplib.get_function_by_version,
'create_lrouter', None)
class NvplibMiscTestCase(base.BaseTestCase):
def test_check_and_truncate_name_with_none(self):
@ -1625,7 +716,3 @@ class NvplibMiscTestCase(base.BaseTestCase):
(nvplib.URI_PREFIX, parent_res,
par_id, child_res, res_id, 'doh'))
self.assertEqual(expected, result)
def _nicira_method(method_name, module_name='nvplib'):
return '%s.%s.%s' % ('neutron.plugins.nicira', module_name, method_name)