Browse Source

OSP-250: Add support for python3

This PR did a few changes that are mostly related to Python3:

- Convert iterators to lists as needed
- Separate most mock paths and store in an individual file
- Use http.client for py3 (handled by six)
- Use upstream HTTPS Connection directly, instead of a customed one
- Update requirements and project configs
- Fix various compatibility issues
- Oranization/Refactor
- Use explicted calls for super
- Other minor fix/improvements

Change-Id: I186f182de82cb9da2ea8215da374bd42eaf1767a
tags/14.0.0
Weifan Fu 1 year ago
parent
commit
206be47aa2
29 changed files with 509 additions and 533 deletions
  1. 12
    0
      .zuul.yaml
  2. 1
    1
      networking_bigswitch/__init__.py
  3. 3
    3
      networking_bigswitch/plugins/bigswitch/agent/restproxy_agent.py
  4. 1
    2
      networking_bigswitch/plugins/bigswitch/config.py
  5. 4
    7
      networking_bigswitch/plugins/bigswitch/l3_router_plugin.py
  6. 2
    2
      networking_bigswitch/plugins/bigswitch/plugin.py
  7. 113
    59
      networking_bigswitch/plugins/bigswitch/servermanager.py
  8. 2
    0
      networking_bigswitch/plugins/bigswitch/utils.py
  9. 1
    2
      networking_bigswitch/plugins/bigswitch/version.py
  10. 7
    7
      networking_bigswitch/plugins/ml2/drivers/mech_bigswitch/driver.py
  11. 6
    45
      networking_bigswitch/tests/unit/bigswitch/fake_server.py
  12. 93
    0
      networking_bigswitch/tests/unit/bigswitch/mock_paths.py
  13. 3
    3
      networking_bigswitch/tests/unit/bigswitch/test_agent_scheduler.py
  14. 30
    32
      networking_bigswitch/tests/unit/bigswitch/test_base.py
  15. 10
    11
      networking_bigswitch/tests/unit/bigswitch/test_capabilities.py
  16. 2
    1
      networking_bigswitch/tests/unit/bigswitch/test_networktemplate_db.py
  17. 2
    1
      networking_bigswitch/tests/unit/bigswitch/test_networktemplateassignment_db.py
  18. 2
    1
      networking_bigswitch/tests/unit/bigswitch/test_reachabilityquicktest_db.py
  19. 2
    1
      networking_bigswitch/tests/unit/bigswitch/test_reachabilitytest_db.py
  20. 31
    31
      networking_bigswitch/tests/unit/bigswitch/test_restproxy_agent.py
  21. 15
    15
      networking_bigswitch/tests/unit/bigswitch/test_restproxy_plugin.py
  22. 13
    13
      networking_bigswitch/tests/unit/bigswitch/test_router_db.py
  23. 2
    2
      networking_bigswitch/tests/unit/bigswitch/test_security_groups.py
  24. 69
    127
      networking_bigswitch/tests/unit/bigswitch/test_servermanager.py
  25. 38
    157
      networking_bigswitch/tests/unit/bigswitch/test_ssl.py
  26. 7
    8
      networking_bigswitch/tests/unit/ml2/drivers/test_bigswitch_mech.py
  27. 22
    1
      requirements.txt
  28. 3
    0
      setup.cfg
  29. 13
    1
      tox.ini

+ 12
- 0
.zuul.yaml View File

@@ -20,6 +20,14 @@
required-projects:
- name: openstack/neutron
- name: openstack/tap-as-a-service
- openstack-tox-py35:
required-projects:
- name: openstack/neutron
- name: openstack/tap-as-a-service
- openstack-tox-py36:
required-projects:
- name: openstack/neutron
- name: openstack/tap-as-a-service
gate:
jobs:
- openstack-tox-pep8:
@@ -30,3 +38,7 @@
required-projects:
- name: openstack/neutron
- name: openstack/tap-as-a-service
- openstack-tox-py35:
required-projects:
- name: openstack/neutron
- name: openstack/tap-as-a-service

+ 1
- 1
networking_bigswitch/__init__.py View File

@@ -14,8 +14,8 @@
# under the License.

import gettext
import six

import six

if six.PY2:
# E1123: unexpected keyword argument

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

@@ -92,13 +92,13 @@ class IVSBridge(object):
try:
resp = self.run_vsctl(['list-ports'], True,
log_fail_as_error=False).strip().splitlines()
port_names = map(lambda x: x.strip(), resp)
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 = map(lambda x: x.strip().split(' ')[1], ports)
port_names = [x.strip().split(' ')[1] for x in ports]
LOG.debug("Ports on IVS: %s", port_names)
return port_names

@@ -174,7 +174,7 @@ class FilterDeviceIDMixin(sg_rpc.SecurityGroupAgentRpc):
self.firewall.prepare_port_filter(device)
if self.use_enhanced_rpc:
LOG.debug("Update security group information for ports %s",
devices.keys())
list(devices.keys()))
self._update_security_group_info(
security_groups, security_group_member_ips)


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

@@ -17,11 +17,10 @@
This module manages configuration options
"""

from oslo_config import cfg

from neutron.conf.agent import common as agconfig
from neutron_lib.api.definitions import portbindings
from neutron_lib.utils import net
from oslo_config import cfg

restproxy_opts = [
cfg.ListOpt('servers', default=['localhost:8800'],

+ 4
- 7
networking_bigswitch/plugins/bigswitch/l3_router_plugin.py View File

@@ -22,16 +22,9 @@ Big Switch core plugin.
"""
import copy

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 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
@@ -41,6 +34,10 @@ from neutron_lib.db import api as db_api
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

+ 2
- 2
networking_bigswitch/plugins/bigswitch/plugin.py View File

@@ -42,7 +42,6 @@ on port-attach) on an additional PUT to do a bulk dump of all persistent data.

import copy
import functools
import httplib
import re

import eventlet
@@ -50,6 +49,7 @@ from oslo_config import cfg
from oslo_log import log as logging
import oslo_messaging
from oslo_utils import importutils
from six.moves import http_client
from sqlalchemy.orm import exc as sqlexc

