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):
@functools.wraps(f)
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 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'
ORCHESTRATION_SERVICE_ID = 'Neutron v2.0'
HASH_MATCH_HEADER = 'X-BSN-BVS-HASH-MATCH'
REQ_CONTEXT_HEADER = 'X-REQ-CONTEXT'
# error messages
NXNETWORK = 'NXVNS'
HTTP_SERVICE_UNAVAILABLE_RETRY_COUNT = 3
@ -125,12 +126,11 @@ class ServerProxy(object):
'cap': self.capabilities})
return self.capabilities
def rest_call(self, action, resource, data='', headers={}, timeout=False,
reconnect=False, hash_handler=None):
def rest_call(self, action, resource, data='', headers=None,
timeout=False, reconnect=False, hash_handler=None):
uri = self.base_uri + resource
body = jsonutils.dumps(data)
if not headers:
headers = {}
headers = headers or {}
headers['Content-type'] = 'application/json'
headers['Accept'] = 'application/json'
headers['NeutronProxy-Agent'] = self.name
@ -425,7 +425,15 @@ class ServerPool(object):
@utils.synchronized('bsn-rest-call')
def rest_call(self, action, resource, data, headers, ignore_codes,
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)
first_response = None
for active_server in good_first:
@ -479,13 +487,15 @@ class ServerPool(object):
return first_response
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
RemoteRestError on failure with a provided error string
By default, 404 errors on DELETE calls are ignored because
they already do not exist on the backend.
"""
ignore_codes = ignore_codes or []
headers = headers or {}
if not ignore_codes and action == 'DELETE':
ignore_codes = [404]
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'
LOG = log.getLogger(__name__)
put_context_in_serverpool = plugin.put_context_in_serverpool
# time in seconds to maintain existence of vswitch response
CACHE_VSWITCH_TIME = 60
@ -71,18 +72,22 @@ class BigSwitchMechanismDriver(plugin.NeutronRestProxyV2Base,
LOG.debug(_("Initialization done"))
@put_context_in_serverpool
def create_network_postcommit(self, context):
# create network on the network controller
self._send_create_network(context.current)
@put_context_in_serverpool
def update_network_postcommit(self, context):
# update network on the network controller
self._send_update_network(context.current)
@put_context_in_serverpool
def delete_network_postcommit(self, context):
# delete network on the network controller
self._send_delete_network(context.current)
@put_context_in_serverpool
def create_port_postcommit(self, context):
# create port on the network controller
port = self._prepare_port_for_controller(context)
@ -90,6 +95,7 @@ class BigSwitchMechanismDriver(plugin.NeutronRestProxyV2Base,
self.async_port_create(port["network"]["tenant_id"],
port["network"]["id"], port)
@put_context_in_serverpool
def update_port_postcommit(self, context):
# update port on the network controller
port = self._prepare_port_for_controller(context)
@ -113,6 +119,7 @@ class BigSwitchMechanismDriver(plugin.NeutronRestProxyV2Base,
triggered_by_tenant=port["network"]["tenant_id"]
)
@put_context_in_serverpool
def delete_port_postcommit(self, context):
# delete port on the network controller
port = context.current

View File

@ -22,8 +22,10 @@ import ssl
import mock
from oslo.config import cfg
from neutron import context
from neutron import manager
from neutron.openstack.common import importutils
from neutron.openstack.common import jsonutils
from neutron.plugins.bigswitch import servermanager
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.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):
sp = servermanager.ServerPool()
with mock.patch(HTTPCON) as conmock:

View File

@ -35,7 +35,8 @@ from neutron.tests.unit import test_db_plugin
PHYS_NET = 'physnet1'
VLAN_START = 1000
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 = DRIVER_MOD + '.BigSwitchMechanismDriver'
@ -212,3 +213,11 @@ class TestBigSwitchMechDriverPortsV2(test_db_plugin.TestPortsV2,
create_body = rmock.mock_calls[-1][1][2]
self.assertIsNotNone(create_body['bound_segment'])
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)