Add option to ignore backend HTTP error in BigSwitch plugin

This patch fixes the way the BigSwitch plugin ignores 404
errors from the backend controller by allowing HTTP codes
to be selectively ignored on REST calls. This prevents
unnecessary exception handling and failover logic in calls
where 404 codes are acceptable.

Change-Id: Ia1118c039af3b45d96fb3f8a5fb5d3febdf50f4f
Fixes: bug #1200023
This commit is contained in:
Kevin Benton
2013-07-10 16:49:31 -07:00
parent f569c75ed9
commit 5b4ef2a513
2 changed files with 33 additions and 15 deletions

View File

@@ -268,13 +268,13 @@ class ServerPool(object):
return ServerProxy(server, port, self.ssl, self.auth, self.neutron_id, return ServerProxy(server, port, self.ssl, self.auth, self.neutron_id,
self.timeout, self.base_uri, self.name) self.timeout, self.base_uri, self.name)
def server_failure(self, resp): def server_failure(self, resp, ignore_codes=[]):
"""Define failure codes as required. """Define failure codes as required.
Note: We assume 301-303 is a failure, and try the next server in Note: We assume 301-303 is a failure, and try the next server in
the server pool. the server pool.
""" """
return resp[0] in FAILURE_CODES return (resp[0] in FAILURE_CODES and resp[0] not in ignore_codes)
def action_success(self, resp): def action_success(self, resp):
"""Defining success codes as required. """Defining success codes as required.
@@ -283,12 +283,12 @@ class ServerPool(object):
""" """
return resp[0] in SUCCESS_CODES return resp[0] in SUCCESS_CODES
def rest_call(self, action, resource, data, headers): def rest_call(self, action, resource, data, headers, ignore_codes):
failed_servers = [] failed_servers = []
while self.servers: while self.servers:
active_server = self.servers[0] active_server = self.servers[0]
ret = active_server.rest_call(action, resource, data, headers) ret = active_server.rest_call(action, resource, data, headers)
if not self.server_failure(ret): if not self.server_failure(ret, ignore_codes):
self.servers.extend(failed_servers) self.servers.extend(failed_servers)
return ret return ret
else: else:
@@ -308,17 +308,17 @@ class ServerPool(object):
self.servers.extend(failed_servers) self.servers.extend(failed_servers)
return (0, None, None, None) return (0, None, None, None)
def get(self, resource, data='', headers=None): def get(self, resource, data='', headers=None, ignore_codes=[]):
return self.rest_call('GET', resource, data, headers) return self.rest_call('GET', resource, data, headers, ignore_codes)
def put(self, resource, data, headers=None): def put(self, resource, data, headers=None, ignore_codes=[]):
return self.rest_call('PUT', resource, data, headers) return self.rest_call('PUT', resource, data, headers, ignore_codes)
def post(self, resource, data, headers=None): def post(self, resource, data, headers=None, ignore_codes=[]):
return self.rest_call('POST', resource, data, headers) return self.rest_call('POST', resource, data, headers, ignore_codes)
def delete(self, resource, data='', headers=None): def delete(self, resource, data='', headers=None, ignore_codes=[]):
return self.rest_call('DELETE', resource, data, headers) return self.rest_call('DELETE', resource, data, headers, ignore_codes)
class RpcProxy(dhcp_rpc_base.DhcpRpcCallbackMixin): class RpcProxy(dhcp_rpc_base.DhcpRpcCallbackMixin):
@@ -790,12 +790,13 @@ class NeutronRestProxyV2(db_base_plugin_v2.NeutronDbPluginV2,
# delete from network ctrl. Remote error on delete is ignored # delete from network ctrl. Remote error on delete is ignored
try: try:
resource = ATTACHMENT_PATH % (tenant_id, net_id, port_id) resource = ATTACHMENT_PATH % (tenant_id, net_id, port_id)
ret = self.servers.delete(resource) ret = self.servers.delete(resource, ignore_codes=[404])
if not self.servers.action_success(ret): if self.servers.server_failure(ret, ignore_codes=[404]):
raise RemoteRestError(ret[2]) raise RemoteRestError(ret[2])
except RemoteRestError as e: except RemoteRestError as e:
LOG.error(_("NeutronRestProxyV2: Unable to update remote port: " LOG.error(_("NeutronRestProxyV2: Unable to update remote port: "
"%s"), e.message) "%s"), e.message)
raise
def create_subnet(self, context, subnet): def create_subnet(self, context, subnet):
LOG.debug(_("NeutronRestProxyV2: create_subnet() called")) LOG.debug(_("NeutronRestProxyV2: create_subnet() called"))

View File

@@ -43,16 +43,33 @@ class HTTPResponseMock():
return "{'status': '200 OK'}" return "{'status': '200 OK'}"
class HTTPResponseMock404():
status = 404
reason = 'Not Found'
def __init__(self, sock, debuglevel=0, strict=0, method=None,
buffering=False):
pass
def read(self):
return "{'status': '404 Not Found'}"
class HTTPConnectionMock(): class HTTPConnectionMock():
def __init__(self, server, port, timeout): def __init__(self, server, port, timeout):
self.response = None
pass pass
def request(self, action, uri, body, headers): def request(self, action, uri, body, headers):
if uri.endswith('attachment') and action == 'DELETE':
self.response = HTTPResponseMock404(None)
else:
self.response = HTTPResponseMock(None)
return return
def getresponse(self): def getresponse(self):
return HTTPResponseMock(None) return self.response
def close(self): def close(self):
pass pass