Merge "BSN: Add context to backend request for debugging"
This commit is contained in:
commit
4c54d6a57e
|
@ -448,7 +448,9 @@ class NeutronRestProxyV2Base(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
def put_context_in_serverpool(f):
|
def put_context_in_serverpool(f):
|
||||||
@functools.wraps(f)
|
@functools.wraps(f)
|
||||||
def wrapper(self, context, *args, **kwargs):
|
def wrapper(self, context, *args, **kwargs):
|
||||||
self.servers.set_context(context)
|
# core plugin: context is top level object
|
||||||
|
# ml2: keeps context in _plugin_context
|
||||||
|
self.servers.set_context(getattr(context, '_plugin_context', context))
|
||||||
return f(self, context, *args, **kwargs)
|
return f(self, context, *args, **kwargs)
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,7 @@ FAILURE_CODES = [0, 301, 302, 303, 400, 401, 403, 404, 500, 501, 502, 503,
|
||||||
BASE_URI = '/networkService/v1.1'
|
BASE_URI = '/networkService/v1.1'
|
||||||
ORCHESTRATION_SERVICE_ID = 'Neutron v2.0'
|
ORCHESTRATION_SERVICE_ID = 'Neutron v2.0'
|
||||||
HASH_MATCH_HEADER = 'X-BSN-BVS-HASH-MATCH'
|
HASH_MATCH_HEADER = 'X-BSN-BVS-HASH-MATCH'
|
||||||
|
REQ_CONTEXT_HEADER = 'X-REQ-CONTEXT'
|
||||||
# error messages
|
# error messages
|
||||||
NXNETWORK = 'NXVNS'
|
NXNETWORK = 'NXVNS'
|
||||||
HTTP_SERVICE_UNAVAILABLE_RETRY_COUNT = 3
|
HTTP_SERVICE_UNAVAILABLE_RETRY_COUNT = 3
|
||||||
|
@ -125,12 +126,11 @@ class ServerProxy(object):
|
||||||
'cap': self.capabilities})
|
'cap': self.capabilities})
|
||||||
return self.capabilities
|
return self.capabilities
|
||||||
|
|
||||||
def rest_call(self, action, resource, data='', headers={}, timeout=False,
|
def rest_call(self, action, resource, data='', headers=None,
|
||||||
reconnect=False, hash_handler=None):
|
timeout=False, reconnect=False, hash_handler=None):
|
||||||
uri = self.base_uri + resource
|
uri = self.base_uri + resource
|
||||||
body = jsonutils.dumps(data)
|
body = jsonutils.dumps(data)
|
||||||
if not headers:
|
headers = headers or {}
|
||||||
headers = {}
|
|
||||||
headers['Content-type'] = 'application/json'
|
headers['Content-type'] = 'application/json'
|
||||||
headers['Accept'] = 'application/json'
|
headers['Accept'] = 'application/json'
|
||||||
headers['NeutronProxy-Agent'] = self.name
|
headers['NeutronProxy-Agent'] = self.name
|
||||||
|
@ -425,7 +425,15 @@ class ServerPool(object):
|
||||||
@utils.synchronized('bsn-rest-call')
|
@utils.synchronized('bsn-rest-call')
|
||||||
def rest_call(self, action, resource, data, headers, ignore_codes,
|
def rest_call(self, action, resource, data, headers, ignore_codes,
|
||||||
timeout=False):
|
timeout=False):
|
||||||
hash_handler = cdb.HashHandler(context=self.get_context_ref())
|
context = self.get_context_ref()
|
||||||
|
if context:
|
||||||
|
# include the requesting context information if available
|
||||||
|
cdict = context.to_dict()
|
||||||
|
# remove the auth token so it's not present in debug logs on the
|
||||||
|
# backend controller
|
||||||
|
cdict.pop('auth_token', None)
|
||||||
|
headers[REQ_CONTEXT_HEADER] = jsonutils.dumps(cdict)
|
||||||
|
hash_handler = cdb.HashHandler(context=context)
|
||||||
good_first = sorted(self.servers, key=lambda x: x.failed)
|
good_first = sorted(self.servers, key=lambda x: x.failed)
|
||||||
first_response = None
|
first_response = None
|
||||||
for active_server in good_first:
|
for active_server in good_first:
|
||||||
|
@ -479,13 +487,15 @@ class ServerPool(object):
|
||||||
return first_response
|
return first_response
|
||||||
|
|
||||||
def rest_action(self, action, resource, data='', errstr='%s',
|
def rest_action(self, action, resource, data='', errstr='%s',
|
||||||
ignore_codes=[], headers={}, timeout=False):
|
ignore_codes=None, headers=None, timeout=False):
|
||||||
"""
|
"""
|
||||||
Wrapper for rest_call that verifies success and raises a
|
Wrapper for rest_call that verifies success and raises a
|
||||||
RemoteRestError on failure with a provided error string
|
RemoteRestError on failure with a provided error string
|
||||||
By default, 404 errors on DELETE calls are ignored because
|
By default, 404 errors on DELETE calls are ignored because
|
||||||
they already do not exist on the backend.
|
they already do not exist on the backend.
|
||||||
"""
|
"""
|
||||||
|
ignore_codes = ignore_codes or []
|
||||||
|
headers = headers or {}
|
||||||
if not ignore_codes and action == 'DELETE':
|
if not ignore_codes and action == 'DELETE':
|
||||||
ignore_codes = [404]
|
ignore_codes = [404]
|
||||||
resp = self.rest_call(action, resource, data, headers, ignore_codes,
|
resp = self.rest_call(action, resource, data, headers, ignore_codes,
|
||||||
|
|
|
@ -36,6 +36,7 @@ from neutron.plugins.ml2 import driver_api as api
|
||||||
|
|
||||||
EXTERNAL_PORT_OWNER = 'neutron:external_port'
|
EXTERNAL_PORT_OWNER = 'neutron:external_port'
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
put_context_in_serverpool = plugin.put_context_in_serverpool
|
||||||
|
|
||||||
# time in seconds to maintain existence of vswitch response
|
# time in seconds to maintain existence of vswitch response
|
||||||
CACHE_VSWITCH_TIME = 60
|
CACHE_VSWITCH_TIME = 60
|
||||||
|
@ -71,18 +72,22 @@ class BigSwitchMechanismDriver(plugin.NeutronRestProxyV2Base,
|
||||||
|
|
||||||
LOG.debug(_("Initialization done"))
|
LOG.debug(_("Initialization done"))
|
||||||
|
|
||||||
|
@put_context_in_serverpool
|
||||||
def create_network_postcommit(self, context):
|
def create_network_postcommit(self, context):
|
||||||
# create network on the network controller
|
# create network on the network controller
|
||||||
self._send_create_network(context.current)
|
self._send_create_network(context.current)
|
||||||
|
|
||||||
|
@put_context_in_serverpool
|
||||||
def update_network_postcommit(self, context):
|
def update_network_postcommit(self, context):
|
||||||
# update network on the network controller
|
# update network on the network controller
|
||||||
self._send_update_network(context.current)
|
self._send_update_network(context.current)
|
||||||
|
|
||||||
|
@put_context_in_serverpool
|
||||||
def delete_network_postcommit(self, context):
|
def delete_network_postcommit(self, context):
|
||||||
# delete network on the network controller
|
# delete network on the network controller
|
||||||
self._send_delete_network(context.current)
|
self._send_delete_network(context.current)
|
||||||
|
|
||||||
|
@put_context_in_serverpool
|
||||||
def create_port_postcommit(self, context):
|
def create_port_postcommit(self, context):
|
||||||
# create port on the network controller
|
# create port on the network controller
|
||||||
port = self._prepare_port_for_controller(context)
|
port = self._prepare_port_for_controller(context)
|
||||||
|
@ -90,6 +95,7 @@ class BigSwitchMechanismDriver(plugin.NeutronRestProxyV2Base,
|
||||||
self.async_port_create(port["network"]["tenant_id"],
|
self.async_port_create(port["network"]["tenant_id"],
|
||||||
port["network"]["id"], port)
|
port["network"]["id"], port)
|
||||||
|
|
||||||
|
@put_context_in_serverpool
|
||||||
def update_port_postcommit(self, context):
|
def update_port_postcommit(self, context):
|
||||||
# update port on the network controller
|
# update port on the network controller
|
||||||
port = self._prepare_port_for_controller(context)
|
port = self._prepare_port_for_controller(context)
|
||||||
|
@ -113,6 +119,7 @@ class BigSwitchMechanismDriver(plugin.NeutronRestProxyV2Base,
|
||||||
triggered_by_tenant=port["network"]["tenant_id"]
|
triggered_by_tenant=port["network"]["tenant_id"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@put_context_in_serverpool
|
||||||
def delete_port_postcommit(self, context):
|
def delete_port_postcommit(self, context):
|
||||||
# delete port on the network controller
|
# delete port on the network controller
|
||||||
port = context.current
|
port = context.current
|
||||||
|
|
|
@ -22,8 +22,10 @@ import ssl
|
||||||
import mock
|
import mock
|
||||||
from oslo.config import cfg
|
from oslo.config import cfg
|
||||||
|
|
||||||
|
from neutron import context
|
||||||
from neutron import manager
|
from neutron import manager
|
||||||
from neutron.openstack.common import importutils
|
from neutron.openstack.common import importutils
|
||||||
|
from neutron.openstack.common import jsonutils
|
||||||
from neutron.plugins.bigswitch import servermanager
|
from neutron.plugins.bigswitch import servermanager
|
||||||
from neutron.tests.unit.bigswitch import test_restproxy_plugin as test_rp
|
from neutron.tests.unit.bigswitch import test_restproxy_plugin as test_rp
|
||||||
|
|
||||||
|
@ -211,6 +213,23 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):
|
||||||
self.assertIn('EXTRA-HEADER', callheaders)
|
self.assertIn('EXTRA-HEADER', callheaders)
|
||||||
self.assertEqual(callheaders['EXTRA-HEADER'], 'HI')
|
self.assertEqual(callheaders['EXTRA-HEADER'], 'HI')
|
||||||
|
|
||||||
|
def test_req_context_header(self):
|
||||||
|
sp = manager.NeutronManager.get_plugin().servers
|
||||||
|
ncontext = context.Context('uid', 'tid')
|
||||||
|
sp.set_context(ncontext)
|
||||||
|
with mock.patch(HTTPCON) as conmock:
|
||||||
|
rv = conmock.return_value
|
||||||
|
rv.getresponse.return_value.getheader.return_value = 'HASHHEADER'
|
||||||
|
sp.rest_action('GET', '/')
|
||||||
|
callheaders = rv.request.mock_calls[0][1][3]
|
||||||
|
self.assertIn(servermanager.REQ_CONTEXT_HEADER, callheaders)
|
||||||
|
ctxdct = ncontext.to_dict()
|
||||||
|
# auth token is not included
|
||||||
|
ctxdct.pop('auth_token')
|
||||||
|
self.assertEqual(
|
||||||
|
ctxdct, jsonutils.loads(
|
||||||
|
callheaders[servermanager.REQ_CONTEXT_HEADER]))
|
||||||
|
|
||||||
def test_capabilities_retrieval(self):
|
def test_capabilities_retrieval(self):
|
||||||
sp = servermanager.ServerPool()
|
sp = servermanager.ServerPool()
|
||||||
with mock.patch(HTTPCON) as conmock:
|
with mock.patch(HTTPCON) as conmock:
|
||||||
|
|
|
@ -35,7 +35,8 @@ from neutron.tests.unit import test_db_plugin
|
||||||
PHYS_NET = 'physnet1'
|
PHYS_NET = 'physnet1'
|
||||||
VLAN_START = 1000
|
VLAN_START = 1000
|
||||||
VLAN_END = 1100
|
VLAN_END = 1100
|
||||||
SERVER_POOL = 'neutron.plugins.bigswitch.servermanager.ServerPool'
|
SERVER_MANAGER = 'neutron.plugins.bigswitch.servermanager'
|
||||||
|
SERVER_POOL = SERVER_MANAGER + '.ServerPool'
|
||||||
DRIVER_MOD = 'neutron.plugins.ml2.drivers.mech_bigswitch.driver'
|
DRIVER_MOD = 'neutron.plugins.ml2.drivers.mech_bigswitch.driver'
|
||||||
DRIVER = DRIVER_MOD + '.BigSwitchMechanismDriver'
|
DRIVER = DRIVER_MOD + '.BigSwitchMechanismDriver'
|
||||||
|
|
||||||
|
@ -212,3 +213,11 @@ class TestBigSwitchMechDriverPortsV2(test_db_plugin.TestPortsV2,
|
||||||
create_body = rmock.mock_calls[-1][1][2]
|
create_body = rmock.mock_calls[-1][1][2]
|
||||||
self.assertIsNotNone(create_body['bound_segment'])
|
self.assertIsNotNone(create_body['bound_segment'])
|
||||||
self.assertEqual(create_body[portbindings.HOST_ID], ext_id)
|
self.assertEqual(create_body[portbindings.HOST_ID], ext_id)
|
||||||
|
|
||||||
|
def test_req_context_header_present(self):
|
||||||
|
with contextlib.nested(
|
||||||
|
mock.patch(SERVER_MANAGER + '.ServerProxy.rest_call'),
|
||||||
|
self.port(**{'device_id': 'devid', 'binding:host_id': 'host'})
|
||||||
|
) as (mock_rest, p):
|
||||||
|
headers = mock_rest.mock_calls[0][1][3]
|
||||||
|
self.assertIn('X-REQ-CONTEXT', headers)
|
||||||
|
|
Loading…
Reference in New Issue