Merge "Add support for the extra route extension in the NVP plugin."
This commit is contained in:
commit
e13014ec7e
@ -42,11 +42,13 @@ from neutron.db import agentschedulers_db
|
|||||||
from neutron.db import api as db
|
from neutron.db import api as db
|
||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
from neutron.db import dhcp_rpc_base
|
from neutron.db import dhcp_rpc_base
|
||||||
|
from neutron.db import extraroute_db
|
||||||
from neutron.db import l3_db
|
from neutron.db import l3_db
|
||||||
from neutron.db import models_v2
|
from neutron.db import models_v2
|
||||||
from neutron.db import portsecurity_db
|
from neutron.db import portsecurity_db
|
||||||
from neutron.db import quota_db # noqa
|
from neutron.db import quota_db # noqa
|
||||||
from neutron.db import securitygroups_db
|
from neutron.db import securitygroups_db
|
||||||
|
from neutron.extensions import extraroute
|
||||||
from neutron.extensions import l3
|
from neutron.extensions import l3
|
||||||
from neutron.extensions import portsecurity as psec
|
from neutron.extensions import portsecurity as psec
|
||||||
from neutron.extensions import providernet as pnet
|
from neutron.extensions import providernet as pnet
|
||||||
@ -124,7 +126,7 @@ class NVPRpcCallbacks(dhcp_rpc_base.DhcpRpcCallbackMixin):
|
|||||||
|
|
||||||
|
|
||||||
class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
l3_db.L3_NAT_db_mixin,
|
extraroute_db.ExtraRoute_db_mixin,
|
||||||
portsecurity_db.PortSecurityDbMixin,
|
portsecurity_db.PortSecurityDbMixin,
|
||||||
securitygroups_db.SecurityGroupDbMixin,
|
securitygroups_db.SecurityGroupDbMixin,
|
||||||
mac_db.MacLearningDbMixin,
|
mac_db.MacLearningDbMixin,
|
||||||
@ -139,7 +141,8 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
functionality using NVP.
|
functionality using NVP.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
supported_extension_aliases = ["mac-learning",
|
supported_extension_aliases = ["extraroute",
|
||||||
|
"mac-learning",
|
||||||
"network-gateway",
|
"network-gateway",
|
||||||
"nvp-qos",
|
"nvp-qos",
|
||||||
"port-security",
|
"port-security",
|
||||||
@ -1458,7 +1461,7 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
self._update_router_gw_info(context, router_db['id'], gw_info)
|
self._update_router_gw_info(context, router_db['id'], gw_info)
|
||||||
return self._make_router_dict(router_db)
|
return self._make_router_dict(router_db)
|
||||||
|
|
||||||
def update_router(self, context, id, router):
|
def update_router(self, context, router_id, router):
|
||||||
# Either nexthop is updated or should be kept as it was before
|
# Either nexthop is updated or should be kept as it was before
|
||||||
r = router['router']
|
r = router['router']
|
||||||
nexthop = None
|
nexthop = None
|
||||||
@ -1479,22 +1482,45 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
ext_subnet = ext_net.subnets[0]
|
ext_subnet = ext_net.subnets[0]
|
||||||
nexthop = ext_subnet.gateway_ip
|
nexthop = ext_subnet.gateway_ip
|
||||||
try:
|
try:
|
||||||
nvplib.update_lrouter(self.cluster, id,
|
for route in r.get('routes', []):
|
||||||
router['router'].get('name'), nexthop)
|
if route['destination'] == '0.0.0.0/0':
|
||||||
|
msg = _("'routes' cannot contain route '0.0.0.0/0', "
|
||||||
|
"this must be updated through the default "
|
||||||
|
"gateway attribute")
|
||||||
|
raise q_exc.BadRequest(resource='router', msg=msg)
|
||||||
|
previous_routes = nvplib.update_lrouter(
|
||||||
|
self.cluster, router_id, r.get('name'),
|
||||||
|
nexthop, routes=r.get('routes'))
|
||||||
# NOTE(salv-orlando): The exception handling below is not correct, but
|
# NOTE(salv-orlando): The exception handling below is not correct, but
|
||||||
# unfortunately nvplib raises a neutron notfound exception when an
|
# unfortunately nvplib raises a neutron notfound exception when an
|
||||||
# object is not found in the underlying backend
|
# object is not found in the underlying backend
|
||||||
except q_exc.NotFound:
|
except q_exc.NotFound:
|
||||||
# Put the router in ERROR status
|
# Put the router in ERROR status
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
router_db = self._get_router(context, id)
|
router_db = self._get_router(context, router_id)
|
||||||
router_db['status'] = constants.NET_STATUS_ERROR
|
router_db['status'] = constants.NET_STATUS_ERROR
|
||||||
raise nvp_exc.NvpPluginException(
|
raise nvp_exc.NvpPluginException(
|
||||||
err_msg=_("Logical router %s not found on NVP Platform") % id)
|
err_msg=_("Logical router %s not found "
|
||||||
|
"on NVP Platform") % router_id)
|
||||||
except NvpApiClient.NvpApiException:
|
except NvpApiClient.NvpApiException:
|
||||||
raise nvp_exc.NvpPluginException(
|
raise nvp_exc.NvpPluginException(
|
||||||
err_msg=_("Unable to update logical router on NVP Platform"))
|
err_msg=_("Unable to update logical router on NVP Platform"))
|
||||||
return super(NvpPluginV2, self).update_router(context, id, router)
|
except nvp_exc.NvpInvalidVersion:
|
||||||
|
msg = _("Request cannot contain 'routes' with the NVP "
|
||||||
|
"platform currently in execution. Please, try "
|
||||||
|
"without specifying the static routes.")
|
||||||
|
LOG.exception(msg)
|
||||||
|
raise q_exc.BadRequest(resource='router', msg=msg)
|
||||||
|
try:
|
||||||
|
return super(NvpPluginV2, self).update_router(context,
|
||||||
|
router_id, router)
|
||||||
|
except (extraroute.InvalidRoutes,
|
||||||
|
extraroute.RouterInterfaceInUseByRoute,
|
||||||
|
extraroute.RoutesExhausted):
|
||||||
|
with excutils.save_and_reraise_exception():
|
||||||
|
# revert changes made to NVP
|
||||||
|
nvplib.update_explicit_routes_lrouter(
|
||||||
|
self.cluster, router_id, previous_routes)
|
||||||
|
|
||||||
def delete_router(self, context, id):
|
def delete_router(self, context, id):
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
|
@ -31,12 +31,24 @@ def _find_nvp_version_in_headers(headers):
|
|||||||
for (header_name, header_value) in (headers or ()):
|
for (header_name, header_value) in (headers or ()):
|
||||||
try:
|
try:
|
||||||
if header_name == 'server':
|
if header_name == 'server':
|
||||||
return header_value.split('/')[1]
|
return NVPVersion(header_value.split('/')[1])
|
||||||
except IndexError:
|
except IndexError:
|
||||||
LOG.warning(_("Unable to fetch NVP version from response "
|
LOG.warning(_("Unable to fetch NVP version from response "
|
||||||
"headers:%s"), headers)
|
"headers:%s"), headers)
|
||||||
|
|
||||||
|
|
||||||
|
class NVPVersion(object):
|
||||||
|
"""Abstracts NVP version by exposing major and minor."""
|
||||||
|
|
||||||
|
def __init__(self, nvp_version):
|
||||||
|
self.full_version = nvp_version.split('.')
|
||||||
|
self.major = int(self.full_version[0])
|
||||||
|
self.minor = int(self.full_version[1])
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '.'.join(self.full_version)
|
||||||
|
|
||||||
|
|
||||||
class NVPApiHelper(client_eventlet.NvpApiClientEventlet):
|
class NVPApiHelper(client_eventlet.NvpApiClientEventlet):
|
||||||
'''API helper class.
|
'''API helper class.
|
||||||
|
|
||||||
@ -153,10 +165,13 @@ class NVPApiHelper(client_eventlet.NvpApiClientEventlet):
|
|||||||
|
|
||||||
def get_nvp_version(self):
|
def get_nvp_version(self):
|
||||||
if not self._nvp_version:
|
if not self._nvp_version:
|
||||||
# generate a simple request (/ws.v1/log)
|
# Determine the NVP version by querying the control
|
||||||
# this will cause nvp_version to be fetched
|
# cluster nodes. Currently, the version will be the
|
||||||
# don't bother about response
|
# one of the server that responds.
|
||||||
self.request('GET', '/ws.v1/log')
|
self.request('GET', '/ws.v1/control-cluster/node')
|
||||||
|
if not self._nvp_version:
|
||||||
|
LOG.error(_('Unable to determine NVP version. '
|
||||||
|
'Plugin might not work as expected.'))
|
||||||
return self._nvp_version
|
return self._nvp_version
|
||||||
|
|
||||||
def fourZeroFour(self):
|
def fourZeroFour(self):
|
||||||
|
@ -190,8 +190,9 @@ class NvpApiRequest(object):
|
|||||||
# the conn to be released with is_conn_error == True
|
# the conn to be released with is_conn_error == True
|
||||||
# which puts the conn on the back of the client's priority
|
# which puts the conn on the back of the client's priority
|
||||||
# queue.
|
# queue.
|
||||||
if response.status >= 500:
|
if (response.status == httplib.INTERNAL_SERVER_ERROR and
|
||||||
LOG.warn(_("[%(rid)d] Request '%(method) %(url)s' "
|
response.status > httplib.NOT_IMPLEMENTED):
|
||||||
|
LOG.warn(_("[%(rid)d] Request '%(method)s %(url)s' "
|
||||||
"received: %(status)s"),
|
"received: %(status)s"),
|
||||||
{'rid': self._rid(), 'method': self._method,
|
{'rid': self._rid(), 'method': self._method,
|
||||||
'url': self._url, 'status': response.status})
|
'url': self._url, 'status': response.status})
|
||||||
|
@ -24,6 +24,10 @@ class NvpPluginException(q_exc.NeutronException):
|
|||||||
message = _("An unexpected error occurred in the NVP Plugin:%(err_msg)s")
|
message = _("An unexpected error occurred in the NVP Plugin:%(err_msg)s")
|
||||||
|
|
||||||
|
|
||||||
|
class NvpInvalidVersion(NvpPluginException):
|
||||||
|
message = _("Unable to fulfill request with version %(version)s.")
|
||||||
|
|
||||||
|
|
||||||
class NvpInvalidConnection(NvpPluginException):
|
class NvpInvalidConnection(NvpPluginException):
|
||||||
message = _("Invalid NVP connection parameters: %(conn_params)s")
|
message = _("Invalid NVP connection parameters: %(conn_params)s")
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ from oslo.config import cfg
|
|||||||
# no neutron-specific logic in it
|
# no neutron-specific logic in it
|
||||||
from neutron.common import constants
|
from neutron.common import constants
|
||||||
from neutron.common import exceptions as exception
|
from neutron.common import exceptions as exception
|
||||||
|
from neutron.openstack.common import excutils
|
||||||
from neutron.openstack.common import log
|
from neutron.openstack.common import log
|
||||||
from neutron.plugins.nicira.common import (
|
from neutron.plugins.nicira.common import (
|
||||||
exceptions as nvp_exc)
|
exceptions as nvp_exc)
|
||||||
@ -48,11 +49,12 @@ URI_PREFIX = "/ws.v1"
|
|||||||
LSWITCH_RESOURCE = "lswitch"
|
LSWITCH_RESOURCE = "lswitch"
|
||||||
LSWITCHPORT_RESOURCE = "lport/%s" % LSWITCH_RESOURCE
|
LSWITCHPORT_RESOURCE = "lport/%s" % LSWITCH_RESOURCE
|
||||||
LROUTER_RESOURCE = "lrouter"
|
LROUTER_RESOURCE = "lrouter"
|
||||||
# Current neutron version
|
|
||||||
LROUTERPORT_RESOURCE = "lport/%s" % LROUTER_RESOURCE
|
LROUTERPORT_RESOURCE = "lport/%s" % LROUTER_RESOURCE
|
||||||
|
LROUTERRIB_RESOURCE = "rib/%s" % LROUTER_RESOURCE
|
||||||
LROUTERNAT_RESOURCE = "nat/lrouter"
|
LROUTERNAT_RESOURCE = "nat/lrouter"
|
||||||
LQUEUE_RESOURCE = "lqueue"
|
LQUEUE_RESOURCE = "lqueue"
|
||||||
GWSERVICE_RESOURCE = "gateway-service"
|
GWSERVICE_RESOURCE = "gateway-service"
|
||||||
|
# Current neutron version
|
||||||
NEUTRON_VERSION = "2013.1"
|
NEUTRON_VERSION = "2013.1"
|
||||||
# Other constants for NVP resource
|
# Other constants for NVP resource
|
||||||
MAX_DISPLAY_NAME_LEN = 40
|
MAX_DISPLAY_NAME_LEN = 40
|
||||||
@ -74,16 +76,29 @@ taken_context_ids = []
|
|||||||
_lqueue_cache = {}
|
_lqueue_cache = {}
|
||||||
|
|
||||||
|
|
||||||
def version_dependent(func):
|
def version_dependent(wrapped_func):
|
||||||
func_name = func.__name__
|
func_name = wrapped_func.__name__
|
||||||
|
|
||||||
def dispatch_version_dependent_function(cluster, *args, **kwargs):
|
def dispatch_version_dependent_function(cluster, *args, **kwargs):
|
||||||
nvp_ver = cluster.api_client.get_nvp_version()
|
# Call the wrapper function, in case we need to
|
||||||
if nvp_ver:
|
# run validation checks regarding versions. It
|
||||||
ver_major = int(nvp_ver.split('.')[0])
|
# should return the NVP version
|
||||||
real_func = NVPLIB_FUNC_DICT[func_name][ver_major]
|
v = (wrapped_func(cluster, *args, **kwargs) or
|
||||||
|
cluster.api_client.get_nvp_version())
|
||||||
|
if v:
|
||||||
|
func = (NVPLIB_FUNC_DICT[func_name][v.major].get(v.minor) or
|
||||||
|
NVPLIB_FUNC_DICT[func_name][v.major]['default'])
|
||||||
|
if func is None:
|
||||||
|
LOG.error(_('NVP version %(ver)s does not support method '
|
||||||
|
'%(fun)s.') % {'ver': v, 'fun': func_name})
|
||||||
|
raise NotImplementedError()
|
||||||
|
else:
|
||||||
|
raise NvpApiClient.ServiceUnavailable('NVP version is not set. '
|
||||||
|
'Unable to complete request'
|
||||||
|
'correctly. Check log for '
|
||||||
|
'NVP communication errors.')
|
||||||
func_kwargs = kwargs
|
func_kwargs = kwargs
|
||||||
arg_spec = inspect.getargspec(real_func)
|
arg_spec = inspect.getargspec(func)
|
||||||
if not arg_spec.keywords and not arg_spec.varargs:
|
if not arg_spec.keywords and not arg_spec.varargs:
|
||||||
# drop args unknown to function from func_args
|
# drop args unknown to function from func_args
|
||||||
arg_set = set(func_kwargs.keys())
|
arg_set = set(func_kwargs.keys())
|
||||||
@ -91,7 +106,7 @@ def version_dependent(func):
|
|||||||
del func_kwargs[arg]
|
del func_kwargs[arg]
|
||||||
# NOTE(salvatore-orlando): shall we fail here if a required
|
# NOTE(salvatore-orlando): shall we fail here if a required
|
||||||
# argument is not passed, or let the called function raise?
|
# argument is not passed, or let the called function raise?
|
||||||
real_func(cluster, *args, **func_kwargs)
|
return func(cluster, *args, **func_kwargs)
|
||||||
|
|
||||||
return dispatch_version_dependent_function
|
return dispatch_version_dependent_function
|
||||||
|
|
||||||
@ -284,7 +299,22 @@ def create_l2_gw_service(cluster, tenant_id, display_name, devices):
|
|||||||
json.dumps(gwservice_obj), cluster=cluster)
|
json.dumps(gwservice_obj), cluster=cluster)
|
||||||
|
|
||||||
|
|
||||||
def create_lrouter(cluster, tenant_id, display_name, nexthop):
|
def _prepare_lrouter_body(name, tenant_id, router_type, **kwargs):
|
||||||
|
body = {
|
||||||
|
"display_name": _check_and_truncate_name(name),
|
||||||
|
"tags": [{"tag": tenant_id, "scope": "os_tid"},
|
||||||
|
{"tag": NEUTRON_VERSION, "scope": "quantum"}],
|
||||||
|
"routing_config": {
|
||||||
|
"type": router_type
|
||||||
|
},
|
||||||
|
"type": "LogicalRouterConfig"
|
||||||
|
}
|
||||||
|
if kwargs:
|
||||||
|
body["routing_config"].update(kwargs)
|
||||||
|
return body
|
||||||
|
|
||||||
|
|
||||||
|
def create_implicit_routing_lrouter(cluster, tenant_id, display_name, nexthop):
|
||||||
"""Create a NVP logical router on the specified cluster.
|
"""Create a NVP logical router on the specified cluster.
|
||||||
|
|
||||||
:param cluster: The target NVP cluster
|
:param cluster: The target NVP cluster
|
||||||
@ -295,25 +325,36 @@ def create_lrouter(cluster, tenant_id, display_name, nexthop):
|
|||||||
:raise NvpApiException: if there is a problem while communicating
|
:raise NvpApiException: if there is a problem while communicating
|
||||||
with the NVP controller
|
with the NVP controller
|
||||||
"""
|
"""
|
||||||
display_name = _check_and_truncate_name(display_name)
|
implicit_routing_config = {
|
||||||
tags = [{"tag": tenant_id, "scope": "os_tid"},
|
"default_route_next_hop": {
|
||||||
{"tag": NEUTRON_VERSION, "scope": "quantum"}]
|
"gateway_ip_address": nexthop,
|
||||||
lrouter_obj = {
|
"type": "RouterNextHop"
|
||||||
"display_name": display_name,
|
|
||||||
"tags": tags,
|
|
||||||
"routing_config": {
|
|
||||||
"default_route_next_hop": {
|
|
||||||
"gateway_ip_address": nexthop,
|
|
||||||
"type": "RouterNextHop"
|
|
||||||
},
|
|
||||||
"type": "SingleDefaultRouteImplicitRoutingConfig"
|
|
||||||
},
|
},
|
||||||
"type": "LogicalRouterConfig"
|
|
||||||
}
|
}
|
||||||
|
lrouter_obj = _prepare_lrouter_body(
|
||||||
|
display_name, tenant_id,
|
||||||
|
"SingleDefaultRouteImplicitRoutingConfig",
|
||||||
|
**implicit_routing_config)
|
||||||
return do_request(HTTP_POST, _build_uri_path(LROUTER_RESOURCE),
|
return do_request(HTTP_POST, _build_uri_path(LROUTER_RESOURCE),
|
||||||
json.dumps(lrouter_obj), cluster=cluster)
|
json.dumps(lrouter_obj), cluster=cluster)
|
||||||
|
|
||||||
|
|
||||||
|
def create_explicit_routing_lrouter(cluster, tenant_id,
|
||||||
|
display_name, nexthop):
|
||||||
|
lrouter_obj = _prepare_lrouter_body(
|
||||||
|
display_name, tenant_id, "RoutingTableRoutingConfig")
|
||||||
|
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):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def delete_lrouter(cluster, lrouter_id):
|
def delete_lrouter(cluster, lrouter_id):
|
||||||
do_request(HTTP_DELETE, _build_uri_path(LROUTER_RESOURCE,
|
do_request(HTTP_DELETE, _build_uri_path(LROUTER_RESOURCE,
|
||||||
resource_id=lrouter_id),
|
resource_id=lrouter_id),
|
||||||
@ -381,8 +422,8 @@ def update_l2_gw_service(cluster, gateway_id, display_name):
|
|||||||
json.dumps(gwservice_obj), cluster=cluster)
|
json.dumps(gwservice_obj), cluster=cluster)
|
||||||
|
|
||||||
|
|
||||||
def update_lrouter(cluster, lrouter_id, display_name, nexthop):
|
def update_implicit_routing_lrouter(cluster, r_id, display_name, nexthop):
|
||||||
lrouter_obj = get_lrouter(cluster, lrouter_id)
|
lrouter_obj = get_lrouter(cluster, r_id)
|
||||||
if not display_name and not nexthop:
|
if not display_name and not nexthop:
|
||||||
# Nothing to update
|
# Nothing to update
|
||||||
return lrouter_obj
|
return lrouter_obj
|
||||||
@ -395,11 +436,150 @@ def update_lrouter(cluster, lrouter_id, display_name, nexthop):
|
|||||||
if nh_element:
|
if nh_element:
|
||||||
nh_element["gateway_ip_address"] = nexthop
|
nh_element["gateway_ip_address"] = nexthop
|
||||||
return do_request(HTTP_PUT, _build_uri_path(LROUTER_RESOURCE,
|
return do_request(HTTP_PUT, _build_uri_path(LROUTER_RESOURCE,
|
||||||
resource_id=lrouter_id),
|
resource_id=r_id),
|
||||||
json.dumps(lrouter_obj),
|
json.dumps(lrouter_obj),
|
||||||
cluster=cluster)
|
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:
|
||||||
|
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 < 3) or (v.major >= 3 and v.minor < 2):
|
||||||
|
raise nvp_exc.NvpInvalidVersion(version=v)
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
def delete_network(cluster, net_id, lswitch_id):
|
def delete_network(cluster, net_id, lswitch_id):
|
||||||
delete_networks(cluster, net_id, [lswitch_id])
|
delete_networks(cluster, net_id, [lswitch_id])
|
||||||
|
|
||||||
@ -1027,14 +1207,27 @@ def update_lrouter_port_ips(cluster, lrouter_id, lport_id,
|
|||||||
raise nvp_exc.NvpPluginException(err_msg=msg)
|
raise nvp_exc.NvpPluginException(err_msg=msg)
|
||||||
|
|
||||||
|
|
||||||
# TODO(salvatore-orlando): Also handle changes in minor versions
|
|
||||||
NVPLIB_FUNC_DICT = {
|
NVPLIB_FUNC_DICT = {
|
||||||
'create_lrouter_dnat_rule': {2: create_lrouter_dnat_rule_v2,
|
'create_lrouter': {
|
||||||
3: create_lrouter_dnat_rule_v3},
|
2: {'default': create_implicit_routing_lrouter, },
|
||||||
'create_lrouter_snat_rule': {2: create_lrouter_snat_rule_v2,
|
3: {'default': create_implicit_routing_lrouter,
|
||||||
3: create_lrouter_snat_rule_v3},
|
2: create_explicit_routing_lrouter, }, },
|
||||||
'create_lrouter_nosnat_rule': {2: create_lrouter_nosnat_rule_v2,
|
'update_lrouter': {
|
||||||
3: create_lrouter_nosnat_rule_v3}
|
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, }, },
|
||||||
|
'get_default_route_explicit_routing_lrouter': {
|
||||||
|
3: {2: get_default_route_explicit_routing_lrouter_v32,
|
||||||
|
3: get_default_route_explicit_routing_lrouter_v33, }, },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ from neutron import context
|
|||||||
from neutron.extensions import agent
|
from neutron.extensions import agent
|
||||||
from neutron.openstack.common import log as logging
|
from neutron.openstack.common import log as logging
|
||||||
import neutron.plugins.nicira as nvp_plugin
|
import neutron.plugins.nicira as nvp_plugin
|
||||||
|
from neutron.plugins.nicira.NvpApiClient import NVPVersion
|
||||||
from neutron.tests.unit.nicira import fake_nvpapiclient
|
from neutron.tests.unit.nicira import fake_nvpapiclient
|
||||||
from neutron.tests.unit import test_db_plugin
|
from neutron.tests.unit import test_db_plugin
|
||||||
|
|
||||||
@ -84,7 +85,7 @@ class MacLearningDBTestCase(test_db_plugin.NeutronDbPluginV2TestCase):
|
|||||||
return self.fc.fake_request(*args, **kwargs)
|
return self.fc.fake_request(*args, **kwargs)
|
||||||
|
|
||||||
# Emulate tests against NVP 2.x
|
# Emulate tests against NVP 2.x
|
||||||
instance.return_value.get_nvp_version.return_value = "2.999"
|
instance.return_value.get_nvp_version.return_value = NVPVersion("3.0")
|
||||||
instance.return_value.request.side_effect = _fake_request
|
instance.return_value.request.side_effect = _fake_request
|
||||||
cfg.CONF.set_override('metadata_mode', None, 'NVP')
|
cfg.CONF.set_override('metadata_mode', None, 'NVP')
|
||||||
self.addCleanup(self.fc.reset_all)
|
self.addCleanup(self.fc.reset_all)
|
||||||
|
@ -34,6 +34,7 @@ from neutron.plugins.nicira.extensions import nvp_networkgw
|
|||||||
from neutron.plugins.nicira.extensions import nvp_qos as ext_qos
|
from neutron.plugins.nicira.extensions import nvp_qos as ext_qos
|
||||||
from neutron.plugins.nicira import NeutronPlugin
|
from neutron.plugins.nicira import NeutronPlugin
|
||||||
from neutron.plugins.nicira import NvpApiClient
|
from neutron.plugins.nicira import NvpApiClient
|
||||||
|
from neutron.plugins.nicira.NvpApiClient import NVPVersion
|
||||||
from neutron.plugins.nicira import nvplib
|
from neutron.plugins.nicira import nvplib
|
||||||
from neutron.tests.unit.nicira import fake_nvpapiclient
|
from neutron.tests.unit.nicira import fake_nvpapiclient
|
||||||
import neutron.tests.unit.nicira.test_networkgw as test_l2_gw
|
import neutron.tests.unit.nicira.test_networkgw as test_l2_gw
|
||||||
@ -86,7 +87,7 @@ class NiciraPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
|
|||||||
return self.fc.fake_request(*args, **kwargs)
|
return self.fc.fake_request(*args, **kwargs)
|
||||||
|
|
||||||
# Emulate tests against NVP 2.x
|
# Emulate tests against NVP 2.x
|
||||||
instance.return_value.get_nvp_version.return_value = "2.999"
|
instance.return_value.get_nvp_version.return_value = NVPVersion("2.9")
|
||||||
instance.return_value.request.side_effect = _fake_request
|
instance.return_value.request.side_effect = _fake_request
|
||||||
super(NiciraPluginV2TestCase, self).setUp(self._plugin_name)
|
super(NiciraPluginV2TestCase, self).setUp(self._plugin_name)
|
||||||
cfg.CONF.set_override('metadata_mode', None, 'NVP')
|
cfg.CONF.set_override('metadata_mode', None, 'NVP')
|
||||||
|
@ -44,6 +44,9 @@ class NvplibTestCase(base.BaseTestCase):
|
|||||||
% NICIRA_PKG_PATH, autospec=True)
|
% NICIRA_PKG_PATH, autospec=True)
|
||||||
instance = self.mock_nvpapi.start()
|
instance = self.mock_nvpapi.start()
|
||||||
instance.return_value.login.return_value = "the_cookie"
|
instance.return_value.login.return_value = "the_cookie"
|
||||||
|
fake_version = getattr(self, 'fake_version', "2.9")
|
||||||
|
instance.return_value.get_nvp_version.return_value = (
|
||||||
|
NvpApiClient.NVPVersion(fake_version))
|
||||||
|
|
||||||
def _fake_request(*args, **kwargs):
|
def _fake_request(*args, **kwargs):
|
||||||
return self.fc.fake_request(*args, **kwargs)
|
return self.fc.fake_request(*args, **kwargs)
|
||||||
@ -69,35 +72,32 @@ class NvplibTestCase(base.BaseTestCase):
|
|||||||
|
|
||||||
class TestNvplibNatRules(NvplibTestCase):
|
class TestNvplibNatRules(NvplibTestCase):
|
||||||
|
|
||||||
def _test_create_lrouter_dnat_rule(self, func):
|
def _test_create_lrouter_dnat_rule(self, version):
|
||||||
tenant_id = 'pippo'
|
with mock.patch.object(self.fake_cluster.api_client,
|
||||||
lrouter = nvplib.create_lrouter(self.fake_cluster,
|
'get_nvp_version',
|
||||||
tenant_id,
|
new=lambda: NvpApiClient.NVPVersion(version)):
|
||||||
'fake_router',
|
tenant_id = 'pippo'
|
||||||
'192.168.0.1')
|
lrouter = nvplib.create_lrouter(self.fake_cluster,
|
||||||
nat_rule = func(self.fake_cluster, lrouter['uuid'], '10.0.0.99',
|
tenant_id,
|
||||||
match_criteria={'destination_ip_addresses':
|
'fake_router',
|
||||||
'192.168.0.5'})
|
'192.168.0.1')
|
||||||
uri = nvplib._build_uri_path(nvplib.LROUTERNAT_RESOURCE,
|
nat_rule = nvplib.create_lrouter_dnat_rule(
|
||||||
nat_rule['uuid'],
|
self.fake_cluster, lrouter['uuid'], '10.0.0.99',
|
||||||
lrouter['uuid'])
|
match_criteria={'destination_ip_addresses':
|
||||||
return nvplib.do_request("GET", uri, cluster=self.fake_cluster)
|
'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):
|
def test_create_lrouter_dnat_rule_v2(self):
|
||||||
resp_obj = self._test_create_lrouter_dnat_rule(
|
self._test_create_lrouter_dnat_rule('2.9')
|
||||||
nvplib.create_lrouter_dnat_rule_v2)
|
|
||||||
self.assertEqual('DestinationNatRule', resp_obj['type'])
|
|
||||||
self.assertEqual('192.168.0.5',
|
|
||||||
resp_obj['match']['destination_ip_addresses'])
|
|
||||||
|
|
||||||
def test_create_lrouter_dnat_rule_v3(self):
|
def test_create_lrouter_dnat_rule_v31(self):
|
||||||
resp_obj = self._test_create_lrouter_dnat_rule(
|
self._test_create_lrouter_dnat_rule('3.1')
|
||||||
nvplib.create_lrouter_dnat_rule_v2)
|
|
||||||
# TODO(salvatore-orlando): Extend FakeNVPApiClient to deal with
|
|
||||||
# different versions of NVP API
|
|
||||||
self.assertEqual('DestinationNatRule', resp_obj['type'])
|
|
||||||
self.assertEqual('192.168.0.5',
|
|
||||||
resp_obj['match']['destination_ip_addresses'])
|
|
||||||
|
|
||||||
|
|
||||||
class NvplibNegativeTests(base.BaseTestCase):
|
class NvplibNegativeTests(base.BaseTestCase):
|
||||||
@ -110,6 +110,10 @@ class NvplibNegativeTests(base.BaseTestCase):
|
|||||||
% NICIRA_PKG_PATH, autospec=True)
|
% NICIRA_PKG_PATH, autospec=True)
|
||||||
instance = self.mock_nvpapi.start()
|
instance = self.mock_nvpapi.start()
|
||||||
instance.return_value.login.return_value = "the_cookie"
|
instance.return_value.login.return_value = "the_cookie"
|
||||||
|
# Choose 2.9, but the version is irrelevant for the aim of
|
||||||
|
# these tests as calls are throwing up errors anyway
|
||||||
|
self.fake_version = NvpApiClient.NVPVersion('2.9')
|
||||||
|
instance.return_value.get_nvp_version.return_value = self.fake_version
|
||||||
|
|
||||||
def _faulty_request(*args, **kwargs):
|
def _faulty_request(*args, **kwargs):
|
||||||
raise nvplib.NvpApiClient.NvpApiException
|
raise nvplib.NvpApiClient.NvpApiException
|
||||||
@ -365,6 +369,187 @@ class TestNvplibLogicalSwitches(NvplibTestCase):
|
|||||||
self.fake_cluster, 'whatever', ['whatever'])
|
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': '2013.1'},
|
||||||
|
{'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'
|
||||||
|
router_type = 'SingleDefaultRouteImplicitRoutingConfig'
|
||||||
|
route_config = {
|
||||||
|
'default_route_next_hop': {'gateway_ip_address': 'fake_address',
|
||||||
|
'type': 'RouterNextHop'}, }
|
||||||
|
body = nvplib._prepare_lrouter_body(router_name, 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': 'quantum', 'tag': '2013.1'}],
|
||||||
|
'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'
|
||||||
|
body = nvplib._prepare_lrouter_body(router_name, tenant_id,
|
||||||
|
router_type)
|
||||||
|
expected = {'display_name': 'fake_router_name',
|
||||||
|
'routing_config': {'type': 'RoutingTableRoutingConfig'},
|
||||||
|
'tags': [{'scope': 'os_tid', 'tag': 'fake_tenant_id'},
|
||||||
|
{'scope': 'quantum', 'tag': '2013.1'}],
|
||||||
|
'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, 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):
|
class TestNvplibLogicalRouters(NvplibTestCase):
|
||||||
|
|
||||||
def _verify_lrouter(self, res_lrouter,
|
def _verify_lrouter(self, res_lrouter,
|
||||||
@ -733,7 +918,7 @@ class TestNvplibLogicalRouters(NvplibTestCase):
|
|||||||
'10.0.0.1')
|
'10.0.0.1')
|
||||||
with mock.patch.object(self.fake_cluster.api_client,
|
with mock.patch.object(self.fake_cluster.api_client,
|
||||||
'get_nvp_version',
|
'get_nvp_version',
|
||||||
new=lambda: version):
|
new=lambda: NvpApiClient.NVPVersion(version)):
|
||||||
nvplib.create_lrouter_snat_rule(
|
nvplib.create_lrouter_snat_rule(
|
||||||
self.fake_cluster, lrouter['uuid'],
|
self.fake_cluster, lrouter['uuid'],
|
||||||
'10.0.0.2', '10.0.0.2', order=200,
|
'10.0.0.2', '10.0.0.2', order=200,
|
||||||
@ -754,7 +939,7 @@ class TestNvplibLogicalRouters(NvplibTestCase):
|
|||||||
'10.0.0.1')
|
'10.0.0.1')
|
||||||
with mock.patch.object(self.fake_cluster.api_client,
|
with mock.patch.object(self.fake_cluster.api_client,
|
||||||
'get_nvp_version',
|
'get_nvp_version',
|
||||||
return_value=version):
|
return_value=NvpApiClient.NVPVersion(version)):
|
||||||
nvplib.create_lrouter_dnat_rule(
|
nvplib.create_lrouter_dnat_rule(
|
||||||
self.fake_cluster, lrouter['uuid'], '192.168.0.2', order=200,
|
self.fake_cluster, lrouter['uuid'], '192.168.0.2', order=200,
|
||||||
dest_port=dest_port,
|
dest_port=dest_port,
|
||||||
@ -797,7 +982,7 @@ class TestNvplibLogicalRouters(NvplibTestCase):
|
|||||||
'10.0.0.1')
|
'10.0.0.1')
|
||||||
with mock.patch.object(self.fake_cluster.api_client,
|
with mock.patch.object(self.fake_cluster.api_client,
|
||||||
'get_nvp_version',
|
'get_nvp_version',
|
||||||
new=lambda: version):
|
new=lambda: NvpApiClient.NVPVersion(version)):
|
||||||
nvplib.create_lrouter_nosnat_rule(
|
nvplib.create_lrouter_nosnat_rule(
|
||||||
self.fake_cluster, lrouter['uuid'],
|
self.fake_cluster, lrouter['uuid'],
|
||||||
order=100,
|
order=100,
|
||||||
@ -820,7 +1005,7 @@ class TestNvplibLogicalRouters(NvplibTestCase):
|
|||||||
# v2 or v3 makes no difference for this test
|
# v2 or v3 makes no difference for this test
|
||||||
with mock.patch.object(self.fake_cluster.api_client,
|
with mock.patch.object(self.fake_cluster.api_client,
|
||||||
'get_nvp_version',
|
'get_nvp_version',
|
||||||
new=lambda: '2.0'):
|
new=lambda: NvpApiClient.NVPVersion('2.0')):
|
||||||
nvplib.create_lrouter_snat_rule(
|
nvplib.create_lrouter_snat_rule(
|
||||||
self.fake_cluster, lrouter['uuid'],
|
self.fake_cluster, lrouter['uuid'],
|
||||||
'10.0.0.2', '10.0.0.2', order=220,
|
'10.0.0.2', '10.0.0.2', order=220,
|
||||||
@ -1164,3 +1349,7 @@ class TestNvplibClusterVersion(NvplibTestCase):
|
|||||||
with mock.patch.object(nvplib, 'do_request', new=fakedorequest):
|
with mock.patch.object(nvplib, 'do_request', new=fakedorequest):
|
||||||
version = nvplib.get_cluster_version('whatever')
|
version = nvplib.get_cluster_version('whatever')
|
||||||
self.assertIsNone(version)
|
self.assertIsNone(version)
|
||||||
|
|
||||||
|
|
||||||
|
def _nicira_method(method_name, module_name='nvplib'):
|
||||||
|
return '%s.%s.%s' % ('neutron.plugins.nicira', module_name, method_name)
|
||||||
|
Loading…
Reference in New Issue
Block a user