From 5b4ef2a513bc7c8d2a2eecb57f656bf42bb0dd52 Mon Sep 17 00:00:00 2001 From: Kevin Benton Date: Wed, 10 Jul 2013 16:49:31 -0700 Subject: [PATCH] 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 --- neutron/plugins/bigswitch/plugin.py | 29 ++++++++++--------- .../unit/bigswitch/test_restproxy_plugin.py | 19 +++++++++++- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/neutron/plugins/bigswitch/plugin.py b/neutron/plugins/bigswitch/plugin.py index 29a5fb7f9..a08246894 100644 --- a/neutron/plugins/bigswitch/plugin.py +++ b/neutron/plugins/bigswitch/plugin.py @@ -268,13 +268,13 @@ class ServerPool(object): return ServerProxy(server, port, self.ssl, self.auth, self.neutron_id, self.timeout, self.base_uri, self.name) - def server_failure(self, resp): + def server_failure(self, resp, ignore_codes=[]): """Define failure codes as required. Note: We assume 301-303 is a failure, and try the next server in 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): """Defining success codes as required. @@ -283,12 +283,12 @@ class ServerPool(object): """ 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 = [] while self.servers: active_server = self.servers[0] 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) return ret else: @@ -308,17 +308,17 @@ class ServerPool(object): self.servers.extend(failed_servers) return (0, None, None, None) - def get(self, resource, data='', headers=None): - return self.rest_call('GET', resource, data, headers) + def get(self, resource, data='', headers=None, ignore_codes=[]): + return self.rest_call('GET', resource, data, headers, ignore_codes) - def put(self, resource, data, headers=None): - return self.rest_call('PUT', resource, data, headers) + def put(self, resource, data, headers=None, ignore_codes=[]): + return self.rest_call('PUT', resource, data, headers, ignore_codes) - def post(self, resource, data, headers=None): - return self.rest_call('POST', resource, data, headers) + def post(self, resource, data, headers=None, ignore_codes=[]): + return self.rest_call('POST', resource, data, headers, ignore_codes) - def delete(self, resource, data='', headers=None): - return self.rest_call('DELETE', resource, data, headers) + def delete(self, resource, data='', headers=None, ignore_codes=[]): + return self.rest_call('DELETE', resource, data, headers, ignore_codes) 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 try: resource = ATTACHMENT_PATH % (tenant_id, net_id, port_id) - ret = self.servers.delete(resource) - if not self.servers.action_success(ret): + ret = self.servers.delete(resource, ignore_codes=[404]) + if self.servers.server_failure(ret, ignore_codes=[404]): raise RemoteRestError(ret[2]) except RemoteRestError as e: LOG.error(_("NeutronRestProxyV2: Unable to update remote port: " "%s"), e.message) + raise def create_subnet(self, context, subnet): LOG.debug(_("NeutronRestProxyV2: create_subnet() called")) diff --git a/neutron/tests/unit/bigswitch/test_restproxy_plugin.py b/neutron/tests/unit/bigswitch/test_restproxy_plugin.py index 920d02a9b..b6d743191 100644 --- a/neutron/tests/unit/bigswitch/test_restproxy_plugin.py +++ b/neutron/tests/unit/bigswitch/test_restproxy_plugin.py @@ -43,16 +43,33 @@ class HTTPResponseMock(): 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(): def __init__(self, server, port, timeout): + self.response = None pass def request(self, action, uri, body, headers): + if uri.endswith('attachment') and action == 'DELETE': + self.response = HTTPResponseMock404(None) + else: + self.response = HTTPResponseMock(None) return def getresponse(self): - return HTTPResponseMock(None) + return self.response def close(self): pass -- 2.45.2