from neutron.agent import rpc as agent_rpc
@@ -928,7 +928,7 @@ class NeutronRestProxyV2Base(db_base_plugin_v2.NeutronDbPluginV2,
# and the data in the backend.
# Run a sync to get it consistent.
if (cfg.CONF.RESTPROXY.auto_sync_on_failure and
e.status == httplib.NOT_FOUND and
e.status == http_client.NOT_FOUND and
servermanager.NXNETWORK in e.reason):
LOG.error("Inconsistency with backend controller "
"triggering full synchronization.")

+ 113
- 59
networking_bigswitch/plugins/bigswitch/servermanager.py View File

@@ -27,32 +27,32 @@ The following functionality is handled by this module:

"""
import base64
import httplib
import os
import re
import socket
import ssl
import time

from neutron_lib import exceptions

from oslo_log import log as logging

import eventlet
import eventlet.corolocal
from keystoneauth1.identity import v3
from keystoneauth1 import session
from keystoneclient.v3 import client as ksclient
from neutron_lib import exceptions
from oslo_config import cfg
from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import excutils
import six
from six.moves import http_client
from sqlalchemy.types import Enum

from networking_bigswitch.plugins.bigswitch.db import consistency_db as cdb
from networking_bigswitch.plugins.bigswitch.i18n import _
from networking_bigswitch.plugins.bigswitch.i18n import _LE
from networking_bigswitch.plugins.bigswitch.i18n import _LI
from networking_bigswitch.plugins.bigswitch.i18n import _LW
from networking_bigswitch.plugins.bigswitch.utils import Util
import os
from oslo_config import cfg
from oslo_serialization import jsonutils
from oslo_utils import excutils
from sqlalchemy.types import Enum

LOG = logging.getLogger(__name__)

@@ -97,7 +97,7 @@ HTTP_SERVICE_UNAVAILABLE_RETRY_INTERVAL = 3

KEYSTONE_SYNC_RATE_LIMIT = 30 # Limit KeyStone sync to once in 30 secs
# TOPO_SYNC Responses
TOPO_RESPONSE_OK = (httplib.OK, httplib.OK, True, True)
TOPO_RESPONSE_OK = (http_client.OK, http_client.OK, True, True)
TOPO_RESPONSE_FAIL = (0, None, None, None)

# RE pattern for checking BCF supported names
@@ -252,11 +252,11 @@ def get_keystoneauth_cfg(conf, name):
class ServerProxy(object):
"""REST server proxy to a network controller."""

def __init__(self, server, port, ssl, auth, neutron_id, timeout,
def __init__(self, server, port, is_ssl_enabled, auth, neutron_id, timeout,
base_uri, name, mypool, combined_cert):
self.server = server
self.port = port
self.ssl = ssl
self.is_ssl_enabled = is_ssl_enabled
self.base_uri = base_uri
self.timeout = timeout
self.name = name
@@ -268,16 +268,40 @@ class ServerProxy(object):
self.capabilities = []
# enable server to reference parent pool
self.mypool = mypool
# cache connection here to avoid a SSL handshake for every connection
self.currentconn = None

# TODO(weifan): cache connection to avoid a SSL handshake for every
# connection
self.cached_conn = None

# ssl_context is the new standard interface for handling certificates
# initialize ssl context
self.ssl_context = None

if auth:
if ':' in auth:
self.auth = 'Basic ' + base64.encodestring(auth).strip()
if six.PY2:
self.auth = 'Basic ' + base64.encodestring(auth).strip()
else:
self.auth = 'Basic ' + base64.b64encode(auth.encode(
'utf-8')).decode('utf-8')
else:
self.auth_token = 'session_cookie="' + auth + '"'

self.combined_cert = combined_cert
if is_ssl_enabled:
# initialize ssl context
self.ssl_context = None

# Uses PROTOCOL_TLS (new default)
# or PROTOCOL_SSLv23(deprecated, old default)
# both works with BCF TLS connections
self.ssl_context = ssl.create_default_context(cafile=combined_cert)

if six.PY2:
# Monkey Patch to skip hostname check for ssl in py2
# There is a bug with the old version
ssl.match_hostname = lambda cert, hostname: True
else:
self.ssl_context.check_hostname = False

def get_capabilities(self):
try:
@@ -317,8 +341,9 @@ class ServerProxy(object):
headers['Authorization'] = self.auth

LOG.debug("ServerProxy: server=%(server)s, port=%(port)d, "
"ssl=%(ssl)r",
{'server': self.server, 'port': self.port, 'ssl': self.ssl})
"is_ssl_enabled=%(is_ssl_enabled)r",
{'server': self.server, 'port': self.port,
'is_ssl_enabled': self.is_ssl_enabled})
LOG.debug("ServerProxy: resource=%(resource)s, data=%(data)r, "
"headers=%(headers)r, action=%(action)s",
{'resource': resource, 'data': data, 'headers': headers,
@@ -333,26 +358,39 @@ class ServerProxy(object):
# need a new connection if timeout has changed
reconnect = True

if not self.currentconn or reconnect:
if self.currentconn:
self.currentconn.close()
if self.ssl:
currentconn = HTTPSConnectionWithValidation(
self.server, self.port, timeout=timeout)
if not self.cached_conn or reconnect:
if self.cached_conn:
self.cached_conn.close()
if self.is_ssl_enabled:
currentconn = http_client.HTTPSConnection(
self.server, self.port, timeout=timeout,
context=self.ssl_context)

if currentconn is None:
LOG.error('ServerProxy: Could not establish HTTPS '
'connection')
return 0, None, None, None
currentconn.combined_cert = self.combined_cert

# TODO(weifan): cache connection and reuse
# require keep-alive
# self.cached_conn = currentconn

else:
currentconn = httplib.HTTPConnection(
currentconn = http_client.HTTPConnection(
self.server, self.port, timeout=timeout)
if currentconn is None:
LOG.error('ServerProxy: Could not establish HTTP '
'connection')
return 0, None, None, None

# TODO(weifan): cache connection and reuse
# require keep-alive
# self.cached_conn = currentconn

try:
# TODO(weifan): use cache connection instead of currentconn
# require keep alive

bcf_request_time = time.time()
currentconn.request(action, uri, body, headers)
response = currentconn.getresponse()
@@ -369,7 +407,12 @@ class ServerProxy(object):
pass

ret = (response.status, response.reason, respstr, respdata)
except httplib.HTTPException:

# TODO(weifan): use cache connection
# currently closing every connection after use
currentconn.close()

except http_client.HTTPException:
# If we were using a cached connection, try again with a new one.
with excutils.save_and_reraise_exception() as ctxt:
currentconn.close()
@@ -393,6 +436,7 @@ class ServerProxy(object):
'reason': ret[1],
'ret': ret[2],
'data': ret[3]})

return ret


@@ -415,7 +459,7 @@ class ServerPool(object):
# till next failure). Use 'server_auth' to encode api-key
servers = cfg.CONF.RESTPROXY.servers
self.auth = cfg.CONF.RESTPROXY.server_auth
self.ssl = cfg.CONF.RESTPROXY.server_ssl
self.is_ssl_enabled = cfg.CONF.RESTPROXY.server_ssl
self.neutron_id = cfg.CONF.RESTPROXY.neutron_id
# unicode config
self.cfg_unicode_enabled = cfg.CONF.RESTPROXY.naming_scheme_unicode
@@ -609,9 +653,12 @@ class ServerPool(object):
return False

def server_proxy_for(self, server, port):
# TODO(weifan): use ssl_context to load certificates instead of our
# own codes
combined_cert = self._get_combined_cert_for_server(server, port)
return ServerProxy(server, port, self.ssl, self.auth, self.neutron_id,
self.timeout, self.base_uri, self.name, mypool=self,
return ServerProxy(server, port, self.is_ssl_enabled, self.auth,
self.neutron_id, self.timeout, self.base_uri,
self.name, mypool=self,
combined_cert=combined_cert)

def _get_combined_cert_for_server(self, server, port):
@@ -619,7 +666,7 @@ class ServerPool(object):
# so we make one containing the trusted CAs and the corresponding
# host cert for this server
combined_cert = None
if self.ssl and not cfg.CONF.RESTPROXY.no_ssl_validation:
if self.is_ssl_enabled and not cfg.CONF.RESTPROXY.no_ssl_validation:
base_ssl = cfg.CONF.RESTPROXY.ssl_cert_directory
host_dir = os.path.join(base_ssl, 'host_certs')
ca_dir = os.path.join(base_ssl, 'ca_certs')
@@ -675,15 +722,45 @@ class ServerPool(object):
if name.endswith('.pem')]
return certs

def py34_get_server_certificate(self, server_info):
"""Temp Fix for py34

:param server_info: (server, port) # tuple
:return:
"""
# There is some issue with ssl.get_server_certificate in PY3.4
# 'with' statements are causing __exit__ errors
# The code here is basically duplicate logic of upstream ssl
# Except that it does not use 'with' keyword
# https://github.com/python/cpython/blob/3.4/Lib/ssl.py#L933
# Note: This error is only observed in OSP, it seems to work in
# interactive console.
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
conn = socket.create_connection(server_info)
ssl_sock = ctx.wrap_socket(conn)
dercert = ssl_sock.getpeercert(True)
cert = ssl.DER_cert_to_PEM_cert(dercert)
ssl_sock.close()
conn.close()
return cert

def _fetch_and_store_cert(self, server, port, path):
"""_fetch_and_store_cert

Grabs a certificate from a server and writes it to
a given path.
"""

try:
cert = ssl.get_server_certificate((server, port),
ssl_version=ssl.PROTOCOL_SSLv23)
if six.PY2:
# TODO(weifan): Test if this works in PY3.5
# or some later PY3 versions
cert = ssl.get_server_certificate((server, port))
else:
cert = self.py34_get_server_certificate((server, port))

except Exception as e:
raise cfg.Error(_('Could not retrieve initial '
'certificate from controller %(server)s. '
@@ -692,6 +769,7 @@ class ServerPool(object):

LOG.warning("Storing to certificate for host %(server)s "
"at %(path)s", {'server': server, 'path': path})

self._file_put_contents(path, cert)

return cert
@@ -734,7 +812,7 @@ class ServerPool(object):
ret = active_server.rest_call(action, resource, data, headers,
timeout,
reconnect=self.always_reconnect)
if ret[0] != httplib.SERVICE_UNAVAILABLE:
if ret[0] != http_client.SERVICE_UNAVAILABLE:
break
eventlet.sleep(HTTP_SERVICE_UNAVAILABLE_RETRY_INTERVAL)

@@ -1186,27 +1264,3 @@ class ServerPool(object):
while True:
eventlet.sleep(polling_interval)
self._update_tenant_cache()


class HTTPSConnectionWithValidation(httplib.HTTPSConnection):

# If combined_cert is None, the connection will continue without
# any certificate validation.
combined_cert = None

def connect(self):
sock = socket.create_connection((self.host, self.port),
self.timeout, self.source_address)
if self._tunnel_host:
self.sock = sock
self._tunnel()

if self.combined_cert:
self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
cert_reqs=ssl.CERT_REQUIRED,
ca_certs=self.combined_cert,
ssl_version=ssl.PROTOCOL_SSLv23)
else:
self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
cert_reqs=ssl.CERT_NONE,
ssl_version=ssl.PROTOCOL_SSLv23)

+ 2
- 0
networking_bigswitch/plugins/bigswitch/utils.py View File

@@ -14,6 +14,8 @@
# under the License.
from neutron_lib import exceptions as n_exc

from networking_bigswitch.plugins.bigswitch.i18n import _


class Util(object):
"""Util

+ 1
- 2
networking_bigswitch/plugins/bigswitch/version.py View File

@@ -24,8 +24,7 @@ YEAR, COUNT, REVISION = vcsversion.NEUTRONRESTPROXY_VERSION


def canonical_version_string():
return '.'.join(filter(None,
vcsversion.NEUTRONRESTPROXY_VERSION))
return '.'.join([_f for _f in vcsversion.NEUTRONRESTPROXY_VERSION if _f])


def version_string():

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

@@ -14,15 +14,9 @@
# under the License.
import copy
import datetime
import httplib
import os

import eventlet
from oslo_config import cfg
from oslo_log import log
import oslo_messaging
from oslo_utils import excutils
from oslo_utils import timeutils

from neutron.extensions import securitygroup as ext_sg
from neutron_lib.api.definitions import portbindings
@@ -34,6 +28,12 @@ from neutron_lib import context as ctx
from neutron_lib.plugins import directory
from neutron_lib.plugins.ml2 import api
from neutron_lib import rpc as lib_rpc
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.i18n import _
@@ -391,7 +391,7 @@ class BigSwitchMechanismDriver(plugin.NeutronRestProxyV2Base,
except servermanager.RemoteRestError as e:
with excutils.save_and_reraise_exception() as ctxt:
if (cfg.CONF.RESTPROXY.auto_sync_on_failure and
e.status == httplib.NOT_FOUND and
e.status == http_client.NOT_FOUND and
servermanager.NXNETWORK in e.reason):
ctxt.reraise = False
LOG.error("Inconsistency with backend controller "

+ 6
- 45
networking_bigswitch/tests/unit/bigswitch/fake_server.py View File

@@ -58,7 +58,7 @@ class HTTPResponseMock500(HTTPResponseMock):

class HTTPConnectionMock(object):

def __init__(self, server, port, timeout):
def __init__(self, host, port, timeout):
self.response = None
self.broken = False
# Port 9000 is the broken server
@@ -101,14 +101,14 @@ class HTTPConnectionMock(object):

class HTTPConnectionMock404(HTTPConnectionMock):

def __init__(self, server, port, timeout):
def __init__(self, host, port, timeout):
self.response = HTTPResponseMock404(None)
self.broken = True


class HTTPConnectionMock500(HTTPConnectionMock):

def __init__(self, server, port, timeout):
def __init__(self, host, port, timeout):
self.response = HTTPResponseMock500(None)
self.broken = True

@@ -138,47 +138,8 @@ class VerifyMultiTenantFloatingIP(HTTPConnectionMock):


class HTTPSMockBase(HTTPConnectionMock):
expected_cert = ''
combined_cert = None

def __init__(self, host, port=None, key_file=None, cert_file=None,
strict=None, timeout=None, source_address=None):
def __init__(self, host, port=None, context=None, timeout=None,
source_address=None):
self.host = host
self.ssl_context = context
super(HTTPSMockBase, self).__init__(host, port, timeout)

def request(self, method, url, body=None, headers=None):
self.connect()
if headers is None:
headers = {}
super(HTTPSMockBase, self).request(method, url, body, headers)


class HTTPSNoValidation(HTTPSMockBase):

def connect(self):
if self.combined_cert:
raise Exception('combined_cert set on NoValidation')


class HTTPSCAValidation(HTTPSMockBase):
expected_cert = 'DUMMYCERTIFICATEAUTHORITY'

def connect(self):
contents = get_cert_contents(self.combined_cert)
if self.expected_cert not in contents:
raise Exception('No dummy CA cert in cert_file')


class HTTPSHostValidation(HTTPSMockBase):
expected_cert = 'DUMMYCERTFORHOST%s'

def connect(self):
contents = get_cert_contents(self.combined_cert)
expected = self.expected_cert % self.host
if expected not in contents:
raise Exception(_('No host cert for %(server)s in cert %(cert)s'),
{'server': self.host, 'cert': contents})


def get_cert_contents(path):
raise Exception('METHOD MUST BE MOCKED FOR TEST')

+ 93
- 0
networking_bigswitch/tests/unit/bigswitch/mock_paths.py View File

@@ -0,0 +1,93 @@
# Copyright 2018 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.

import six

"""For storing paths used for mocking, this is used in various test files.
"""
# Keystone
KEYSTONE_CLIENT = 'keystoneclient.v3.client.Client'

# Neutron
DHCP_NOTIFIER = ('neutron.api.rpc.agentnotifiers.dhcp_rpc_agent_api'
'.DhcpAgentNotifyAPI.notify')

NEUTRON_AGENT = 'neutron.agent'
OVS_BRIDGE = NEUTRON_AGENT + '.common.ovs_lib.OVSBridge'
PLUGIN_API = NEUTRON_AGENT + '.rpc.PluginApi'
CONSUMER_CREATE = NEUTRON_AGENT + '.rpc.create_consumers'

SG_RPC = NEUTRON_AGENT + '.securitygroups_rpc'

CONTEXT = 'neutron_lib.context'

NEUTRON_CFG = 'neutron.common.config'
LIB_RPC_TRANSPORT = 'neutron_lib.rpc.TRANSPORT'

# BSN
BSN_DIR = 'networking_bigswitch.plugins.bigswitch'

# Config
PL_CONFIG = BSN_DIR + '.config'

# DB
CONSISTENCY_DB = BSN_DIR + '.db.consistency_db'

# Driver
DRIVER_MOD = 'networking_bigswitch.plugins.ml2.drivers.mech_bigswitch.driver'
DRIVER = DRIVER_MOD + '.BigSwitchMechanismDriver'


# plugin/l3_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'
SPAWN = PLUGIN_PATH + '.eventlet.GreenPool.spawn_n'
MAP_DISPLAY_NAME_OR_TENANT = (PLUGIN_PATH + '.NeutronRestProxyV2Base'
'._map_display_name_or_tenant')

# 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'
SERVER_REST_CALL = SERVER_MANAGER + '.ServerProxy.rest_call'
HTTPCON = SERVER_MANAGER + '.http_client.HTTPConnection'
HTTPSCON = SERVER_MANAGER + '.http_client.HTTPSConnection'

SERVER_POOL = SERVER_MANAGER + '.ServerPool'
POOL_REST_ACTION = SERVER_POOL + '.rest_action'
POOL_REST_CALL = SERVER_POOL + '.rest_call'
BACKGROUND = SERVER_POOL + '.start_background_tasks'
POOL_TOPO_SYNC = SERVER_POOL + '.force_topo_sync'
POOL_UPDATE_TENANT_CACHE = SERVER_POOL + '._update_tenant_cache'
POOL_GET_CAPABILITIES = SERVER_POOL + '.get_capabilities'
IS_UNICODE_ENABLED = SERVER_POOL + '.is_unicode_enabled'

# SSL Cert Related
if six.PY2:
GET_SERVER_CERTIFICATE = SERVER_MANAGER + '.ssl.get_server_certificate'
else:
GET_SERVER_CERTIFICATE = SERVER_POOL + '.py34_get_server_certificate'
SSL_CREATE_DEFAULT_CONTEXT = SERVER_MANAGER + '.ssl.create_default_context'
CERT_COMBINER = SERVER_POOL + '._combine_certs_to_file'
FILE_PUT = SERVER_POOL + '._file_put_contents'
GET_CA_CERTS = SERVER_POOL + '._get_ca_cert_paths'

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

@@ -13,9 +13,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from neutron.tests.unit.db import test_agentschedulers_db

from networking_bigswitch.tests.unit.bigswitch import test_base
from neutron.tests.unit.db import test_agentschedulers_db


class BigSwitchDhcpAgentNotifierTestCase(
@@ -23,12 +23,12 @@ class BigSwitchDhcpAgentNotifierTestCase(
test_base.BigSwitchTestBase):

plugin_str = ('%s.NeutronRestProxyV2' %
test_base.RESTPROXY_PKG_PATH)
test_base.PLUGIN_PATH)

def setUp(self):
self.setup_config_files()
self.setup_patches()
super(BigSwitchDhcpAgentNotifierTestCase, self).setUp()
test_agentschedulers_db.OvsDhcpAgentNotifierTestCase.setUp(self)
self.setup_db()
self.startHttpPatch()
self.dhcp_notifier_p.stop()

+ 30
- 32
networking_bigswitch/tests/unit/bigswitch/test_base.py View File

@@ -17,10 +17,9 @@
import os

import mock
from oslo_config import cfg

import neutron.common.test_lib as test_lib
from neutron.db import api # noqa
from oslo_config import cfg

from networking_bigswitch.plugins.bigswitch import config
from networking_bigswitch.plugins.bigswitch.db import consistency_db
@@ -31,36 +30,32 @@ from networking_bigswitch.plugins.bigswitch.servermanager\
import TOPO_RESPONSE_OK
from networking_bigswitch.tests.unit.bigswitch import fake_server


RESTPROXY_PKG_PATH = 'networking_bigswitch.plugins.bigswitch.plugin'
L3_RESTPROXY_PKG_PATH = ('networking_bigswitch.plugins.bigswitch'
'.l3_router_plugin')
BSN_SERVICE_PLUGIN_PATH = ('networking_bigswitch.plugins.bigswitch'
'.bsn_service_plugin')
NOTIFIER = 'networking_bigswitch.plugins.bigswitch.plugin.AgentNotifierApi'
DHCP_NOTIFIER = ('neutron.api.rpc.agentnotifiers.dhcp_rpc_agent_api.'
'DhcpAgentNotifyAPI.notify')
CERTFETCH = ('networking_bigswitch.plugins.bigswitch.servermanager.ServerPool'
'._fetch_cert') # noqa
SERVER_MANAGER = 'networking_bigswitch.plugins.bigswitch.servermanager'
HTTPCON = ('networking_bigswitch.plugins.bigswitch.servermanager.httplib'
'.HTTPConnection')
SPAWN = ('networking_bigswitch.plugins.bigswitch.plugin.eventlet.GreenPool'
'.spawn_n')
KSCLIENT = 'keystoneclient.v3.client.Client'
BACKGROUND = SERVER_MANAGER + '.ServerPool.start_background_tasks'
MAP_DISPLAY_NAME_OR_TENANT = ('networking_bigswitch.plugins.bigswitch.plugin.'
'NeutronRestProxyV2Base.'
'_map_display_name_or_tenant')
IS_UNICODE_ENABLED = ('networking_bigswitch.plugins.bigswitch.servermanager.'
'ServerPool.is_unicode_enabled')
LIB_RPC_TRANSPORT = ('neutron_lib.rpc.TRANSPORT')
from networking_bigswitch.tests.unit.bigswitch.mock_paths import BACKGROUND
from networking_bigswitch.tests.unit.bigswitch.mock_paths import \
BSN_SERVICE_PLUGIN_PATH
from networking_bigswitch.tests.unit.bigswitch.mock_paths import DHCP_NOTIFIER
from networking_bigswitch.tests.unit.bigswitch.mock_paths import HTTPCON
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 \
MAP_DISPLAY_NAME_OR_TENANT
from networking_bigswitch.tests.unit.bigswitch.mock_paths import NOTIFIER
from networking_bigswitch.tests.unit.bigswitch.mock_paths import PLUGIN_PATH
from networking_bigswitch.tests.unit.bigswitch.mock_paths import \
POOL_TOPO_SYNC
from networking_bigswitch.tests.unit.bigswitch.mock_paths import SERVER_MANAGER
from networking_bigswitch.tests.unit.bigswitch.mock_paths import SPAWN


class BigSwitchTestBase(object):

_plugin_name = ('%s.NeutronRestProxyV2' % RESTPROXY_PKG_PATH)
_l3_plugin_name = ('%s.L3RestProxy' % L3_RESTPROXY_PKG_PATH)
_plugin_name = ('%s.NeutronRestProxyV2' % PLUGIN_PATH)
_l3_plugin_name = ('%s.L3RestProxy' % L3_PLUGIN_PATH)
_bsn_service_plugin_name = ('%s.BSNServicePlugin'
% BSN_SERVICE_PLUGIN_PATH)

@@ -101,20 +96,24 @@ class BigSwitchTestBase(object):
# disable exception log to prevent json parse error from showing
self.log_exc_p = mock.patch(SERVER_MANAGER + ".LOG.exception",
new=lambda *args, **kwargs: None)
self.ksclient_p = mock.patch(KSCLIENT)

self.ksclient_p = mock.patch(KEYSTONE_CLIENT)

self.map_display_name_or_tenant_p = mock.patch(
MAP_DISPLAY_NAME_OR_TENANT,
side_effect=self.map_tenant_name_side_effect)
self.is_unicode_enabled_p = mock.patch(
IS_UNICODE_ENABLED,
side_effect=self.is_unicode_enabled_side_effect)
# TODO(weifan): Find out why Mocking Transport does not work
# This mock fixes problems on zuul, but it is still broken locally
self.lib_rpc_transport_p = mock.patch(LIB_RPC_TRANSPORT)
# start all mock patches
self.log_exc_p.start()
self.plugin_notifier_p.start()
self.dhcp_notifier_p.start()
self.spawn_p.start()
self.watch_p.start()
self.dhcp_notifier_p.start()
self.ksclient_p.start()
self.map_display_name_or_tenant_p.start()
self.is_unicode_enabled_p.start()
@@ -127,8 +126,7 @@ class BigSwitchTestBase(object):

def startTopoSyncPatch(self):
self.topo_sync_p = \
mock.patch(SERVER_MANAGER + '.ServerPool.force_topo_sync',
return_value=(True, TOPO_RESPONSE_OK))
mock.patch(POOL_TOPO_SYNC, return_value=(True, TOPO_RESPONSE_OK))
self.topo_sync_p.start()

def setup_db(self):

+ 10
- 11
networking_bigswitch/tests/unit/bigswitch/test_capabilities.py View File

@@ -22,22 +22,21 @@ from neutron_lib.plugins import directory

from networking_bigswitch.tests.unit.bigswitch import test_router_db

PLUGIN = 'networking_bigswitch.plugins.bigswitch.plugin'
SERVERMANAGER = PLUGIN + '.servermanager'
SERVERPOOL = SERVERMANAGER + '.ServerPool'
SERVERRESTCALL = SERVERMANAGER + '.ServerProxy.rest_call'
HTTPCON = SERVERMANAGER + '.httplib.HTTPConnection'
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


class CapabilitiesTests(test_router_db.RouterDBTestBase):

def test_floating_ip_capability(self):
with\
mock.patch(SERVERRESTCALL,
mock.patch(SERVER_REST_CALL,
return_value=(200, None, '["floatingip"]', None)),\
mock.patch(SERVERPOOL + '.rest_create_floatingip',
mock.patch(SERVER_POOL + '.rest_create_floatingip',
return_value=(200, None, None, None)) as mock_create,\
mock.patch(SERVERPOOL + '.rest_delete_floatingip',
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
@@ -58,9 +57,9 @@ class CapabilitiesTests(test_router_db.RouterDBTestBase):

def test_floating_ip_capability_neg(self):
with\
mock.patch(SERVERRESTCALL,
mock.patch(SERVER_REST_CALL,
return_value=(200, None, '[""]', None)),\
mock.patch(SERVERPOOL + '.rest_update_network',
mock.patch(SERVER_POOL + '.rest_update_network',
return_value=(200, None, None, None)) as mock_netupdate:
with self.floatingip_with_assoc() as fip:
pass
@@ -75,7 +74,7 @@ class CapabilitiesTests(test_router_db.RouterDBTestBase):
"their assignment to the servermanager object is not "
"thread-safe")
with mock.patch(
SERVERRESTCALL, return_value=(200, None, '["keep-alive"]', None)
SERVER_REST_CALL, return_value=(200, None, '["keep-alive"]', None)
):
# perform a task to cause capabilities to be retrieved
with self.floatingip_with_assoc():

+ 2
- 1
networking_bigswitch/tests/unit/bigswitch/test_networktemplate_db.py View File

@@ -14,10 +14,11 @@
#
# Adapted from neutron.tests.unit.db.test_agents_db.py

from networking_bigswitch.plugins.bigswitch.db import network_template_db
from neutron.tests.unit import testlib_api
from neutron_lib import context

from networking_bigswitch.plugins.bigswitch.db import network_template_db


class TestNetworkTemplateDbMixin(testlib_api.SqlTestCase):
def setUp(self):

+ 2
- 1
networking_bigswitch/tests/unit/bigswitch/test_networktemplateassignment_db.py View File

@@ -14,10 +14,11 @@
#
# Adapted from neutron.tests.unit.db.test_agents_db.py

from networking_bigswitch.plugins.bigswitch.db import network_template_db
from neutron.tests.unit import testlib_api
from neutron_lib import context

from networking_bigswitch.plugins.bigswitch.db import network_template_db


class TestNetworkTemplateAssignmentDbMixin(testlib_api.SqlTestCase):
def setUp(self):

+ 2
- 1
networking_bigswitch/tests/unit/bigswitch/test_reachabilityquicktest_db.py View File

@@ -14,10 +14,11 @@
#
# Adapted from neutron.tests.unit.db.test_agents_db.py

from networking_bigswitch.plugins.bigswitch.db import reachability_test_db
from neutron.tests.unit import testlib_api
from neutron_lib import context

from networking_bigswitch.plugins.bigswitch.db import reachability_test_db


class TestReachabilityQuickTestDbMixin(testlib_api.SqlTestCase):
def setUp(self):

+ 2
- 1
networking_bigswitch/tests/unit/bigswitch/test_reachabilitytest_db.py View File

@@ -14,10 +14,11 @@
#
# Adapted from neutron.tests.unit.db.test_agents_db.py

from networking_bigswitch.plugins.bigswitch.db import reachability_test_db
from neutron.tests.unit import testlib_api
from neutron_lib import context

from networking_bigswitch.plugins.bigswitch.db import reachability_test_db


class TestReachabilityTestDbMixin(testlib_api.SqlTestCase):
def setUp(self):

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

@@ -14,23 +14,23 @@
# under the License.

import mock
from oslo_utils import importutils

from neutron.tests import base
from oslo_utils import importutils

from networking_bigswitch.plugins.bigswitch import config as pl_config

OVSBRIDGE = 'neutron.agent.common.ovs_lib.OVSBridge'
PLUGINAPI = 'neutron.agent.rpc.PluginApi'
CONTEXT = 'neutron_lib.context'
CONSUMERCREATE = 'neutron.agent.rpc.create_consumers'
SGRPC = 'neutron.agent.securitygroups_rpc'
AGENTMOD = 'networking_bigswitch.plugins.bigswitch.agent.restproxy_agent'
SGAGENT = AGENTMOD + '.FilterDeviceIDMixin'
IVSBRIDGE = AGENTMOD + '.IVSBridge'
NFVSWBRIDGE = AGENTMOD + '.NFVSwitchBridge'
NEUTRONCFG = 'neutron.common.config'
PLCONFIG = 'networking_bigswitch.plugins.bigswitch.config'
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
from networking_bigswitch.tests.unit.bigswitch.mock_paths import SG_AGENT
from networking_bigswitch.tests.unit.bigswitch.mock_paths import SG_RPC


class BaseAgentTestCase(base.BaseTestCase):
@@ -38,19 +38,19 @@ class BaseAgentTestCase(base.BaseTestCase):
def setUp(self):
pl_config.register_config()
super(BaseAgentTestCase, self).setUp()
self.mod_agent = importutils.import_module(AGENTMOD)
self.mod_agent = importutils.import_module(AGENT_MOD)


class TestRestProxyAgentOVS(BaseAgentTestCase):
def setUp(self):
super(TestRestProxyAgentOVS, self).setUp()
self.plapi = mock.patch(PLUGINAPI).start()
self.ovsbridge_p = mock.patch(OVSBRIDGE)
self.plapi = mock.patch(PLUGIN_API).start()
self.ovsbridge_p = mock.patch(OVS_BRIDGE)
self.ovsbridge = self.ovsbridge_p.start()
self.context = mock.patch(CONTEXT).start()
self.rpc = mock.patch(CONSUMERCREATE).start()
self.sg_agent = mock.patch(SGAGENT).start()
self.sg_rpc = mock.patch(SGRPC).start()
self.rpc = mock.patch(CONSUMER_CREATE).start()
self.sg_agent = mock.patch(SG_AGENT).start()
self.sg_rpc = mock.patch(SG_RPC).start()

def mock_agent(self):
mock_context = mock.Mock(return_value='abc')
@@ -170,10 +170,10 @@ class TestRestProxyAgent(BaseAgentTestCase):
'CONF.AGENT.root_helper': 'helper',
'CONF.AGENT.report_interval': 60}
with\
mock.patch(AGENTMOD + '.cfg', **cfg_attrs) as mock_conf,\
mock.patch(AGENTMOD + '.config.init'),\
mock.patch(NEUTRONCFG) as mock_log_conf,\
mock.patch(PLCONFIG):
mock.patch(AGENT_MOD + '.cfg', **cfg_attrs) as mock_conf,\
mock.patch(AGENT_MOD + '.config.init'),\
mock.patch(NEUTRON_CFG) as mock_log_conf,\
mock.patch(PL_CONFIG):
self.mod_agent.main()

mock_log_conf.assert_has_calls([
@@ -182,7 +182,7 @@ class TestRestProxyAgent(BaseAgentTestCase):

def test_main(self):
agent_attrs = {'daemon_loop.side_effect': SystemExit(0)}
with mock.patch(AGENTMOD + '.RestProxyAgent',
with mock.patch(AGENT_MOD + '.RestProxyAgent',
**agent_attrs) as mock_agent:
self.assertRaises(SystemExit, self.mock_main)

@@ -199,7 +199,7 @@ class TestRestProxyAgentIVS(TestRestProxyAgentOVS):
# 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(IVSBRIDGE + '.run_vsctl').start()
self.runvsctl = mock.patch(IVS_BRIDGE + '.run_vsctl').start()

def mock_agent(self):
mock_context = mock.Mock(return_value='abc')
@@ -219,7 +219,7 @@ class TestRestProxyAgentIVS(TestRestProxyAgentOVS):
def test_port_update_not_vifport(self):
port = {'id': '1', 'security_groups': 'default'}

with mock.patch(IVSBRIDGE + '.get_vif_port_by_id',
with mock.patch(IVS_BRIDGE + '.get_vif_port_by_id',
return_value=False) as get_vif:
self.mock_port_update(port=port)

@@ -229,7 +229,7 @@ class TestRestProxyAgentIVS(TestRestProxyAgentOVS):
def test_port_update_without_secgroup(self):
port = {'id': '1'}

with mock.patch(IVSBRIDGE + '.get_vif_port_by_id',
with mock.patch(IVS_BRIDGE + '.get_vif_port_by_id',
return_value='1') as get_vif:
self.mock_port_update(port=port)

@@ -239,7 +239,7 @@ class TestRestProxyAgentIVS(TestRestProxyAgentOVS):
def test_port_update(self):
port = {'id': '1', 'security_groups': 'default'}

with mock.patch(IVSBRIDGE + '.get_vif_port_by_id',
with mock.patch(IVS_BRIDGE + '.get_vif_port_by_id',
return_value='1') as get_vif:
self.mock_port_update(port=port)

@@ -347,7 +347,7 @@ class TestRestProxyAgentNFVSwitch(TestRestProxyAgentOVS):
def test_port_update_not_vifport(self):
port = {'id': '1', 'security_groups': 'default'}

with mock.patch(NFVSWBRIDGE + '.get_vif_port_by_id',
with mock.patch(NFV_SW_BRIDGE + '.get_vif_port_by_id',
return_value=False) as get_vif:
self.mock_port_update(port=port)

@@ -357,7 +357,7 @@ class TestRestProxyAgentNFVSwitch(TestRestProxyAgentOVS):
def test_port_update_without_secgroup(self):
port = {'id': '1'}

with mock.patch(NFVSWBRIDGE + '.get_vif_port_by_id',
with mock.patch(NFV_SW_BRIDGE + '.get_vif_port_by_id',
return_value=False) as get_vif:
self.mock_port_update(port=port)

@@ -367,7 +367,7 @@ class TestRestProxyAgentNFVSwitch(TestRestProxyAgentOVS):
def test_port_update(self):
port = {'id': '1', 'security_groups': 'default'}

with mock.patch(NFVSWBRIDGE + '.get_vif_port_by_id',
with mock.patch(NFV_SW_BRIDGE + '.get_vif_port_by_id',
return_value=False) as get_vif:
self.mock_port_update(port=port)


+ 15
- 15
networking_bigswitch/tests/unit/bigswitch/test_restproxy_plugin.py View File

@@ -15,9 +15,7 @@
# limitations under the License.

import mock
from oslo_config import cfg
import webob.exc

from mock import patch
from neutron.tests.unit import _test_extension_portbindings as test_bindings
from neutron.tests.unit.api.v2 import test_base
from neutron.tests.unit.db import test_allowedaddresspairs_db as test_addr_pair
@@ -26,20 +24,20 @@ from neutron_lib.api.definitions import portbindings
from neutron_lib import constants
from neutron_lib import context
from neutron_lib.plugins import directory
from oslo_config import cfg
import webob.exc

from networking_bigswitch.plugins.bigswitch import config as pl_config
from networking_bigswitch.plugins.bigswitch import constants as bsn_constants
from networking_bigswitch.plugins.bigswitch.servermanager import\
from networking_bigswitch.plugins.bigswitch.servermanager import \
TenantIDNotFound
from networking_bigswitch.tests.unit.bigswitch import fake_server
from networking_bigswitch.tests.unit.bigswitch \
import test_base as bsn_test_base

patch = mock.patch
HTTPCON = ('networking_bigswitch.plugins.bigswitch.servermanager.httplib'
'.HTTPConnection')
IS_UNICODE_ENABLED = ('networking_bigswitch.plugins.bigswitch.servermanager.'
'ServerPool.is_unicode_enabled')
from networking_bigswitch.tests.unit.bigswitch.mock_paths import HTTPCON
from networking_bigswitch.tests.unit.bigswitch.mock_paths import \
IS_UNICODE_ENABLED


class BigSwitchProxyPluginV2TestCase(bsn_test_base.BigSwitchTestBase,
@@ -60,10 +58,11 @@ class BigSwitchProxyPluginV2TestCase(bsn_test_base.BigSwitchTestBase,
service_plugins.update(bsn_service_plugins)
else:
service_plugins = bsn_service_plugins
super(BigSwitchProxyPluginV2TestCase,
self).setUp(self._plugin_name,
service_plugins=service_plugins,
ext_mgr=ext_mgr)

test_plugin.NeutronDbPluginV2TestCase.setUp(
self, self._plugin_name,
service_plugins=service_plugins,
ext_mgr=ext_mgr)

self.port_create_status = 'BUILD'
self.startHttpPatch()
@@ -108,7 +107,7 @@ class TestBigSwitchProxyPortsV2(test_plugin.TestPortsV2,
with self.port(name='test'):
ports = directory.get_plugin().get_ports(
context.get_admin_context(), fields=['name'])
self.assertEqual(['name'], ports[0].keys())
self.assertEqual(['name'], list(ports[0].keys()))

def test_router_port_status_active(self):
# router ports screw up port auto-deletion so it has to be
@@ -217,8 +216,9 @@ class TestBigSwitchProxyPortsV2(test_plugin.TestPortsV2,
self.subnet() as s,\
patch(HTTPCON, create=True,
new=fake_server.HTTPConnectionMock404),\
patch(bsn_test_base.RESTPROXY_PKG_PATH +
patch(bsn_test_base.PLUGIN_PATH +
'.NeutronRestProxyV2._send_all_data') as mock_send_all:

with self.port(subnet=s, device_id='somedevid') as p:
# wait for the async port thread to finish
plugin = directory.get_plugin()

+ 13
- 13
networking_bigswitch/tests/unit/bigswitch/test_router_db.py View File

@@ -15,6 +15,12 @@
# Adapted from neutron.tests.unit.extensions,test_l3

import mock
from neutron.extensions import l3
from neutron.tests.unit.api.v2 import test_base
from neutron.tests.unit.extensions import test_extra_dhcp_opt as test_dhcpopts
from neutron.tests.unit.extensions import test_l3 as test_l3
from neutron_lib import context
from neutron_lib.plugins import directory
from oslo_config import cfg
from oslo_serialization import jsonutils
from oslo_utils import uuidutils
@@ -24,16 +30,9 @@ from networking_bigswitch.plugins.bigswitch.db import tenant_policy_db # noqa
from networking_bigswitch.tests.unit.bigswitch import fake_server
from networking_bigswitch.tests.unit.bigswitch \
import test_base as bsn_test_base
from neutron.extensions import l3
from neutron.tests.unit.api.v2 import test_base
from neutron.tests.unit.extensions import test_extra_dhcp_opt as test_dhcpopts
from neutron.tests.unit.extensions import test_l3 as test_l3
from neutron_lib import context
from neutron_lib.plugins import directory

from networking_bigswitch.tests.unit.bigswitch.mock_paths import HTTPCON

HTTPCON = ('networking_bigswitch.plugins.bigswitch.servermanager.httplib'
'.HTTPConnection')
_uuid = uuidutils.generate_uuid


@@ -55,8 +54,7 @@ class DHCPOptsTestCase(bsn_test_base.BigSwitchTestBase,
def setUp(self, plugin=None):
self.setup_patches()
self.setup_config_files()
super(test_dhcpopts.ExtraDhcpOptDBTestCase,
self).setUp(plugin=self._plugin_name)
test_dhcpopts.TestExtraDhcpOpt.setUp(self, plugin=self._plugin_name)
self.setup_db()
self.startHttpPatch()

@@ -72,9 +70,11 @@ class RouterDBTestBase(bsn_test_base.BigSwitchTestBase,
self.setup_config_files()
ext_mgr = RouterRulesTestExtensionManager()
service_plugins = {'L3_ROUTER_NAT': self._l3_plugin_name}
super(RouterDBTestBase, self).setUp(plugin=self._plugin_name,
ext_mgr=ext_mgr,
service_plugins=service_plugins)
test_l3.L3BaseForIntTests.setUp(self,
plugin=self._plugin_name,
ext_mgr=ext_mgr,
service_plugins=service_plugins)

self.setup_db()
cfg.CONF.set_default('allow_overlapping_ips', False)
self.plugin_obj = directory.get_plugin('L3_ROUTER_NAT')

+ 2
- 2
networking_bigswitch/tests/unit/bigswitch/test_security_groups.py View File

@@ -23,14 +23,14 @@ from networking_bigswitch.tests.unit.bigswitch import test_base
class RestProxySecurityGroupsTestCase(test_sg.SecurityGroupDBTestCase,
test_base.BigSwitchTestBase):
plugin_str = ('%s.NeutronRestProxyV2' %
test_base.RESTPROXY_PKG_PATH)
test_base.PLUGIN_PATH)

def setUp(self, plugin=None):
test_sg_rpc.set_firewall_driver(test_sg_rpc.FIREWALL_HYBRID_DRIVER)
self.setup_config_files()
self.setup_patches()
self._attribute_map_bk_ = {}
super(RestProxySecurityGroupsTestCase, self).setUp(self.plugin_str)
test_sg.SecurityGroupDBTestCase.setUp(self, self.plugin_str)
self.setup_db()
plugin = directory.get_plugin()
self.notifier = plugin.notifier

+ 69
- 127
networking_bigswitch/tests/unit/bigswitch/test_servermanager.py View File

@@ -11,40 +11,55 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import httplib
import socket
import ssl
import time

import mock
from neutron_lib.plugins import directory
from oslo_config import cfg
from oslo_db import exception as db_exc
from oslo_utils import importutils
from six.moves import http_client

from networking_bigswitch.plugins.bigswitch.db import consistency_db
from networking_bigswitch.plugins.bigswitch import servermanager
from networking_bigswitch.tests.unit.bigswitch \
import test_restproxy_plugin as test_rp
from neutron_lib.plugins import directory

SERVERMANAGER = 'networking_bigswitch.plugins.bigswitch.servermanager'
CONSISTENCYDB = 'networking_bigswitch.plugins.bigswitch.db.consistency_db'
HTTPCON = SERVERMANAGER + '.httplib.HTTPConnection'
HTTPSCON = SERVERMANAGER + '.HTTPSConnectionWithValidation'
SERVER_GET_CAPABILITIES = SERVERMANAGER + '.ServerPool.get_capabilities'
from networking_bigswitch.tests.unit.bigswitch.mock_paths import CERT_COMBINER
from networking_bigswitch.tests.unit.bigswitch.mock_paths import CONSISTENCY_DB
from networking_bigswitch.tests.unit.bigswitch.mock_paths import \
GET_SERVER_CERTIFICATE
from networking_bigswitch.tests.unit.bigswitch.mock_paths import HTTPCON
from networking_bigswitch.tests.unit.bigswitch.mock_paths import HTTPSCON
from networking_bigswitch.tests.unit.bigswitch.mock_paths import \
POOL_GET_CAPABILITIES
from networking_bigswitch.tests.unit.bigswitch.mock_paths import \
POOL_REST_ACTION
from networking_bigswitch.tests.unit.bigswitch.mock_paths import \
POOL_REST_CALL
from networking_bigswitch.tests.unit.bigswitch.mock_paths import \
POOL_TOPO_SYNC
from networking_bigswitch.tests.unit.bigswitch.mock_paths import \
POOL_UPDATE_TENANT_CACHE
from networking_bigswitch.tests.unit.bigswitch.mock_paths import SERVER_MANAGER
from networking_bigswitch.tests.unit.bigswitch.mock_paths import \
SERVER_REST_CALL


class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):

def setUp(self):
self.socket_mock = mock.patch(
SERVERMANAGER + '.socket.create_connection').start()
self.wrap_mock = mock.patch(SERVERMANAGER + '.ssl.wrap_socket').start()
SERVER_MANAGER + '.socket.create_connection').start()
self.wrap_mock = mock.patch(SERVER_MANAGER +
'.ssl.wrap_socket').start()
super(ServerManagerTests, self).setUp()
# http patch must not be running or it will mangle the servermanager
# import where the https connection classes are defined
self.httpPatch.stop()
self.sm = importutils.import_module(SERVERMANAGER)
self.sm = importutils.import_module(SERVER_MANAGER)

def test_no_servers(self):
cfg.CONF.set_override('servers', [], 'RESTPROXY')
@@ -64,18 +79,17 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):

def test_sticky_cert_fetch_fail(self):
pl = directory.get_plugin()
pl.servers.ssl = True
with mock.patch(
'ssl.get_server_certificate',
side_effect=Exception('There is no more entropy in the universe')
) as sslgetmock:
pl.servers.is_ssl_enabled = True
with mock.patch(GET_SERVER_CERTIFICATE,
side_effect=Exception('There is no more entropy in the'
'universe')) as sslgetmock:
self.assertRaises(
cfg.Error,
pl.servers._get_combined_cert_for_server,
*('example.org', 443)
)
sslgetmock.assert_has_calls([mock.call(
('example.org', 443), ssl_version=ssl.PROTOCOL_SSLv23)])
sslgetmock.assert_has_calls([mock.call(('example.org', 443))])

def test_consistency_watchdog_stops_with_0_polling_interval(self):
pl = directory.get_plugin()
@@ -93,12 +107,12 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):

with mock.patch('eventlet.sleep') as smock,\
mock.patch(
SERVERMANAGER + '.ServerPool.rest_call',
POOL_REST_CALL,
side_effect=servermanager.RemoteRestError(
reason='Failure to trigger except clause.'))\
as rmock,\
mock.patch(
SERVERMANAGER + '.LOG.exception',
SERVER_MANAGER + '.LOG.exception',
side_effect=KeyError('Failure to break loop'))\
as lmock:
# should return immediately without consistency capability
@@ -113,7 +127,7 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):

def test_file_put_contents(self):
pl = directory.get_plugin()
with mock.patch(SERVERMANAGER + '.open', create=True) as omock:
with mock.patch(SERVER_MANAGER + '.open', create=True) as omock:
pl.servers._file_put_contents('somepath', 'contents')
omock.assert_has_calls([mock.call('somepath', 'w')])
omock.return_value.__enter__.return_value.assert_has_calls([
@@ -122,7 +136,7 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):

def test_combine_certs_to_file(self):
pl = directory.get_plugin()
with mock.patch(SERVERMANAGER + '.open', create=True) as omock:
with mock.patch(SERVER_MANAGER + '.open', create=True) as omock:
omock.return_value.__enter__().read.return_value = 'certdata'
pl.servers._combine_certs_to_file(['cert1.pem', 'cert2.pem'],
'combined.pem')
@@ -239,7 +253,7 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):
self.assertEqual(resp, (0, None, None, None))
# verify same behavior on ssl class
sp.servers[0].currentcon = False
sp.servers[0].ssl = True
sp.servers[0].is_ssl_enabled = True
with mock.patch(HTTPSCON, return_value=None):
resp = sp.servers[0].rest_call('GET', '/')
self.assertEqual(resp, (0, None, None, None))
@@ -256,7 +270,7 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):
sp.servers[0].rest_call('GET', '/first')
# raise an error on re-use to verify reconnect
# return okay the second time so the reconnect works
rv.request.side_effect = [httplib.ImproperConnectionState(),
rv.request.side_effect = [http_client.ImproperConnectionState(),
mock.MagicMock()]
sp.servers[0].rest_call('GET', '/second')
uris = [c[1][1] for c in rv.request.mock_calls]
@@ -282,8 +296,8 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):
sp.servers[0].rest_call('GET', '/first')
# after retrying once, the rest call should raise the
# exception up
rv.request.side_effect = httplib.ImproperConnectionState()
self.assertRaises(httplib.ImproperConnectionState,
rv.request.side_effect = http_client.ImproperConnectionState()
self.assertRaises(http_client.ImproperConnectionState,
sp.servers[0].rest_call,
*('GET', '/second'))
# 1 for the first call, 2 for the second with retry
@@ -298,7 +312,7 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):

def test_cert_get_fail(self):
pl = directory.get_plugin()
pl.servers.ssl = True
pl.servers.is_ssl_enabled = True
with mock.patch('os.path.exists', return_value=False):
self.assertRaises(cfg.Error,
pl.servers._get_combined_cert_for_server,
@@ -306,16 +320,14 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):

def test_cert_make_dirs(self):
pl = directory.get_plugin()
pl.servers.ssl = True
pl.servers.is_ssl_enabled = True
cfg.CONF.set_override('ssl_sticky', False, 'RESTPROXY')
# pretend base dir exists, 3 children don't, and host cert does
with mock.patch('os.path.exists',
side_effect=[True, False, False,
False, True]) as exmock,\
mock.patch('os.makedirs') as makemock,\
mock.patch(
SERVERMANAGER + '.ServerPool._combine_certs_to_file')\
as combmock:
mock.patch(CERT_COMBINER) as combmock:
# will raise error because no certs found
self.assertIn(
'example.org',
@@ -330,7 +342,7 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):

def test_no_cert_error(self):
pl = directory.get_plugin()
pl.servers.ssl = True
pl.servers.is_ssl_enabled = True
cfg.CONF.set_override('ssl_sticky', False, 'RESTPROXY')
# pretend base dir exists and 3 children do, but host cert doesn't
with mock.patch(
@@ -358,10 +370,10 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):

def test_retry_on_unavailable(self):
pl = directory.get_plugin()
with mock.patch(SERVERMANAGER + '.ServerProxy.rest_call',
return_value=(httplib.SERVICE_UNAVAILABLE,
with mock.patch(SERVER_REST_CALL,
return_value=(http_client.SERVICE_UNAVAILABLE,
0, 0, 0)) as srestmock,\
mock.patch(SERVERMANAGER + '.eventlet.sleep') as tmock:
mock.patch(SERVER_MANAGER + '.eventlet.sleep') as tmock:
# making a call should trigger retries with sleeps in between
pl.servers.rest_call('GET', '/', '', None, [])
rest_call = [mock.call('GET', '/', '', None, False,
@@ -377,10 +389,10 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):

def test_delete_failure_forces_topo_sync(self):
pl = directory.get_plugin()
with mock.patch(SERVERMANAGER + '.ServerProxy.rest_call',
return_value=(httplib.INTERNAL_SERVER_ERROR,
with mock.patch(SERVER_REST_CALL,
return_value=(http_client.INTERNAL_SERVER_ERROR,
0, 0, 0)), \
mock.patch(SERVERMANAGER + '.ServerPool.force_topo_sync',
mock.patch(POOL_TOPO_SYNC,
return_value=(False,
servermanager.TOPO_RESPONSE_OK)) \
as topo_mock:
@@ -396,10 +408,10 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):

def test_post_failure_forces_topo_sync(self):
pl = directory.get_plugin()
with mock.patch(SERVERMANAGER + '.ServerProxy.rest_call',
return_value=(httplib.INTERNAL_SERVER_ERROR,
with mock.patch(SERVER_REST_CALL,
return_value=(http_client.INTERNAL_SERVER_ERROR,
0, 0, 0)), \
mock.patch(SERVERMANAGER + '.ServerPool.force_topo_sync',
mock.patch(POOL_TOPO_SYNC,
return_value=(False,
servermanager.TOPO_RESPONSE_OK)) \
as topo_mock:
@@ -414,10 +426,10 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):

def test_topo_sync_failure_does_not_force_topo_sync(self):
pl = directory.get_plugin()
with mock.patch(SERVERMANAGER + '.ServerProxy.rest_call',
return_value=(httplib.INTERNAL_SERVER_ERROR,
with mock.patch(SERVER_REST_CALL,
return_value=(http_client.INTERNAL_SERVER_ERROR,
0, 0, 0)), \
mock.patch(SERVERMANAGER + '.ServerPool.force_topo_sync',
mock.patch(POOL_TOPO_SYNC,
return_value=(False,
servermanager.TOPO_RESPONSE_OK)) \
as topo_mock:
@@ -436,8 +448,8 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):
pl.servers.get_topo_function = None
with \
mock.patch(
SERVERMANAGER + '.ServerProxy.rest_call',
return_value=(httplib.NOT_FOUND, 0, 0, 0)):
SERVER_REST_CALL,
return_value=(http_client.NOT_FOUND, 0, 0, 0)):
# making a call should trigger a conflict sync that will
# error without the topology function set
self.assertRaises(
@@ -449,10 +461,10 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):
def test_no_sync_without_keystone(self):
pl = directory.get_plugin()
with\
mock.patch(SERVERMANAGER + '.ServerPool._update_tenant_cache',
return_value=(False)),\
mock.patch(SERVERMANAGER + '.ServerProxy.rest_call',
return_value=(httplib.CONFLICT, 0, 0, 0)) as srestmock:
mock.patch(POOL_UPDATE_TENANT_CACHE, return_value=(False)),\
mock.patch(SERVER_REST_CALL,
return_value=(http_client.CONFLICT, 0, 0,
0)) as srestmock:
# making a call should trigger a conflict sync
pl.servers.rest_call('GET', '/', '', None, [])
srestmock.assert_called_once_with(
@@ -460,9 +472,8 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):

def test_no_send_all_data_without_keystone(self):
pl = directory.get_plugin()
with mock.patch(SERVERMANAGER + '.ServerPool._update_tenant_cache',
return_value=(False)), \
mock.patch(SERVERMANAGER + '.ServerPool.force_topo_sync',
with mock.patch(POOL_UPDATE_TENANT_CACHE, return_value=(False)), \
mock.patch(POOL_TOPO_SYNC,
return_value=(False, servermanager.TOPO_RESPONSE_OK)) \
as tmock:
# making a call should trigger a conflict sync
@@ -471,7 +482,7 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):

def test_floating_calls(self):
pl = directory.get_plugin()
with mock.patch(SERVERMANAGER + '.ServerPool.rest_action') as ramock:
with mock.patch(POOL_REST_ACTION) as ramock:
body1 = {'id': 'somefloat'}
body2 = {'name': 'myfl'}
pl.servers.rest_create_floatingip('tenant', body1)
@@ -488,58 +499,6 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):
errstr=u'Unable to delete floating IP: %s')
])

def test_HTTPSConnectionWithValidation_without_cert(self):
con = self.sm.HTTPSConnectionWithValidation(
'www.example.org', 443, timeout=90)
con.source_address = '127.0.0.1'
con.request("GET", "/")
self.socket_mock.assert_has_calls([mock.call(
('www.example.org', 443), 90, '127.0.0.1'
)])
self.wrap_mock.assert_has_calls([mock.call(
self.socket_mock(), None, None, cert_reqs=ssl.CERT_NONE,
ssl_version=ssl.PROTOCOL_SSLv23
)])
self.assertEqual(con.sock, self.wrap_mock())

def test_HTTPSConnectionWithValidation_with_cert(self):
con = self.sm.HTTPSConnectionWithValidation(
'www.example.org', 443, timeout=90)
con.combined_cert = 'SOMECERTS.pem'
con.source_address = '127.0.0.1'
con.request("GET", "/")
self.socket_mock.assert_has_calls([mock.call(
('www.example.org', 443), 90, '127.0.0.1'
)])
self.wrap_mock.assert_has_calls([mock.call(
self.socket_mock(), None, None, ca_certs='SOMECERTS.pem',
cert_reqs=ssl.CERT_REQUIRED,
ssl_version=ssl.PROTOCOL_SSLv23
)])
self.assertEqual(con.sock, self.wrap_mock())

def test_HTTPSConnectionWithValidation_tunnel(self):
tunnel_mock = mock.patch.object(
self.sm.HTTPSConnectionWithValidation,
'_tunnel').start()
con = self.sm.HTTPSConnectionWithValidation(
'www.example.org', 443, timeout=90)
con.source_address = '127.0.0.1'
con.set_tunnel('myproxy.local', 3128)
con.request("GET", "/")
self.socket_mock.assert_has_calls([mock.call(
('www.example.org', 443), 90, '127.0.0.1'
)])
self.wrap_mock.assert_has_calls([mock.call(
self.socket_mock(), None, None, cert_reqs=ssl.CERT_NONE,
ssl_version=ssl.PROTOCOL_SSLv23
)])
# _tunnel() doesn't take any args
tunnel_mock.assert_has_calls([mock.call()])
self.assertEqual(con._tunnel_host, 'myproxy.local')
self.assertEqual(con._tunnel_port, 3128)
self.assertEqual(con.sock, self.wrap_mock())

def test_is_unicode_enabled(self):
"""Verify that unicode is enabled only when both conditions are True:

@@ -557,11 +516,11 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):
return ['dummy']

patch_supported = mock.patch(
SERVER_GET_CAPABILITIES,
POOL_GET_CAPABILITIES,
side_effect=capability_unicode_supported)

patch_unsupported = mock.patch(
SERVER_GET_CAPABILITIES,
POOL_GET_CAPABILITIES,
side_effect=capability_unicode_unsupported)

# Create a server pool with default naming_scheme_unicode
@@ -594,23 +553,6 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):
patch_unsupported.stop()


class TestSockets(test_rp.BigSwitchProxyPluginV2TestCase):

def setUp(self):
super(TestSockets, self).setUp()
# http patch must not be running or it will mangle the servermanager
# import where the https connection classes are defined
self.httpPatch.stop()
self.sm = importutils.import_module(SERVERMANAGER)

def test_socket_create_attempt(self):
# exercise the socket creation to make sure it works on both python
# versions
con = self.sm.HTTPSConnectionWithValidation('127.0.0.1', 0, timeout=1)
# if httpcon was created, a connect attempt should raise a socket error
self.assertRaises(socket.error, con.connect)


class HashLockingTests(test_rp.BigSwitchProxyPluginV2TestCase):

def _get_hash_from_handler_db(self, handler):
@@ -669,7 +611,7 @@ class HashLockingTests(test_rp.BigSwitchProxyPluginV2TestCase):
hh2_ts_hh1_ts_plus_1780 = float(handler1.lock_ts) + 1780
handler2 = consistency_db.HashHandler(
hash_id='1', timestamp_ms=hh2_ts_hh1_ts_plus_1780)
with mock.patch(CONSISTENCYDB + '.eventlet.sleep',
with mock.patch(CONSISTENCY_DB + '.eventlet.sleep',
side_effect=[Exception]) as emock:
try:
handler2.lock(check_ts=False)
@@ -755,7 +697,7 @@ class HashLockingTests(test_rp.BigSwitchProxyPluginV2TestCase):
handler2 = consistency_db.HashHandler()

with mock.patch.object(handler2._FACADE, 'get_engine') as ge, \
mock.patch(CONSISTENCYDB + '.eventlet.sleep',
mock.patch(CONSISTENCY_DB + '.eventlet.sleep',
side_effect=[None]) as emock:
conn = ge.return_value.begin.return_value.__enter__.return_value
firstresult = mock.Mock()

+ 38
- 157
networking_bigswitch/tests/unit/bigswitch/test_ssl.py View File

@@ -12,38 +12,33 @@
# License for the specific language governing permissions and limitations
# under the License.
import os
import ssl

import mock
from oslo_config import cfg
from oslo_log import log as logging
import webob.exc

from neutron.tests.unit.api.v2 import test_base
from neutron.tests.unit.db import test_db_base_plugin_v2 as test_plugin
from oslo_config import cfg
from oslo_log import log as logging

from networking_bigswitch.tests.unit.bigswitch import fake_server
from networking_bigswitch.tests.unit.bigswitch \
import test_base as bsn_test_base

LOG = logging.getLogger(__name__)
from networking_bigswitch.tests.unit.bigswitch.mock_paths import CERT_COMBINER
from networking_bigswitch.tests.unit.bigswitch.mock_paths import FILE_PUT
from networking_bigswitch.tests.unit.bigswitch.mock_paths import GET_CA_CERTS
from networking_bigswitch.tests.unit.bigswitch.mock_paths import \
GET_SERVER_CERTIFICATE
from networking_bigswitch.tests.unit.bigswitch.mock_paths import HTTPSCON
from networking_bigswitch.tests.unit.bigswitch.mock_paths import \
SSL_CREATE_DEFAULT_CONTEXT

SERVERMANAGER = 'networking_bigswitch.plugins.bigswitch.servermanager'
HTTPS = SERVERMANAGER + '.HTTPSConnectionWithValidation'
CERTCOMBINER = SERVERMANAGER + '.ServerPool._combine_certs_to_file'
FILEPUT = SERVERMANAGER + '.ServerPool._file_put_contents'
GETCACERTS = SERVERMANAGER + '.ServerPool._get_ca_cert_paths'
GETHOSTCERT = SERVERMANAGER + '.ServerPool._get_host_cert_path'
SSLGETCERT = SERVERMANAGER + '.ssl.get_server_certificate'
FAKECERTGET = ('networking_bigswitch.tests.unit.bigswitch.fake_server'
'.get_cert_contents')
LOG = logging.getLogger(__name__)


class test_ssl_certificate_base(test_plugin.NeutronDbPluginV2TestCase,
bsn_test_base.BigSwitchTestBase):

plugin_str = ('%s.NeutronRestProxyV2' %
bsn_test_base.RESTPROXY_PKG_PATH)
bsn_test_base.PLUGIN_PATH)
servername = None
cert_base = None

@@ -70,20 +65,17 @@ class test_ssl_certificate_base(test_plugin.NeutronDbPluginV2TestCase,
self.setup_patches()

# Mock method SSL lib uses to grab cert from server
self.sslgetcert_m = mock.patch(SSLGETCERT, create=True).start()
self.sslgetcert_m = mock.patch(GET_SERVER_CERTIFICATE,
create=True).start()
self.sslgetcert_m.return_value = self.host_cert_val

# Mock methods that write and read certs from the file-system
self.fileput_m = mock.patch(FILEPUT, create=True).start()
self.certcomb_m = mock.patch(CERTCOMBINER, create=True).start()
self.getcacerts_m = mock.patch(GETCACERTS, create=True).start()

# this is used to configure what certificate contents the fake HTTPS
# lib should expect to receive
self.fake_certget_m = mock.patch(FAKECERTGET, create=True).start()
self.fileput_m = mock.patch(FILE_PUT, create=True).start()
self.certcomb_m = mock.patch(CERT_COMBINER, create=True).start()
self.getcacerts_m = mock.patch(GET_CA_CERTS, create=True).start()

def setUp(self):
super(test_ssl_certificate_base, self).setUp(self.plugin_str)
test_plugin.NeutronDbPluginV2TestCase.setUp(self, self.plugin_str)
self.setup_db()


@@ -94,155 +86,44 @@ class TestSslSticky(test_ssl_certificate_base):
cfg.CONF.set_override('server_ssl', True, 'RESTPROXY')
cfg.CONF.set_override('ssl_sticky', True, 'RESTPROXY')
self._setUp()
# Set fake HTTPS connection's expectation
self.fake_certget_m.return_value = self.host_cert_val
# # Set fake HTTPS connection's expectation
# self.fake_certget_m.return_value = self.host_cert_val
# No CA certs for this test
self.getcacerts_m.return_value = []

self.ssl_create_default_context_m = mock.patch(
SSL_CREATE_DEFAULT_CONTEXT,
create=True).start()
super(TestSslSticky, self).setUp()

def test_sticky_cert(self):
"""Test certificate is stored, and https connection is used

:return:
"""
# SSL connection should be successful and cert should be cached
with mock.patch(HTTPS, new=fake_server.HTTPSHostValidation),\
self.network():
with mock.patch(HTTPSCON) as https_mock, self.network():
# CA certs should have been checked for
self.getcacerts_m.assert_has_calls([mock.call(self.ca_certs_path)])
# cert should have been fetched via SSL lib
self.sslgetcert_m.assert_has_calls(
[mock.call((self.servername, 443),
ssl_version=ssl.PROTOCOL_SSLv23)]
[mock.call((self.servername, 443))]
)

# cert should have been recorded
self.fileput_m.assert_has_calls([mock.call(self.host_cert_path,
self.host_cert_val)])
# no ca certs, so host cert only for this combined cert
self.certcomb_m.assert_has_calls([mock.call([self.host_cert_path],
self.comb_cert_path)])


class TestSslHostCert(test_ssl_certificate_base):

def setUp(self):
self.setup_config_files()
cfg.CONF.set_override('server_ssl', True, 'RESTPROXY')
cfg.CONF.set_override('ssl_sticky', False, 'RESTPROXY')
self.httpsPatch = mock.patch(HTTPS, create=True,
new=fake_server.HTTPSHostValidation)
self.httpsPatch.start()
self._setUp()
# Set fake HTTPS connection's expectation
self.fake_certget_m.return_value = self.host_cert_val
# No CA certs for this test
self.getcacerts_m.return_value = []
# Pretend host cert exists
self.hcertpath_p = mock.patch(GETHOSTCERT,
return_value=(self.host_cert_path, True),
create=True).start()
super(TestSslHostCert, self).setUp()

def test_host_cert(self):
# SSL connection should be successful because of pre-configured cert
with self.network():
self.hcertpath_p.assert_has_calls([
mock.call(os.path.join(self.cert_base, 'host_certs'),
self.servername)
])
# sticky is disabled, no fetching allowed
self.assertFalse(self.sslgetcert_m.call_count)
# no ca certs, so host cert is only for this combined cert
# no ca certs, so host cert only for this combined cert
self.certcomb_m.assert_has_calls([mock.call([self.host_cert_path],
self.comb_cert_path)])

# confirm that ssl_context is created
self.ssl_create_default_context_m.assert_called_once()

class TestSslCaCert(test_ssl_certificate_base):
# Test HTTPS Connection is used for REST Calls
https_mock.assert_called_once()

def setUp(self):
self.setup_config_files()
cfg.CONF.set_override('server_ssl', True, 'RESTPROXY')
cfg.CONF.set_override('ssl_sticky', False, 'RESTPROXY')
self.httpsPatch = mock.patch(HTTPS, create=True,
new=fake_server.HTTPSCAValidation)
self.httpsPatch.start()
self._setUp()

# pretend to have a few ca certs
self.getcacerts_m.return_value = ['ca1.pem', 'ca2.pem']

# Set fake HTTPS connection's expectation
self.fake_certget_m.return_value = 'DUMMYCERTIFICATEAUTHORITY'

super(TestSslCaCert, self).setUp()

def test_ca_cert(self):
# SSL connection should be successful because CA cert was present
# If not, attempting to create a network would raise an exception
with self.network():
# sticky is disabled, no fetching allowed
self.assertFalse(self.sslgetcert_m.call_count)
# 2 CAs and no host cert so combined should only contain both CAs
self.certcomb_m.assert_has_calls([mock.call(['ca1.pem', 'ca2.pem'],
self.comb_cert_path)])


class TestSslWrongHostCert(test_ssl_certificate_base):

def setUp(self):
self.setup_config_files()
cfg.CONF.set_override('server_ssl', True, 'RESTPROXY')
cfg.CONF.set_override('ssl_sticky', True, 'RESTPROXY')
self._setUp()

# Set fake HTTPS connection's expectation to something wrong
self.fake_certget_m.return_value = 'OTHERCERT'

# No CA certs for this test
self.getcacerts_m.return_value = []

# Pretend host cert exists
self.hcertpath_p = mock.patch(GETHOSTCERT,
return_value=(self.host_cert_path, True),
create=True).start()
super(TestSslWrongHostCert, self).setUp()

def test_error_no_cert(self):
# since there will already be a host cert, sticky should not take
# effect and there will be an error because the host cert's contents
# will be incorrect
tid = test_base._uuid()
data = {}
data['network'] = {'tenant_id': tid, 'name': 'name',
'admin_state_up': True}
with mock.patch(HTTPS, new=fake_server.HTTPSHostValidation):
req = self.new_create_request('networks', data, 'json')
res = req.get_response(self.api)
self.assertEqual(res.status_int,
webob.exc.HTTPInternalServerError.code)
self.hcertpath_p.assert_has_calls([
mock.call(os.path.join(self.cert_base, 'host_certs'),
self.servername)
])
# sticky is enabled, but a host cert already exists so it shant fetch
self.assertFalse(self.sslgetcert_m.call_count)
# no ca certs, so host cert only for this combined cert
self.certcomb_m.assert_has_calls([mock.call([self.host_cert_path],
self.comb_cert_path)])


class TestSslNoValidation(test_ssl_certificate_base):

def setUp(self):
self.setup_config_files()
cfg.CONF.set_override('server_ssl', True, 'RESTPROXY')
cfg.CONF.set_override('ssl_sticky', False, 'RESTPROXY')
cfg.CONF.set_override('no_ssl_validation', True, 'RESTPROXY')
self._setUp()
super(TestSslNoValidation, self).setUp()

def test_validation_disabled(self):
# SSL connection should be successful without any certificates
# If not, attempting to create a network will raise an exception
with mock.patch(HTTPS, new=fake_server.HTTPSNoValidation),\
self.network():
# no sticky grabbing and no cert combining with no enforcement
self.assertFalse(self.sslgetcert_m.call_count)
self.assertFalse(self.certcomb_m.call_count)
# confirm that ssl_context is passed
self.assertTrue(https_mock.
call_args_list[0][1].get('context'))

+ 7
- 8
networking_bigswitch/tests/unit/ml2/drivers/test_bigswitch_mech.py View File

@@ -17,8 +17,6 @@
import functools

import mock
from oslo_serialization import jsonutils

from neutron.conf.plugins.ml2 import config as ml2_config
from neutron.db import l3_db
from neutron.plugins.ml2.drivers import type_vlan as vlan_config
@@ -32,6 +30,8 @@ from neutron_lib import context as neutron_context
from neutron_lib import exceptions as n_exc
from neutron_lib.plugins import constants as plugin_constants
from neutron_lib.plugins import directory
from oslo_serialization import jsonutils
from oslo_utils import uuidutils

from networking_bigswitch.plugins.bigswitch import config as pl_config
from networking_bigswitch.plugins.bigswitch import servermanager
@@ -40,18 +40,17 @@ from networking_bigswitch.plugins.ml2.drivers.mech_bigswitch \
# from networking_bigswitch.tests.unit.bigswitch.fake_server \
# import HTTPResponseMock
import networking_bigswitch.tests.unit.bigswitch.test_restproxy_plugin as trp
from oslo_utils import uuidutils

from networking_bigswitch.tests.unit.bigswitch.mock_paths import DRIVER
from networking_bigswitch.tests.unit.bigswitch.mock_paths import DRIVER_MOD
# from networking_bigswitch.tests.unit.bigswitch.mock_paths import HTTPCON
from networking_bigswitch.tests.unit.bigswitch.mock_paths import SERVER_POOL

_uuid = uuidutils.generate_uuid

PHYS_NET = 'physnet1'
VLAN_START = 1000
VLAN_END = 1100
SERVER_MANAGER = 'networking_bigswitch.plugins.bigswitch.servermanager'
SERVER_POOL = SERVER_MANAGER + '.ServerPool'
DRIVER_MOD = 'networking_bigswitch.plugins.ml2.drivers.mech_bigswitch.driver'
DRIVER = DRIVER_MOD + '.BigSwitchMechanismDriver'
HTTPCON = SERVER_MANAGER + '.httplib.HTTPConnection'


class TestBigSwitchMechDriverBase(trp.BigSwitchProxyPluginV2TestCase):

+ 22
- 1
requirements.txt View File

@@ -3,7 +3,28 @@
# setup the requirements. If any packages are added that are
# specific to bsnstack lib, put them here.

six>=1.10.0 # MIT
alembic>=1.0.0 # MIT
distro>=1.3.0 # Apache-2.0
eventlet>=0.24.1 # MIT
keystoneauth1>=3.11.1 # Apache-2.0
mock>=2.0.0 # BSD
neutron_lib>=1.20.0 # Apache-2.0
os_net_config>=10.0.0 # Apache-2.0
oslo.i18n>=3.22.1 # Apache-2.0
oslo.serialization>=2.28.1 # Apache-2.0
oslo.utils>=3.37.1 # Apache-2.0
oslo_config>=6.7.0 # Apache-2.0
oslo_db>=4.42.0 # Apache-2.0
oslo_log>=3.40.1 # Apache-2.0
oslo_messaging>=9.2.0 # Apache-2.0
oslo_service>=1.33.0 # Apache-2.0
oslotest>=3.7.0 # Apache-2.0
python-keystoneclient>=3.18.0 # Apache-2.0
requests>=2.18.4 # Apache-2.0
setuptools>=18.5 # MIT
six>=1.11.0 # MIT
SQLAlchemy>=1.2.12 # MIT
WebOb>=1.8.4 # MIT

# These repos are installed from git in OpenStack CI if the job
# configures them as required-projects:

+ 3
- 0
setup.cfg View File

@@ -15,6 +15,9 @@ classifier =
Programming Language :: Python
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.5
Programming Language :: Python :: 3.6

[files]
data_files =

+ 13
- 1
tox.ini View File

@@ -1,5 +1,5 @@
[tox]
envlist = py27,pep8
envlist = py36,py35,py27,pep8
minversion = 2.0
skipsdist = True

@@ -100,6 +100,18 @@ commands =
{[testenv:dev]commands}
{[testenv]commands}

[testenv:py35-dev]
basepython = python3.5
commands =
{[testenv:dev]commands}
{[testenv]commands}

[testenv:py36-dev]
basepython = python3.6
commands =
{[testenv:dev]commands}
{[testenv]commands}

[testenv:pep8-dev]
basepython = python3
commands =

Loading…
Cancel
Save