~niedbalski/ubuntu/vivid/neutron/fixes-1447803

« back to all changes in this revision

Viewing changes to neutron/plugins/bigswitch/servermanager.py

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-10-03 18:45:23 UTC
  • mfrom: (1.1.15)
  • Revision ID: package-import@ubuntu.com-20141003184523-4mt6dy1q3j8n30c9
Tags: 1:2014.2~rc1-0ubuntu1
* New upstream release candidate:
  - d/p/*: Refreshed.
  - d/control: Add python-requests-mock to BD's.
  - d/control: Align versioned requirements with upstream.
* Transition linuxbridge and openvswitch plugin users to modular
  layer 2 plugin (LP: #1323729):
  - d/control: Mark removed plugin packages as transitional, depend
    on neutron-plugin-ml2, mark oldlibs/extra.
  - d/neutron-plugin-{linuxbridge,openvswitch}.install: Drop.
  - d/control: Depend on neutron-plugin-ml2 for linuxbridge
    agent package.
  - d/neutron-plugin-linuxbridge-agent.upstart: Use ml2 plugin
    configuration files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
13
#    License for the specific language governing permissions and limitations
14
14
#    under the License.
15
 
#
16
 
# @author: Mandeep Dhami, Big Switch Networks, Inc.
17
 
# @author: Sumit Naiksatam, sumitnaiksatam@gmail.com, Big Switch Networks, Inc.
18
 
# @author: Kevin Benton, Big Switch Networks, Inc.
19
15
 
20
16
"""
21
17
This module manages the HTTP and HTTPS connections to the backend controllers.
35
31
import os
36
32
import socket
37
33
import ssl
 
34
import time
38
35
import weakref
39
36
 
40
37
import eventlet
64
61
ROUTER_INTF_PATH = "/tenants/%s/routers/%s/interfaces/%s"
65
62
TOPOLOGY_PATH = "/topology"
66
63
HEALTH_PATH = "/health"
 
64
SWITCHES_PATH = "/switches/%s"
67
65
SUCCESS_CODES = range(200, 207)
68
66
FAILURE_CODES = [0, 301, 302, 303, 400, 401, 403, 404, 500, 501, 502, 503,
69
67
                 504, 505]
70
68
BASE_URI = '/networkService/v1.1'
71
69
ORCHESTRATION_SERVICE_ID = 'Neutron v2.0'
72
70
HASH_MATCH_HEADER = 'X-BSN-BVS-HASH-MATCH'
 
71
REQ_CONTEXT_HEADER = 'X-REQ-CONTEXT'
73
72
# error messages
74
73
NXNETWORK = 'NXVNS'
 
74
HTTP_SERVICE_UNAVAILABLE_RETRY_COUNT = 3
 
75
HTTP_SERVICE_UNAVAILABLE_RETRY_INTERVAL = 3
75
76
 
76
77
 
77
78
class RemoteRestError(exceptions.NeutronException):
121
122
                                                'cap': self.capabilities})
122
123
        return self.capabilities
123
124
 
124
 
    def rest_call(self, action, resource, data='', headers={}, timeout=False,
125
 
                  reconnect=False, hash_handler=None):
 
125
    def rest_call(self, action, resource, data='', headers=None,
 
126
                  timeout=False, reconnect=False, hash_handler=None):
126
127
        uri = self.base_uri + resource
127
128
        body = jsonutils.dumps(data)
128
 
        if not headers:
129
 
            headers = {}
 
129
        headers = headers or {}
130
130
        headers['Content-type'] = 'application/json'
131
131
        headers['Accept'] = 'application/json'
132
132
        headers['NeutronProxy-Agent'] = self.name
196
196
                except ValueError:
197
197
                    # response was not JSON, ignore the exception
198
198
                    pass
199
 
            else:
200
 
                hash_handler.close_update_session()
201
199
            ret = (response.status, response.reason, respstr, respdata)
202
200
        except httplib.HTTPException:
203
201
            # If we were using a cached connection, try again with a new one.
423
421
    @utils.synchronized('bsn-rest-call')
424
422
    def rest_call(self, action, resource, data, headers, ignore_codes,
425
423
                  timeout=False):
426
 
        hash_handler = cdb.HashHandler(context=self.get_context_ref())
 
424
        context = self.get_context_ref()
 
425
        if context:
 
426
            # include the requesting context information if available
 
427
            cdict = context.to_dict()
 
428
            # remove the auth token so it's not present in debug logs on the
 
429
            # backend controller
 
430
            cdict.pop('auth_token', None)
 
431
            headers[REQ_CONTEXT_HEADER] = jsonutils.dumps(cdict)
 
432
        hash_handler = cdb.HashHandler(context=context)
427
433
        good_first = sorted(self.servers, key=lambda x: x.failed)
428
434
        first_response = None
429
435
        for active_server in good_first:
430
 
            ret = active_server.rest_call(action, resource, data, headers,
431
 
                                          timeout,
432
 
                                          reconnect=self.always_reconnect,
433
 
                                          hash_handler=hash_handler)
 
436
            for x in range(HTTP_SERVICE_UNAVAILABLE_RETRY_COUNT + 1):
 
437
                ret = active_server.rest_call(action, resource, data, headers,
 
438
                                              timeout,
 
439
                                              reconnect=self.always_reconnect,
 
440
                                              hash_handler=hash_handler)
 
441
                if ret[0] != httplib.SERVICE_UNAVAILABLE:
 
442
                    break
 
443
                time.sleep(HTTP_SERVICE_UNAVAILABLE_RETRY_INTERVAL)
 
444
 
434
445
            # If inconsistent, do a full synchronization
435
446
            if ret[0] == httplib.CONFLICT:
436
447
                if not self.get_topo_function:
472
483
        return first_response
473
484
 
474
485
    def rest_action(self, action, resource, data='', errstr='%s',
475
 
                    ignore_codes=[], headers={}, timeout=False):
 
486
                    ignore_codes=None, headers=None, timeout=False):
476
487
        """
477
488
        Wrapper for rest_call that verifies success and raises a
478
489
        RemoteRestError on failure with a provided error string
479
490
        By default, 404 errors on DELETE calls are ignored because
480
491
        they already do not exist on the backend.
481
492
        """
 
493
        ignore_codes = ignore_codes or []
 
494
        headers = headers or {}
482
495
        if not ignore_codes and action == 'DELETE':
483
496
            ignore_codes = [404]
484
497
        resp = self.rest_call(action, resource, data, headers, ignore_codes,
578
591
        errstr = _("Unable to delete floating IP: %s")
579
592
        self.rest_action('DELETE', resource, errstr=errstr)
580
593
 
 
594
    def rest_get_switch(self, switch_id):
 
595
        resource = SWITCHES_PATH % switch_id
 
596
        errstr = _("Unable to retrieve switch: %s")
 
597
        return self.rest_action('GET', resource, errstr=errstr)
 
598
 
581
599
    def _consistency_watchdog(self, polling_interval=60):
582
600
        if 'consistency' not in self.get_capabilities():
583
601
            LOG.warning(_("Backend server(s) do not support automated "