Browse Source

OSP-298 remove p+v support and related tests

removed a few vswitch related options and default to ovs

Change-Id: Id8e7cc52cea423c78e3181e0ce2bda742d3478fc
changes/29/781929/5
Weifan Fu 1 month ago
parent
commit
ecdecbe3d6
15 changed files with 32 additions and 1818 deletions
  1. +0
    -19
      etc/neutron/plugins/bigswitch/restproxy.ini
  2. +5
    -113
      networking_bigswitch/plugins/bigswitch/agent/restproxy_agent.py
  3. +1
    -5
      networking_bigswitch/plugins/bigswitch/config.py
  4. +0
    -530
      networking_bigswitch/plugins/bigswitch/l3_router_plugin.py
  5. +15
    -136
      networking_bigswitch/plugins/bigswitch/plugin.py
  6. +1
    -99
      networking_bigswitch/plugins/ml2/drivers/mech_bigswitch/driver.py
  7. +0
    -1
      networking_bigswitch/tests/unit/bigswitch/etc/restproxy.ini.test
  8. +1
    -4
      networking_bigswitch/tests/unit/bigswitch/mock_paths.py
  9. +1
    -3
      networking_bigswitch/tests/unit/bigswitch/test_base.py
  10. +5
    -45
      networking_bigswitch/tests/unit/bigswitch/test_capabilities.py
  11. +1
    -187
      networking_bigswitch/tests/unit/bigswitch/test_restproxy_agent.py
  12. +2
    -10
      networking_bigswitch/tests/unit/bigswitch/test_restproxy_plugin.py
  13. +0
    -491
      networking_bigswitch/tests/unit/bigswitch/test_router_db.py
  14. +0
    -174
      networking_bigswitch/tests/unit/ml2/drivers/test_bigswitch_mech.py
  15. +0
    -1
      setup.cfg

+ 0
- 19
etc/neutron/plugins/bigswitch/restproxy.ini View File

@ -82,20 +82,6 @@ servers=localhost:8080
# BCF. (Require BCF 5.0 or above)
# naming_scheme_unicode = True
[nova]
# Specify the VIF_TYPE that will be controlled on the Nova compute instances
# options: ivs or ovs
# default: ovs
# vif_type = ovs
# Overrides for vif types based on nova compute node host IDs
# Comma separated list of host IDs to fix to a specific VIF type
# The VIF type is taken from the end of the configuration item
# node_override_vif_<vif_type>
# For example, the following would set the VIF type to IVS for
# host-id1 and host-id2
# node_overrride_vif_ivs=host-id1,host-id2
[router]
# Specify the default router rules installed in newly created tenant routers
# Specify multiple times for multiple rules
@ -121,11 +107,6 @@ servers=localhost:8080
# Default: 5
# polling_interval=5
# Virtual switch type on the compute node.
# Options: ovs, ivs or nfvswitch
# Default: ivs
# virtual_switch_type = ivs
[securitygroup]
# Controls if neutron security group is enabled or not.
# It should be false when you use nova security group.


+ 5
- 113
networking_bigswitch/plugins/bigswitch/agent/restproxy_agent.py View File

