Merge "BSN: Add context to backend request for debugging"

This commit is contained in:
Jenkins 2014-09-15 12:34:12 +00:00 committed by Gerrit Code Review
commit 4c54d6a57e
5 changed files with 55 additions and 8 deletions

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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:

View File

@ -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)