@ -28,12 +28,10 @@ from neutron_lib import context as q_context
from oslo_config import cfg
from oslo_log import log
from oslo_service import loopingcall
from oslo_utils import excutils
from networking_bigswitch.plugins.bigswitch import config as pl_config
from networking_bigswitch.plugins.bigswitch.i18n import _LI
from neutron.agent.common import ovs_lib
from neutron.agent.linux import utils
from neutron.agent import rpc as agent_rpc
from neutron.agent import securitygroups_rpc as sg_rpc
from neutron.api.rpc.handlers import securitygroups_rpc as api_sg_rpc
@ -42,100 +40,9 @@ from neutron.extensions import securitygroup as ext_sg
eventlet.monkey_patch()
IVS_PORT_MTU = 9000
IVS_VM_PORT_PREFIX = 'qvo'
IVS_VM_PORT_IFACE_PREFIXES = [IVS_VM_PORT_PREFIX, 'qvb', 'tap', 'qbr']
LOG = log.getLogger(__name__)
class IVSBridge(object):
"""IVS Bridge
This class does not provide parity with OVS using IVS.
It's only the bare minimum necessary to use IVS with this agent.
"""
def run_vsctl(self, args, check_error=False, log_fail_as_error=True):
full_args = ["ivs-ctl"] + args
try:
resp = utils.execute(full_args, run_as_root=True,
return_stderr=True,
log_fail_as_error=log_fail_as_error)
return resp[0] or resp[1]
except Exception as e:
with excutils.save_and_reraise_exception() as ctxt:
if log_fail_as_error:
logfunc = LOG.error
else:
logfunc = LOG.debug
logfunc("Unable to execute %(cmd)s. "
"Exception: %(exception)s",
{'cmd': full_args, 'exception': e})
if not check_error:
ctxt.reraise = False
def get_vif_port_set(self):
port_names = self.get_port_name_list()
edge_ports = set(port_names)
return edge_ports
def get_vif_port_by_id(self, port_id):
# IVS in nova uses hybrid method with last 11 chars of UUID
name = ('qvo%s' % port_id)[:14]
if name in self.get_vif_port_set():
return name
return False
def get_port_name_list(self):
# Try native list-ports command first and then fallback to show
# command.
try:
resp = self.run_vsctl(['list-ports'], True,
log_fail_as_error=False).strip().splitlines()
port_names = [x.strip() for x in resp]
except RuntimeError:
resp = self.run_vsctl(['show'], True)
# get rid of stats and blank lines
lines = resp.split('ivs:')[1].split('ports:')[1].splitlines()
ports = [x for x in lines if 'packets=' not in x and x.strip()]
port_names = [x.strip().split(' ')[1] for x in ports]
LOG.debug("Ports on IVS: %s", port_names)
return port_names
def set_port_mtu(self, port_name):
# If this IVS port is attached to a VM, set the MTU of all
# corresponding interfaces (veth pairs, tap and bridge interfaces)
if IVS_VM_PORT_PREFIX in port_name:
for iface in IVS_VM_PORT_IFACE_PREFIXES:
iface_name = port_name.replace(IVS_VM_PORT_PREFIX, iface)
cmd = ['ip', 'link', 'set', iface_name, 'mtu', IVS_PORT_MTU]
try:
utils.execute(cmd, run_as_root=True, return_stderr=False,
log_fail_as_error=False)
LOG.debug("MTU of port %s set to %d", str(iface_name),
IVS_PORT_MTU)
except Exception as e:
LOG.error("Set MTU for port %(p)s failed. Unable to "
"execute %(cmd)s. Exception: %(exception)s",
{'p': iface_name, 'cmd': cmd, 'exception': e})
class NFVSwitchBridge(object):
"""NFV Switch Bridge
This class does not provide parity with OVS using NFVSwitch.
It's only the bare minimum necessary to use NFVSwitch with this agent.
"""
def get_vif_port_set(self):
# Un-supported operation. Return empty set for no-op
return set()
def get_vif_port_by_id(self, port_id):
# Un-supported operation. Return False for no-op
return False
class FilterDeviceIDMixin(sg_rpc.SecurityGroupAgentRpc):
"""Override SecurityGroupAgentRpc methods that call firewall_driver.
@ -220,18 +127,12 @@ class RestProxyAgent(api_sg_rpc.SecurityGroupAgentRpcCallbackMixin):
target = oslo_messaging.Target(version='1.1')
def __init__(self, integ_br, polling_interval, vs='ovs'):
def __init__(self, integ_br, polling_interval):
super(RestProxyAgent, self).__init__()
self.polling_interval = polling_interval
if vs == 'ivs':
self.int_br = IVSBridge()
self.agent_type = "BSN IVS Agent"
elif vs == "nfvswitch":
self.int_br = NFVSwitchBridge()
self.agent_type = "BSN NFVSwitch Agent"
else:
self.int_br = ovs_lib.OVSBridge(integ_br)
self.agent_type = "OVS Agent"
self.int_br = ovs_lib.OVSBridge(integ_br)
self.agent_type = "OVS Agent"
self.agent_state = {
'binary': 'neutron-bsn-agent',
'host': cfg.CONF.host,
@ -296,13 +197,6 @@ class RestProxyAgent(api_sg_rpc.SecurityGroupAgentRpcCallbackMixin):
'added': added,
'removed': removed}
def _update_port_mtus(self, port_info):
"""Update the MTU of all ports that attach the VM port to IVS """
if 'added' in port_info:
ports = port_info['added']
for port in ports:
self.int_br.set_port_mtu(port)
def _process_devices_filter(self, port_info):
if 'added' in port_info:
self.sg_agent.prepare_devices_filter(port_info['added'])
@ -318,7 +212,6 @@ class RestProxyAgent(api_sg_rpc.SecurityGroupAgentRpcCallbackMixin):
port_info = self._update_ports(ports)
if port_info:
LOG.debug("Agent loop has new device")
self._update_port_mtus(port_info)
self._process_devices_filter(port_info)
ports = port_info['current']
except Exception:
@ -341,8 +234,7 @@ def main():
integ_br = cfg.CONF.RESTPROXYAGENT.integration_bridge
polling_interval = cfg.CONF.RESTPROXYAGENT.polling_interval
bsnagent = RestProxyAgent(integ_br, polling_interval,
cfg.CONF.RESTPROXYAGENT.virtual_switch_type)
bsnagent = RestProxyAgent(integ_br, polling_interval)
bsnagent.daemon_loop()
sys.exit(0)


+ 1
- 5
networking_bigswitch/plugins/bigswitch/config.py View File

@ -98,12 +98,11 @@ router_opts = [
help=_("Maximum number of router rules")),
]
nova_opts = [
cfg.StrOpt('vif_type', default='ivs',
cfg.StrOpt('vif_type', default='ovs',
help=_("Virtual interface type to configure on "
"Nova compute nodes")),
]
VIF_TYPE_IVS = 'ivs'
VIF_TYPES = [
portbindings.VIF_TYPE_UNBOUND,
portbindings.VIF_TYPE_BINDING_FAILED,
@ -112,7 +111,6 @@ VIF_TYPES = [
portbindings.VIF_TYPE_BRIDGE,
portbindings.VIF_TYPE_OTHER,
portbindings.VIF_TYPE_VHOST_USER,
VIF_TYPE_IVS,
'iovisor', 'dvs', '802.1qbg', '802.1qbh', 'hyperv',
'midonet', 'ib_hostdev', 'hw_web', 'vrouter',
]
@ -144,8 +142,6 @@ agent_opts = [
'nodes used for security group insertion.')),
cfg.IntOpt('polling_interval', default=5,
help=_('Seconds between agent checks for port changes')),
cfg.StrOpt('virtual_switch_type', default='ivs',
help=_('Virtual switch type.'))
]


+ 0
- 530
networking_bigswitch/plugins/bigswitch/l3_router_plugin.py View File

@ -1,530 +0,0 @@
# Copyright 2014 Big Switch Networks, 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.
#
"""
Neutron L3 REST Proxy Plugin for Big Switch and Floodlight Controllers.
This plugin handles the L3 router calls for Big Switch Floodlight deployments.
It is intended to be used in conjunction with the Big Switch ML2 driver or the
Big Switch core plugin.
"""
import copy
from neutron.api import extensions as neutron_extensions
from neutron.db import dns_db
from neutron.db import l3_db
from neutron_lib.api.definitions import l3 as l3_apidef
from neutron_lib.callbacks import events
from neutron_lib.callbacks import registry
from neutron_lib.callbacks import resources
from neutron_lib import constants as lib_constants
from neutron_lib.db import api as db_api
from neutron_lib.db import utils as db_utils
from neutron_lib import exceptions
from neutron_lib.plugins import constants as plugin_constants
from neutron_lib.plugins import directory
from oslo_log import helpers as log_helper
from oslo_log import log as logging
from oslo_utils import excutils
from oslo_utils import uuidutils
from networking_bigswitch.plugins.bigswitch.db import tenant_policy_db
from networking_bigswitch.plugins.bigswitch import extensions
from networking_bigswitch.plugins.bigswitch.i18n import _
from networking_bigswitch.plugins.bigswitch.i18n import _LE
from networking_bigswitch.plugins.bigswitch import plugin as cplugin
from networking_bigswitch.plugins.bigswitch import servermanager
from networking_bigswitch.plugins.bigswitch.utils import Util
LOG = logging.getLogger(__name__)
add_debug_log = cplugin.add_debug_log
BCF_CAPABILITY_L3_PLUGIN_MISS_MATCH = (
"BCF does not have floatingip capability, should not "
"deploy BSN l3 router plugin")
BSN_TRANSACTION_ID = 'bsn_transaction_id'
class TransactionCache(object):
"""Cache to store the object ID generated during create operations.
This cache only temporarily stores the ID assigned to a new object during
create operation.
If the operation fails, the cache is used to retrieve the ID assigned to
the object to delete it from the BCF controller.
Cache is a dict storing the transaction to object ID mapping:
{
'transaction_1': 'object_id_1',
'transaction_2': 'object_id_2',
..
'transaction_n': 'object_id_n'
}
"""
def __init__(self):
self.cache = {}
def add_transaction(self, transaction_id, obj_id):
"""Adds txn_id > obj_id mapping to the cache
:param transaction_id: unique bsn_transaction_id generated
:param obj_id: ID assigned to the object during DB create
:return: None
"""
LOG.debug('Adding mapping to transaction cache for transaction_id '
'%(txn_id)s to object_id %(obj_id)s.',
{'txn_id': transaction_id, 'obj_id': obj_id})
self.cache[transaction_id] = obj_id
def remove_transaction(self, transaction_id):
"""Removes the transaction_id from cache
:param transaction_id: unique bsn_transaction_id for the current
operation
:return: obj_id assigned previously or None
"""
if transaction_id not in self.cache:
LOG.debug('Transaction ID %(txn_id)s not found in cache. Maybe an '
'exception caused pre-emptive removal.',
{'txn_id': transaction_id})
return None
obj_id = self.cache.pop(transaction_id)
LOG.debug('Removing mapping from transaction_cache for transaction_id '
'%(txn_id)s to object_id %(obj_id)s.',
{'obj_id': obj_id, 'txn_id': transaction_id})
return obj_id
class L3RestProxy(cplugin.NeutronRestProxyV2Base,
l3_db.L3_NAT_db_mixin,
dns_db.DNSDbMixin,
tenant_policy_db.TenantPolicyDbMixin):
supported_extension_aliases = ["router"]
# This is a flag to tell that L3 plugin is BSN.
bsn = True
@staticmethod
def get_plugin_type():
return plugin_constants.L3
@staticmethod
def get_plugin_description():
return _("L3 Router Service Plugin for Big Switch fabric")
def __init__(self):
# Include the Big Switch Extensions path in the api_extensions
neutron_extensions.append_api_extensions_path(extensions.__path__)
super(L3RestProxy, self).__init__()
self.servers = servermanager.ServerPool.get_instance()
self.subscribe_l3_callbacks()
# upstream stores ID of the object being created as part of the
# safe_creation method
# we don't have access to that local variable. hence we need to stash
# it when it comes as part of before_create_callback
# TransactionCache is a dict with the following mapping:
# {'bsn_transaction_id': 'object_id'}
self.txn_cache = TransactionCache()
def subscribe_l3_callbacks(self):
registry.subscribe(self.router_before_create_callback,
resources.ROUTER, events.BEFORE_CREATE)
registry.subscribe(self.router_after_create_callback, resources.ROUTER,
events.AFTER_CREATE)
registry.subscribe(self.router_precommit_delete_callback,
resources.ROUTER, events.PRECOMMIT_DELETE)
registry.subscribe(self.router_after_delete_callback, resources.ROUTER,
events.AFTER_DELETE)
registry.subscribe(self.router_interface_after_create_callback,
resources.ROUTER_INTERFACE, events.AFTER_CREATE)
@log_helper.log_method_call
def router_before_create_callback(self, resource, event, trigger,
**kwargs):
"""Try to create router on BCF
If failed, rollback the DB operation.
:return:
"""
context = kwargs.get('context')
router = kwargs.get('router')
self.txn_cache.add_transaction(router[BSN_TRANSACTION_ID],
router['id'])
with db_api.CONTEXT_READER.using(context):
mapped_router = self._map_display_name_or_tenant(router)
mapped_router = self._map_state_and_status(mapped_router)
# Does not handle external gateway and some other information
self.servers.rest_create_router(mapped_router['tenant_id'],
mapped_router)
@log_helper.log_method_call
def router_after_create_callback(self, resource, event, trigger, **kwargs):
"""Update external gateway and create tenant policies
:param resource:
:param event:
:param trigger:
:param kwargs:
:return:
"""
context = kwargs.get('context')
router = kwargs.get('router')
tenant_id = router['tenant_id']
# set default router policies
default_policy_dict = self._get_tenant_default_router_policy(tenant_id)
with db_api.CONTEXT_WRITER.using(context):
mapped_router = self._map_display_name_or_tenant(router)
mapped_router = self._map_state_and_status(mapped_router)
# populate external tenant_id if it is absent for external network,
# This is a new work flow in kilo that user can specify external
# network when creating a router
if mapped_router and mapped_router.get('external_gateway_info'):
ext_gw_info = mapped_router.get('external_gateway_info')
ext_net_id = ext_gw_info.get('network_id')
ext_tenant_id = ext_gw_info.get("tenant_id")
if ext_net_id and (not ext_tenant_id):
ext_net = self.get_network(context, ext_net_id)
if ext_net:
mapped_router['external_gateway_info']['tenant_id'] = (
ext_net.get('tenant_id'))
# update router that was created in before_create callback
self.servers.rest_update_router(
mapped_router['tenant_id'], mapped_router, mapped_router['id'])
# post router creation, create default policy if missing
tenantpolicy_dict = super(L3RestProxy, self).create_default_policy(
context, tenant_id, default_policy_dict)
if tenantpolicy_dict:
self.servers.rest_create_tenantpolicy(
tenantpolicy_dict['tenant_id'], tenantpolicy_dict)
@add_debug_log
@log_helper.log_method_call
def create_router(self, context, router):
self._warn_on_state_status(router['router'])
# this also validates if the current tenant can create this router
tenant_id = Util.get_tenant_id_for_create(context, router['router'])
# cache the transaction_id
bsn_transaction_id = uuidutils.generate_uuid()
# add this unique identifier to the router object upstream, so that it
# reaches the pre-commit callback
router['router'][BSN_TRANSACTION_ID] = bsn_transaction_id
try:
new_router = super(L3RestProxy, self).create_router(context,
router)
return new_router
except Exception:
with excutils.save_and_reraise_exception():
try:
router_id = self.txn_cache.remove_transaction(
bsn_transaction_id)
self.servers.rest_delete_router(tenant_id, router_id)
except Exception as e:
LOG.error(_LE("Cannot clean up the router object created "
"on BCF. Exception: %(exc)s"), {'exc': e})
finally:
self.txn_cache.remove_transaction(bsn_transaction_id)
@add_debug_log
@log_helper.log_method_call
def update_router(self, context, router_id, router):
self._warn_on_state_status(router['router'])
orig_router = super(L3RestProxy, self).get_router(context, router_id)
tenant_id = orig_router["tenant_id"]
with db_api.CONTEXT_WRITER.using(context):
setattr(context, 'GUARD_TRANSACTION', False)
new_router = super(L3RestProxy,
self).update_router(context, router_id, router)
router = self._update_ext_gateway_info(context, new_router)
# update router on network controller
self.servers.rest_update_router(tenant_id, router, router_id)
# return updated router
return new_router
@log_helper.log_method_call
def router_precommit_delete_callback(self, resource, event, trigger,
**kwargs):
router = kwargs.get('router_db')
router_id = kwargs.get('router_id')
# delete from network controller
self.servers.rest_delete_router(router['tenant_id'], router_id)
@log_helper.log_method_call
def router_after_delete_callback(self, resource, event, trigger, **kwargs):
context = kwargs.get('context')
orig_router = kwargs.get('original')
tenant_id = orig_router['tenant_id']
# remove tenant policies if this was the last router under tenant
with db_api.CONTEXT_WRITER.using(context):
upstream_routers = super(L3RestProxy, self).get_routers(
context, filters={"tenant_id": [tenant_id]})
LOG.debug('upstream_routers are: %s', upstream_routers)
if not upstream_routers:
# there aren't any routers under tenant. remove all policies
super(L3RestProxy, self).remove_default_policy(context,
tenant_id)
@add_debug_log
@log_helper.log_method_call
def delete_router(self, context, router_id):
with db_api.CONTEXT_READER.using(context):
# Ensure that the router is not used
router_filter = {'router_id': [router_id]}
fips = self.get_floatingips_count(context.elevated(),
filters=router_filter)
if fips:
raise exceptions.l3.RouterInUse(router_id=router_id)
device_owner = lib_constants.DEVICE_OWNER_ROUTER_INTF
device_filter = {'device_id': [router_id],
'device_owner': [device_owner]}
ports = self.get_ports_count(context.elevated(),
filters=device_filter)
if ports:
raise exceptions.l3.RouterInUse(router_id=router_id)
super(L3RestProxy, self).delete_router(context, router_id)
@log_helper.log_method_call
def router_interface_after_create_callback(self, resource, event, trigger,
**kwargs):
context = kwargs.get('context')
port = kwargs.get('port')
router_id = kwargs.get('router_id')
interface_info = kwargs.get('interface_info')
subnet_id_list = []
if 'port_id' in interface_info:
for fixed_ip in port['fixed_ips']:
subnet_id_list.append(fixed_ip['subnet_id'])
elif 'subnet_id' in interface_info:
subnet_id_list.append(interface_info['subnet_id'])
else:
msg = _("Either subnet_id or port_id must be specified")
raise exceptions.BadRequest(resource='router', msg=msg)
for subnet_id in subnet_id_list:
# bookmark for delete in case of transaction rollback
self.txn_cache.add_transaction(interface_info[BSN_TRANSACTION_ID],
subnet_id)
with db_api.CONTEXT_READER.using(context):
# we will use the port's subnet id as interface's id
intf_details = self._get_router_intf_details(context, port,
subnet_id)
tenant_id = intf_details['subnet']['project_id']
# create interface on the network controller
self.servers.rest_add_router_interface(tenant_id, router_id,
intf_details)
directory.get_plugin().update_port(context, port['id'],
{'port': {'status': 'ACTIVE'}})
@add_debug_log
@log_helper.log_method_call
def add_router_interface(self, context, router_id, interface_info):
bsn_transaction_id = uuidutils.generate_uuid()
interface_info[BSN_TRANSACTION_ID] = bsn_transaction_id
try:
new_intf_info = super(L3RestProxy, self).add_router_interface(
context, router_id, interface_info)
return new_intf_info
except Exception:
with excutils.save_and_reraise_exception():
try:
router = self._get_router(context, router_id)
tenant_id = router['tenant_id']
interface_id = self.txn_cache.remove_transaction(
bsn_transaction_id)
# we use port's subnet_id as interface's id
self.servers.rest_remove_router_interface(
tenant_id, router_id, interface_id)
except Exception as e:
LOG.error(_LE("Cannot clean up router interface created "
"on BCF. Exception: %(exc)s"), {'exc': e})
finally:
self.txn_cache.remove_transaction(bsn_transaction_id)
@add_debug_log
@log_helper.log_method_call
def remove_router_interface(self, context, router_id, interface_info):
# Validate args
router = self._get_router(context, router_id)
tenant_id = router['tenant_id']
subnet_id_list = []
# we will first get the interface identifier before deleting in the DB
if not interface_info:
msg = _("Either subnet_id or port_id must be specified")
raise exceptions.BadRequest(resource='router', msg=msg)
if 'port_id' in interface_info:
port = self._get_port(context, interface_info['port_id'])
for fixed_ip in port['fixed_ips']:
subnet_id_list.append(fixed_ip['subnet_id'])
elif 'subnet_id' in interface_info:
subnet = self._get_subnet(context, interface_info['subnet_id'])
subnet_id_list.append(subnet['id'])
else:
msg = _("Either subnet_id or port_id must be specified")
raise exceptions.BadRequest(resource='router', msg=msg)
with db_api.CONTEXT_WRITER.using(context):
# remove router in DB
# TODO(wolverineav): hack until fixed at right place
setattr(context, 'GUARD_TRANSACTION', False)
del_ret = super(L3RestProxy,
self).remove_router_interface(context,
router_id,
interface_info)
for subnet_id in subnet_id_list:
# remove all related router interfaces
self.servers.rest_remove_router_interface(tenant_id, router_id,
subnet_id)
return del_ret
# add floating_port_id into the dict for later port mac lookup
def _make_floatingip_dict(self, floatingip, fields=None,
process_extensions=True):
res = super(L3RestProxy, self)._make_floatingip_dict(
floatingip, fields=fields,
process_extensions=process_extensions)
res['floating_port_id'] = floatingip['floating_port_id']
return db_utils.resource_fields(res, fields)
@add_debug_log
@log_helper.log_method_call
def create_floatingip(self, context, floatingip):
with db_api.CONTEXT_WRITER.using(context):
# create floatingip in DB
# TODO(wolverineav): hack until fixed at right place
setattr(context, 'GUARD_TRANSACTION', False)
new_fl_ip = super(L3RestProxy,
self).create_floatingip(context, floatingip)
# create floatingip on the network controller
try:
if 'floatingip' in self.servers.get_capabilities():
backend_fip = copy.deepcopy(new_fl_ip)
fport = self.get_port(context.elevated(),
backend_fip['floating_port_id'])
backend_fip['floating_mac_address']\
= fport.get('mac_address')
self.servers.rest_create_floatingip(
backend_fip['tenant_id'], backend_fip)
else:
LOG.error(BCF_CAPABILITY_L3_PLUGIN_MISS_MATCH)
self._send_floatingip_update(context)
except servermanager.RemoteRestError as e:
with excutils.save_and_reraise_exception():
LOG.error("NeutronRestProxyV2: Unable to create remote "
"floating IP: %s", e)
# return created floating IP
return new_fl_ip
@add_debug_log
@log_helper.log_method_call
def update_floatingip(self, context, id, floatingip):
with db_api.CONTEXT_WRITER.using(context):
# update floatingip in DB
# TODO(wolverineav): hack until fixed at right place
setattr(context, 'GUARD_TRANSACTION', False)
new_fl_ip = super(L3RestProxy,
self).update_floatingip(context, id, floatingip)
# add mac address for the port
if new_fl_ip.get('floating_port_id'):
fport = self.get_port(context.elevated(),
new_fl_ip['floating_port_id'])
new_fl_ip['floating_mac_address'] = fport.get('mac_address')
# update network on network controller
if 'floatingip' in self.servers.get_capabilities():
self.servers.rest_update_floatingip(new_fl_ip['tenant_id'],
new_fl_ip, id)
else:
LOG.error(BCF_CAPABILITY_L3_PLUGIN_MISS_MATCH)
self._send_floatingip_update(context)
return new_fl_ip
@add_debug_log
@log_helper.log_method_call
def delete_floatingip(self, context, id):
with db_api.CONTEXT_WRITER.using(context):
# delete floating IP in DB
# TODO(wolverineav): hack until fixed at right place
setattr(context, 'GUARD_TRANSACTION', False)
old_fip = super(L3RestProxy, self).get_floatingip(context, id)
super(L3RestProxy, self).delete_floatingip(context, id)
# update network on network controller
if 'floatingip' in self.servers.get_capabilities():
self.servers.rest_delete_floatingip(old_fip['tenant_id'], id)
else:
LOG.error(BCF_CAPABILITY_L3_PLUGIN_MISS_MATCH)
self._send_floatingip_update(context)
@add_debug_log
@log_helper.log_method_call
def disassociate_floatingips(self, context, port_id, do_notify=True):
router_ids = super(L3RestProxy, self).disassociate_floatingips(
context, port_id, do_notify=do_notify)
self._send_floatingip_update(context)
return router_ids
def _update_ext_gateway_info(self, context, updated_router):
if updated_router.get(l3_apidef.EXTERNAL_GW_INFO):
ext_net_id = (updated_router[l3_apidef.EXTERNAL_GW_INFO]
.get('network_id'))
ext_net = self.get_network(context, ext_net_id)
ext_tenant_id = ext_net.get('tenant_id')
if ext_tenant_id:
updated_router[l3_apidef.EXTERNAL_GW_INFO]['tenant_id'] = (
ext_tenant_id)
router = self._map_display_name_or_tenant(updated_router)
router = self._map_state_and_status(router)
# look up the network on this side to save an expensive query on
# the backend controller.
if router and router.get('external_gateway_info'):
router['external_gateway_info']['network'] = self.get_network(
context.elevated(),
router['external_gateway_info']['network_id'])
return router
def _send_floatingip_update(self, context):
try:
ext_net_id = self.get_external_network_id(context)
if ext_net_id:
# Use the elevated state of the context for the ext_net query
admin_context = context.elevated()
ext_net = super(L3RestProxy,
self).get_network(admin_context, ext_net_id)
# update external network on network controller
self._send_update_network(ext_net, admin_context)
except exceptions.TooManyExternalNetworks:
# get_external_network can raise errors when multiple external
# networks are detected, which isn't supported by the Plugin
pass

+ 15
- 136
networking_bigswitch/plugins/bigswitch/plugin.py View File

@ -74,7 +74,6 @@ from neutron_lib.agent import topics
from neutron_lib.api.definitions import allowedaddresspairs as addr_pair
from neutron_lib.api.definitions import external_net as extnet_apidef
from neutron_lib.api.definitions import extra_dhcp_opt as edo_ext
from neutron_lib.api.definitions import l3 as l3_apidef
from neutron_lib.api.definitions import portbindings
from neutron_lib import constants as const
from neutron_lib import context as qcontext
@ -189,10 +188,6 @@ class NeutronRestProxyV2Base(db_base_plugin_v2.NeutronDbPluginV2,
def l3_plugin(self):
return directory.get_plugin(plugin_constants.L3)
@property
def l3_bsn_plugin(self):
return hasattr(self.l3_plugin, "bsn")
@property
def bsn_service_plugin(self):
return directory.get_plugin(bsn_constants.BSN_SERVICE_PLUGIN)
@ -231,12 +226,9 @@ class NeutronRestProxyV2Base(db_base_plugin_v2.NeutronDbPluginV2,
def _get_all_data_auto(self):
return self._get_all_data(
get_floating_ips=self.l3_bsn_plugin,
get_routers=self.l3_bsn_plugin,
get_sgs=cfg.CONF.RESTPROXY.sync_security_groups)
def _get_all_data(self, get_ports=True, get_floating_ips=True,
get_routers=True, get_sgs=True):
def _get_all_data(self, get_ports=True, get_sgs=True):
# sync tenant cache with keystone
if not self.servers._update_tenant_cache(reconcile=False):
return None
@ -266,11 +258,7 @@ class NeutronRestProxyV2Base(db_base_plugin_v2.NeutronDbPluginV2,
new_subnets.append(subnet)
mapped_network['subnets'] = new_subnets
if get_floating_ips:
flips_n_ports = self._get_network_with_floatingips(
mapped_network)
else:
flips_n_ports = mapped_network
networks_n_ports = mapped_network
if get_ports:
ports = []
@ -280,13 +268,7 @@ class NeutronRestProxyV2Base(db_base_plugin_v2.NeutronDbPluginV2,
for port in net_ports:
if not self._is_port_supported(port):
continue
# skip L3 router ports since the backend
# implements the router
if (self.l3_bsn_plugin and
port.get('device_owner') in
[const.DEVICE_OWNER_ROUTER_GW,
const.DEVICE_OWNER_ROUTER_HA_INTF]):
continue
mapped_port = self._map_display_name_or_tenant(port)
if self.servers.is_unicode_enabled():
# remove port name so that it won't be stored in
@ -308,78 +290,16 @@ class NeutronRestProxyV2Base(db_base_plugin_v2.NeutronDbPluginV2,
ports.append(mapped_port)
flips_n_ports['ports'] = ports
networks_n_ports['ports'] = ports
if flips_n_ports:
networks.append(flips_n_ports)
if networks_n_ports:
networks.append(networks_n_ports)
except servermanager.TenantIDNotFound:
# if tenant name is not known to keystone, skip the network
continue
data = {'networks': networks}
if get_routers and self.l3_plugin:
routers = []
all_routers = self.l3_plugin.get_routers(admin_context) or []
all_policies = (self.bsn_service_plugin
.get_tenantpolicies(admin_context)
if self.bsn_service_plugin else [])
tenant_policies = {}
for policy in all_policies:
if policy['tenant_id'] not in tenant_policies:
tenant_policies[policy['tenant_id']] = []
policy['ipproto'] = policy['protocol']
tenant_policies[policy['tenant_id']].append(policy)
for router in all_routers:
try:
# Add tenant_id of the external gateway network
if router.get(l3_apidef.EXTERNAL_GW_INFO):
ext_net_id = router[l3_apidef.EXTERNAL_GW_INFO].get(
'network_id')
ext_net = self.get_network(admin_context, ext_net_id)
ext_tenant_id = ext_net.get('tenant_id')
if ext_tenant_id:
router[l3_apidef.EXTERNAL_GW_INFO]['tenant_id'] = (
ext_tenant_id)
interfaces = []
mapped_router = self._map_display_name_or_tenant(router)
mapped_router = self._map_state_and_status(mapped_router)
if not self._validate_names(mapped_router):
continue
router_filter = {
'device_owner': [const.DEVICE_OWNER_ROUTER_INTF],
'device_id': [router.get('id')]
}
router_ports = self.get_ports(admin_context,
filters=router_filter) or []
for port in router_ports:
for fixed_ip in port['fixed_ips']:
subnet_id = fixed_ip['subnet_id']
intf_details = self._get_router_intf_details(
admin_context, port, subnet_id)
interfaces.append(intf_details)
mapped_router['interfaces'] = interfaces
routers.append(mapped_router)
except servermanager.TenantIDNotFound:
# if tenant name is not known to keystone, skip the network
continue
# append router_tenant_rules to each router
for router in routers:
if router['tenant_id'] in tenant_policies:
router['policies'] = tenant_policies[router['tenant_id']]
data.update({'routers': routers})
# L3 plugin also includes tenant policies
# data.update({'policies': tenant_policies})
if get_sgs and self.l3_plugin:
sgs = plugin.get_security_groups(admin_context) or []
new_sgs = []
@ -428,13 +348,11 @@ class NeutronRestProxyV2Base(db_base_plugin_v2.NeutronDbPluginV2,
def _send_all_data_auto(self, timeout=None, triggered_by_tenant=None):
return self._send_all_data(
send_floating_ips=self.l3_bsn_plugin,
send_routers=self.l3_bsn_plugin,
timeout=timeout,
triggered_by_tenant=triggered_by_tenant)
def _send_all_data(self, send_ports=True, send_floating_ips=True,
send_routers=True, send_sgs=True, timeout=None,
def _send_all_data(self, send_ports=True,
send_sgs=True, timeout=None,
triggered_by_tenant=None):
"""Pushes all data to network ctrl (networks/ports, ports/attachments).
@ -442,7 +360,7 @@ class NeutronRestProxyV2Base(db_base_plugin_v2.NeutronDbPluginV2,
with neutron's current view of that data.
All args are ignored. The `_get_all_data` method dynamically pulls the
relevant information i.e. if its L2 only or L2+L3.
relevant information i.e. starting from train, this supports l2 only
"""
sync_executed, topo_resp = self.servers.force_topo_sync()
return topo_resp
@ -456,38 +374,6 @@ class NeutronRestProxyV2Base(db_base_plugin_v2.NeutronDbPluginV2,
# resource name may contain space. Replace space with -
resource['name'] = Util.format_resource_name(resource['name'])
def _get_network_with_floatingips(self, network, context=None):
if context is None:
context = qcontext.get_admin_context()
net_id = network['id']
net_filter = {'floating_network_id': [net_id]}
if self.l3_plugin:
fl_ips = self.l3_plugin.get_floatingips(context,
filters=net_filter) or []
floating_ips = []
for flip in fl_ips:
try:
# BVS-7525: the 'tenant_id' in a floating-ip represents the
# tenant to which it is allocated.
# Validate that the tenant exists
# name/display-name of floating ip is not actually
# used on bcf
mapped_flip = self._map_display_name_or_tenant(flip)
if mapped_flip.get('floating_port_id'):
fport = self.get_port(context,
mapped_flip['floating_port_id'])
mapped_flip['floating_mac_address'] = \
fport.get('mac_address')
floating_ips.append(mapped_flip)
except servermanager.TenantIDNotFound:
# if tenant name is not known to keystone, skip it
continue
network['floatingips'] = floating_ips
return network
def _get_all_subnets_json_for_network(self, net_id, context=None):
if context is None:
context = qcontext.get_admin_context()
@ -643,19 +529,13 @@ class NeutronRestProxyV2Base(db_base_plugin_v2.NeutronDbPluginV2,
mapped_network = self._get_mapped_network_with_subnets(network,
context)
if self.l3_bsn_plugin:
net_fl_ips = self._get_network_with_floatingips(mapped_network,
context)
else:
net_fl_ips = mapped_network
if not tenant_id:
tenant_id = servermanager.SERVICE_TENANT
net_fl_ips['tenant_id'] = servermanager.SERVICE_TENANT
mapped_network['tenant_id'] = servermanager.SERVICE_TENANT
if not self.servers.is_unicode_enabled():
net_fl_ips['name'] = Util.format_resource_name(
net_fl_ips['name'])
self.servers.rest_update_network(tenant_id, net_id, net_fl_ips)
mapped_network['name'] = Util.format_resource_name(
mapped_network['name'])
self.servers.rest_update_network(tenant_id, net_id, mapped_network)
def _send_delete_network(self, network, context=None):
net_id = network['id']
@ -894,8 +774,7 @@ class NeutronRestProxyV2Base(db_base_plugin_v2.NeutronDbPluginV2,
def _extend_port_dict_binding(self, context, port):
cfg_vif_type = cfg.CONF.NOVA.vif_type.lower()
if cfg_vif_type not in (portbindings.VIF_TYPE_OVS,
pl_config.VIF_TYPE_IVS):
if cfg_vif_type not in (portbindings.VIF_TYPE_OVS):
LOG.warning("Unrecognized vif_type in configuration "
"[%s]. Defaulting to ovs.",
cfg_vif_type)
@ -1346,7 +1225,7 @@ class NeutronRestProxyV2(NeutronRestProxyV2Base,
:raises: RemoteRestError
"""
# if needed, check to see if this is a port owned by
# and l3-router. If so, we should prevent deletion.
# an l3-router. If so, we should prevent deletion.
if l3_port_check and self.l3_plugin:
self.l3_plugin.prevent_l3_port_deletion(context, port_id)
with db_api.CONTEXT_WRITER.using(context):


+ 1
- 99
networking_bigswitch/plugins/ml2/drivers/mech_bigswitch/driver.py View File

@ -13,7 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import copy
import datetime
import os
import eventlet
@ -23,7 +22,6 @@ from neutron_lib.api.definitions import portbindings
from neutron_lib.callbacks import events
from neutron_lib.callbacks import registry
from neutron_lib.callbacks import resources
from neutron_lib import constants as const
from neutron_lib import context as ctx
from neutron_lib.plugins import directory
from neutron_lib.plugins.ml2 import api
@ -32,12 +30,10 @@ from oslo_config import cfg
from oslo_log import log
import oslo_messaging
from oslo_utils import excutils
from oslo_utils import timeutils
from six.moves import http_client
from networking_bigswitch.plugins.bigswitch import config as pl_config
from networking_bigswitch.plugins.bigswitch import constants as bsn_consts
from networking_bigswitch.plugins.bigswitch.i18n import _
from networking_bigswitch.plugins.bigswitch.i18n import _LE
from networking_bigswitch.plugins.bigswitch.i18n import _LW
from networking_bigswitch.plugins.bigswitch import plugin
@ -86,8 +82,7 @@ class BigSwitchMechanismDriver(plugin.NeutronRestProxyV2Base,
self.bridge_mappings = {}
if os.path.isfile(bsn_consts.RH_NET_CONF_PATH):
self.bridge_mappings = Util.read_ovs_bridge_mappings()
# Track hosts running IVS to avoid excessive calls to the backend
self.ivs_host_cache = {}
self.setup_rpc_callbacks()
LOG.debug("Initialization done")
@ -280,13 +275,6 @@ class BigSwitchMechanismDriver(plugin.NeutronRestProxyV2Base,
LOG.debug("SR-IOV port, nothing to do")
return
# If bsn_l3 plugin and it is a gateway port, bind to ivs.
if (self.l3_bsn_plugin and
context.current['device_owner'] == ROUTER_GATEWAY_PORT_OWNER):
directory.get_plugin().update_port_status(
context._plugin_context, context.current['id'],
const.PORT_STATUS_ACTIVE)
try:
# create port on the network controller
port = self._prepare_port_for_controller(context)
@ -383,89 +371,3 @@ class BigSwitchMechanismDriver(plugin.NeutronRestProxyV2Base,
prepped_port = self._map_state_and_status(prepped_port)
prepped_port = self._map_port_hostid(prepped_port, net)
return prepped_port
def _bind_port_ivswitch(self, context, segment):
"""Perform bind_port for Indigo virtual switch.
@param context: PortContext object
"""
vif_type = pl_config.VIF_TYPE_IVS
vif_details = {portbindings.CAP_PORT_FILTER: True,
portbindings.OVS_HYBRID_PLUG: True}
context.set_binding(segment[api.ID], vif_type, vif_details)
@add_debug_log
def bind_port(self, context):
"""Marks ports as bound.
Binds external ports and IVS ports.
Fabric configuration will occur on the subsequent port update.
Currently only vlan segments are supported.
"""
if context.current['device_owner'] == EXTERNAL_PORT_OWNER:
# TODO(kevinbenton): check controller to see if the port exists
# so this driver can be run in parallel with others that add
# support for external port bindings
for segment in context.segments_to_bind:
if segment[api.NETWORK_TYPE] == const.TYPE_VLAN:
context.set_binding(
segment[api.ID], portbindings.VIF_TYPE_BRIDGE,
{portbindings.CAP_PORT_FILTER: False,
portbindings.OVS_HYBRID_PLUG: False})
return
if not self._is_port_supported(context.current):
LOG.debug("Ignoring unsupported vnic type")
return
if self._is_port_sriov(context.current):
LOG.debug("SR-IOV port, nothing to do")
return
# IVS hosts will have a vswitch with the same name as the hostname
if self.does_vswitch_exist(context.host):
for segment in context.segments_to_bind:
if segment[api.NETWORK_TYPE] == const.TYPE_VLAN:
self._bind_port_ivswitch(context, segment)
def does_vswitch_exist(self, host):
"""Check if Indigo vswitch exists with the given hostname.
Returns True if switch exists on backend.
Returns False if switch does not exist.
Returns None if backend could not be reached.
Caches response from backend.
"""
try:
return self._get_cached_vswitch_existence(host)
except ValueError:
# cache was empty for that switch or expired
pass
try:
exists = bool(self.servers.rest_get_switch(host))
except servermanager.RemoteRestError:
# Connectivity or internal server error. Skip cache to try again on
# next binding attempt
return
self.ivs_host_cache[host] = {
'timestamp': datetime.datetime.now(),
'exists': exists
}
return exists
def _get_cached_vswitch_existence(self, host):
"""Returns cached existence.
Expired and non-cached raise ValueError.
"""
entry = self.ivs_host_cache.get(host)
if not entry:
raise ValueError(_('No cache entry for host %s') % host)
diff = timeutils.delta_seconds(entry['timestamp'],
datetime.datetime.now())
if diff > CACHE_VSWITCH_TIME:
self.ivs_host_cache.pop(host)
raise ValueError(_('Expired cache entry for host %s') % host)
return entry['exists']

+ 0
- 1
networking_bigswitch/tests/unit/bigswitch/etc/restproxy.ini.test View File

@ -1,6 +1,5 @@
# Test config file for quantum-proxy-plugin.
[DEFAULT]
service_plugins = bigswitch_l3
[database]
# This line MUST be changed to actually run the plugin.


+ 1
- 4
networking_bigswitch/tests/unit/bigswitch/mock_paths.py View File

@ -49,9 +49,8 @@ DRIVER_MOD = 'networking_bigswitch.plugins.ml2.drivers.mech_bigswitch.driver'
DRIVER = DRIVER_MOD + '.BigSwitchMechanismDriver'
# plugin/l3_plugin path
# plugin path
PLUGIN_PATH = BSN_DIR + '.plugin'
L3_PLUGIN_PATH = BSN_DIR + '.l3_router_plugin'
BSN_SERVICE_PLUGIN_PATH = BSN_DIR + '.bsn_service_plugin'
NOTIFIER = PLUGIN_PATH + '.AgentNotifierApi'
@ -62,8 +61,6 @@ MAP_DISPLAY_NAME_OR_TENANT = (PLUGIN_PATH + '.NeutronRestProxyV2Base'
# Agent
AGENT_MOD = BSN_DIR + '.agent.restproxy_agent'
SG_AGENT = AGENT_MOD + '.FilterDeviceIDMixin'
IVS_BRIDGE = AGENT_MOD + '.IVSBridge'
NFV_SW_BRIDGE = AGENT_MOD + '.NFVSwitchBridge'
# SERVER MANAGER
SERVER_MANAGER = BSN_DIR + '.servermanager'


+ 1
- 3
networking_bigswitch/tests/unit/bigswitch/test_base.py View File

@ -34,7 +34,6 @@ from networking_bigswitch.tests.unit.bigswitch.mock_paths import \
IS_UNICODE_ENABLED
from networking_bigswitch.tests.unit.bigswitch.mock_paths import \
KEYSTONE_CLIENT
from networking_bigswitch.tests.unit.bigswitch.mock_paths import L3_PLUGIN_PATH
from networking_bigswitch.tests.unit.bigswitch.mock_paths import \
LIB_RPC_TRANSPORT
from networking_bigswitch.tests.unit.bigswitch.mock_paths import \
@ -49,7 +48,6 @@ from networking_bigswitch.tests.unit.bigswitch.mock_paths import SPAWN
class BigSwitchTestBase(object):
_plugin_name = ('%s.NeutronRestProxyV2' % PLUGIN_PATH)
_l3_plugin_name = ('%s.L3RestProxy' % L3_PLUGIN_PATH)
_bsn_service_plugin_name = ('%s.BSNServicePlugin'
% BSN_SERVICE_PLUGIN_PATH)
@ -67,7 +65,7 @@ class BigSwitchTestBase(object):
os.path.join(etc_path, 'ssl'), 'RESTPROXY')
# The mock interferes with HTTP(S) connection caching
cfg.CONF.set_override('cache_connections', False, 'RESTPROXY')
cfg.CONF.set_override('service_plugins', ['bigswitch_l3'])
cfg.CONF.set_override('service_plugins', ['router'])
cfg.CONF.set_override('add_meta_server_route', False, 'RESTPROXY')
cfg.CONF.set_override('api_extensions_path', False)


+ 5
- 45
networking_bigswitch/tests/unit/bigswitch/test_capabilities.py View File

@ -16,57 +16,17 @@
import mock
from neutron_lib import context
from neutron_lib.plugins import constants as plugin_constants
from neutron_lib.plugins import directory
from neutron.tests.unit.db import test_db_base_plugin_v2 as test_plugin
from networking_bigswitch.tests.unit.bigswitch.mock_paths import HTTPCON
from networking_bigswitch.tests.unit.bigswitch.mock_paths import SERVER_POOL
from networking_bigswitch.tests.unit.bigswitch.mock_paths import \
SERVER_REST_CALL
from networking_bigswitch.tests.unit.bigswitch import test_router_db
from networking_bigswitch.tests.unit.bigswitch \
import test_base as bsn_test_base
class CapabilitiesTests(test_router_db.RouterDBTestBase):
def test_floating_ip_capability(self):
with\
mock.patch(SERVER_REST_CALL,
return_value=(200, None, '["floatingip"]', None)),\
mock.patch(SERVER_POOL + '.rest_create_floatingip',
return_value=(200, None, None, None)) as mock_create,\
mock.patch(SERVER_POOL + '.rest_delete_floatingip',
return_value=(200, None, None, None)) as mock_delete:
with self.floatingip_with_assoc() as fip:
# we have to grab the floating ip object from the service
# plugin since we send extra information not returned to the
# API caller
l3_plugin = directory.get_plugin(plugin_constants.L3)
fip = l3_plugin.get_floatingip(context.get_admin_context(),
fip['floatingip']['id'])
fip_port = l3_plugin.get_port(context.get_admin_context(),
fip['floating_port_id'])
fip['floating_mac_address'] = fip_port['mac_address']
mock_create.assert_has_calls(
[mock.call(fip['tenant_id'], fip)]
)
mock_delete.assert_has_calls(
[mock.call(fip['tenant_id'], fip['id'])]
)
def test_floating_ip_capability_neg(self):
with\
mock.patch(SERVER_REST_CALL,
return_value=(200, None, '[""]', None)),\
mock.patch(SERVER_POOL + '.rest_update_network',
return_value=(200, None, None, None)) as mock_netupdate:
with self.floatingip_with_assoc() as fip:
pass
updates = [call[0][2]['floatingips']
for call in mock_netupdate.call_args_list]
all_floats = [f['floating_ip_address']
for floats in updates for f in floats]
self.assertIn(fip['floatingip']['floating_ip_address'], all_floats)
class CapabilitiesTestsstCase(bsn_test_base.BigSwitchTestBase,
test_plugin.NeutronDbPluginV2TestCase):
def test_keep_alive_capability(self):
self.skipTest("cached connections are currently disabled because "


+ 1
- 187
networking_bigswitch/tests/unit/bigswitch/test_restproxy_agent.py View File

@ -22,9 +22,7 @@ from networking_bigswitch.tests.unit.bigswitch.mock_paths import AGENT_MOD
from networking_bigswitch.tests.unit.bigswitch.mock_paths import \
CONSUMER_CREATE
from networking_bigswitch.tests.unit.bigswitch.mock_paths import CONTEXT
from networking_bigswitch.tests.unit.bigswitch.mock_paths import IVS_BRIDGE
from networking_bigswitch.tests.unit.bigswitch.mock_paths import NEUTRON_CFG
from networking_bigswitch.tests.unit.bigswitch.mock_paths import NFV_SW_BRIDGE
from networking_bigswitch.tests.unit.bigswitch.mock_paths import OVS_BRIDGE
from networking_bigswitch.tests.unit.bigswitch.mock_paths import PL_CONFIG
from networking_bigswitch.tests.unit.bigswitch.mock_paths import PLUGIN_API
@ -165,7 +163,6 @@ class TestRestProxyAgent(BaseAgentTestCase):
def mock_main(self):
cfg_attrs = {'CONF.RESTPROXYAGENT.integration_bridge': 'integ_br',
'CONF.RESTPROXYAGENT.polling_interval': 5,
'CONF.RESTPROXYAGENT.virtual_switch_type': 'ovs',
'CONF.AGENT.root_helper': 'helper',
'CONF.AGENT.report_interval': 60}
with\
@ -186,189 +183,6 @@ class TestRestProxyAgent(BaseAgentTestCase):
self.assertRaises(SystemExit, self.mock_main)
mock_agent.assert_has_calls([
mock.call('integ_br', 5, 'ovs'),
mock.call('integ_br', 5),
mock.call().daemon_loop()
])
class TestRestProxyAgentIVS(TestRestProxyAgentOVS):
def setUp(self):
super(TestRestProxyAgentIVS, self).setUp()
# we don't want to mock out the whole class, just the part that
# tries to run commands on the system
self.ovsbridge_p.stop()
self.runvsctl = mock.patch(IVS_BRIDGE + '.run_vsctl').start()
def mock_agent(self):
mock_context = mock.Mock(return_value='abc')
self.context.get_admin_context_without_session = mock_context
# same as OVS case except passing 'ivs' for vswitch type
return self.mod_agent.RestProxyAgent('int-br', 2, vs='ivs')
def mock_update_ports(self, vif_port_set=None, registered_ports=None):
vif_port_set = vif_port_set or set()
registered_ports = registered_ports or set()
agent = self.mock_agent()
with mock.patch.object(agent.int_br,
'get_vif_port_set',
return_value=vif_port_set):
return agent._update_ports(registered_ports)
def test_port_update_not_vifport(self):
port = {'id': '1', 'security_groups': 'default'}
with mock.patch(IVS_BRIDGE + '.get_vif_port_by_id',
return_value=False) as get_vif:
self.mock_port_update(port=port)
get_vif.assert_called_once_with('1')
self.assertFalse(self.sg_agent.return_value.refresh_firewall.called)
def test_port_update_without_secgroup(self):
port = {'id': '1'}
with mock.patch(IVS_BRIDGE + '.get_vif_port_by_id',
return_value='1') as get_vif:
self.mock_port_update(port=port)
get_vif.assert_called_once_with('1')
self.assertFalse(self.sg_agent.return_value.refresh_firewall.called)
def test_port_update(self):
port = {'id': '1', 'security_groups': 'default'}
with mock.patch(IVS_BRIDGE + '.get_vif_port_by_id',
return_value='1') as get_vif:
self.mock_port_update(port=port)
get_vif.assert_called_once_with('1')
self.sg_agent.assert_has_calls([
mock.call().refresh_firewall()
])
def test_port_list_with_new_method(self):
agent = self.mock_agent()
self.runvsctl.return_value = "port1\nport2\nport3\n"
self.assertEqual(['port1', 'port2', 'port3'],
agent.int_br.get_port_name_list())
expected_calls = [mock.call(['list-ports'], True,
log_fail_as_error=False)]
self.assertEqual(expected_calls, self.runvsctl.mock_calls)
def test_port_list_fallback_to_show(self):
agent = self.mock_agent()
# fail the first call to 'list-ports' so it falls back to 'show'
self.runvsctl.side_effect = [RuntimeError(), IVS_SHOW_OUTPUT]
self.assertEqual(['ivs', 'p1p1', 'p1p2', 'os-mgmt',
'tapa40e6816-82', 'inband'],
agent.int_br.get_port_name_list())
expected_calls = [mock.call(['list-ports'], True,
log_fail_as_error=False),
mock.call(['show'], True)]
self.assertEqual(expected_calls, self.runvsctl.mock_calls)
# some test 'ivs-ctl show' data
IVS_SHOW_OUTPUT = '''
ovs-system:
kernel lookups: hit=7 missed=11 lost=0
kernel flows=0
ports:
0 ovs-system (internal)
rx: packets=0 bytes=0 errors=0 dropped=0
tx: packets=0 bytes=0 errors=0 dropped=0
1 bond0
rx: packets=0 bytes=0 errors=0 dropped=0
tx: packets=0 bytes=0 errors=0 dropped=0
2 br-int (internal)
rx: packets=0 bytes=0 errors=0 dropped=0
tx: packets=0 bytes=0 errors=0 dropped=0
3 vxlan_sys_4789 (unknown vport type)
rx: packets=0 bytes=0 errors=0 dropped=0
tx: packets=0 bytes=0 errors=0 dropped=0
4 br-tun (internal)
rx: packets=0 bytes=0 errors=0 dropped=0
tx: packets=0 bytes=0 errors=0 dropped=0
5 br-eth0 (internal)
rx: packets=0 bytes=0 errors=0 dropped=0
tx: packets=0 bytes=0 errors=0 dropped=0
6 br-ex (internal)
rx: packets=8 bytes=648 errors=0 dropped=0
tx: packets=0 bytes=0 errors=0 dropped=0
ivs:
kernel lookups: hit=19446 missed=2998 lost=1
kernel flows=1
ports:
0 ivs (internal)
rx: packets=0 bytes=0 errors=0 dropped=0
tx: packets=0 bytes=0 errors=0 dropped=0
1 p1p1
rx: packets=1863 bytes=232066 errors=0 dropped=0
tx: packets=1210 bytes=100440 errors=0 dropped=0
2 p1p2
rx: packets=0 bytes=0 errors=0 dropped=0
tx: packets=0 bytes=0 errors=0 dropped=0
3 os-mgmt (internal)
rx: packets=8 bytes=648 errors=0 dropped=0
tx: packets=0 bytes=0 errors=0 dropped=0
4 tapa40e6816-82
rx: packets=8 bytes=648 errors=0 dropped=0
tx: packets=0 bytes=0 errors=0 dropped=0
1000 inband (internal)
rx: packets=20565 bytes=1768550 errors=0 dropped=0
tx: packets=586 bytes=50368 errors=0 dropped=0'''
class TestRestProxyAgentNFVSwitch(TestRestProxyAgentOVS):
def setUp(self):
super(TestRestProxyAgentNFVSwitch, self).setUp()
# we don't want to mock out the whole class, just the part that
# tries to run commands on the system
self.ovsbridge_p.stop()
def mock_agent(self):
mock_context = mock.Mock(return_value='abc')
self.context.get_admin_context_without_session = mock_context
# same as OVS case except passing 'nfvswitch' for vswitch type
return self.mod_agent.RestProxyAgent('int-br', 2, vs='nfvswitch')
def mock_update_ports(self, vif_port_set=None, registered_ports=None):
vif_port_set = vif_port_set or set()
registered_ports = registered_ports or set()
agent = self.mock_agent()
with mock.patch.object(agent.int_br,
'get_vif_port_set',
return_value=vif_port_set):
return agent._update_ports(registered_ports)
def test_port_update_not_vifport(self):
port = {'id': '1', 'security_groups': 'default'}