~corey.bryant/ubuntu/trusty/neutron/lp1318721

« back to all changes in this revision

Viewing changes to neutron/plugins/ml2/drivers/mechanism_odl.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short, Corey Bryant
  • Date: 2014-10-06 09:15:06 UTC
  • mfrom: (28.1.4 trusty-proposed)
  • Revision ID: package-import@ubuntu.com-20141006091506-cesvev43moce4y74
Tags: 1:2014.1.3-0ubuntu1
[ Corey Bryant ]
* Resynchronize with stable/icehouse (4a0210e) (LP: #1377136):
  - [3a30d19] Deletes floating ip related connection states
  - [dd4b77f] Forbid regular users to reset admin-only attrs to default values
  - [dc2c893] Add delete operations for the ODL MechanismDriver
  - [b51e2c7] Add missing ml2 plugin to migration 1fcfc149aca4
  - [a17a500] Don't convert numeric protocol values to int
  - [3a85946] NSX: Optionally not enforce nat rule match length check
  - [645f984] Don't spawn metadata-proxy for non-isolated nets
  - [b464d89] Big Switch: Check for 'id' in port before lookup
  - [3116ffa] use TRUE in SQL for boolean var
  - [3520e66] call security_groups_member_updated in port_update
  - [50e1534] Don't allow user to set firewall rule with port and no protocol
  - [0061533] BSN: Add context to backend request for debugging
  - [6de6d61] Improve ODL ML2 Exception Handling
  - [2a4153d] Send network name and uuid to subnet create
  - [b5e3c9a] BSN: Allow concurrent reads to consistency DB
  - [b201432] Big Switch: Retry on 503 errors from backend
  - [f6c47ee] NSX: log request body to NSX as debug
  - [97d622a] Fix metadata agent's auth info caching
  - [255df45] NSX: Correct allowed_address_pair return value on create_port
  - [5bea041] Neutron should not use the neutronclient utils module for import_class
  - [d5314e2] Cisco N1kv plugin to send subtype on network profile creation
  - [f32d1ce] Pass object to policy when finding fields to strip
  - [8b5f6be] Call policy.init() once per API request
  - [9a6d811] Perform policy checks only once on list responses
  - [c48db90] Datacenter moid should not be tuple
  - [161d465] Allow unsharing a network used as gateway/floatingip
  - [9574a2f] Add support for router scheduling in Cisco N1kv Plugin
  - [6f54565] Fix func job hook script permission problems
  - [ea43103] Add hook scripts for the functional infra job
  - [8161cb7] Fixes Hyper-V agent issue on Hyper-V 2008 R2
  - [8e99cfd] Fixes Hyper-V issue due to ML2 RPC versioning
  - [69f9121] Ensure ip6tables are used only if ipv6 is enabled in kernel
  - [399b809] Remove explicit dependency on amqplib
  - [a872143] Clear entries in Cisco N1KV specific tables on rollback
  - [ad82fad] Verify ML2 type driver exists before calling del
  - [af2cc98] Big Switch: Only update hash header on success
  - [b1e5eec] Ignore variable column widths in ovsdb functional tests
  - [4a0210e] VMWare: don't notify on disassociate_floatingips()

Show diffs side-by-side

added added

removed removed

Lines of Context:
39
39
ODL_PORT = 'port'
40
40
ODL_PORTS = 'ports'
41
41
 
42
 
not_found_exception_map = {ODL_NETWORKS: n_exc.NetworkNotFound,
43
 
                           ODL_SUBNETS: n_exc.SubnetNotFound,
44
 
                           ODL_PORTS: n_exc.PortNotFound}
45
 
 
46
42
odl_opts = [
47
43
    cfg.StrOpt('url',
48
44
               help=_("HTTP URL of OpenDaylight REST interface.")),
68
64
            pass
69
65
 
70
66
 
 
67
class OpendaylightAuthError(n_exc.NeutronException):
 
68
    message = '%(msg)s'
 
69
 
 
70
 
71
71
class JsessionId(requests.auth.AuthBase):
72
72
 
73
73
    """Attaches the JSESSIONID and JSESSIONIDSSO cookies to an HTTP Request.
95
95
    def obtain_auth_cookies(self):
96
96
        """Make a REST call to obtain cookies for ODL authenticiation."""
97
97
 
98
 
        r = requests.get(self.url, auth=(self.username, self.password))
99
 
        r.raise_for_status()
 
98
        try:
 
99
            r = requests.get(self.url, auth=(self.username, self.password))
 
100
            r.raise_for_status()
 
101
        except requests.exceptions.HTTPError as e:
 
102
            raise OpendaylightAuthError(msg=_("Failed to authenticate with "
 
103
                                              "OpenDaylight: %s") % e)
 
104
        except requests.exceptions.Timeout as e:
 
105
            raise OpendaylightAuthError(msg=_("Authentication Timed"
 
106
                                              " Out: %s") % e)
 
107
 
100
108
        jsessionid = r.cookies.get('JSESSIONID')
101
109
        jsessionidsso = r.cookies.get('JSESSIONIDSSO')
102
110
        if jsessionid and jsessionidsso:
167
175
        if self.out_of_sync:
168
176
            self.sync_full(context)
169
177
        else:
170
 
            self.sync_object(operation, object_type, context)
 
178
            self.sync_single_resource(operation, object_type, context)
171
179
 
172
180
    def filter_create_network_attributes(self, network, context, dbcontext):
173
181
        """Filter out network attributes not required for a create."""
199
207
                urlpath = collection_name + '/' + resource['id']
200
208
                self.sendjson('get', urlpath, None)
201
209
            except requests.exceptions.HTTPError as e:
202
 
                if e.response.status_code == 404:
203
 
                    attr_filter(resource, context, dbcontext)
204
 
                    to_be_synced.append(resource)
 
210
                with excutils.save_and_reraise_exception() as ctx:
 
211
                    if e.response.status_code == requests.codes.not_found:
 
212
                        attr_filter(resource, context, dbcontext)
 
213
                        to_be_synced.append(resource)
 
214
                        ctx.reraise = False
205
215
 
206
216
        key = resource_name if len(to_be_synced) == 1 else collection_name
207
217
 
208
218
        # 400 errors are returned if an object exists, which we ignore.
209
 
        self.sendjson('post', collection_name, {key: to_be_synced}, [400])
 
219
        self.sendjson('post', collection_name, {key: to_be_synced},
 
220
                      [requests.codes.bad_request])
210
221
 
211
222
    @utils.synchronized('odl-sync-full')
212
223
    def sync_full(self, context):
213
224
        """Resync the entire database to ODL.
214
225
 
215
226
        Transition to the in-sync state on success.
216
 
        Note: we only allow a single thead in here at a time.
 
227
        Note: we only allow a single thread in here at a time.
217
228
        """
218
229
        if not self.out_of_sync:
219
230
            return
256
267
                         ODL_SUBNETS: filter_update_subnet_attributes,
257
268
                         ODL_PORTS: filter_update_port_attributes}
258
269
 
259
 
    def sync_single_resource(self, operation, object_type, obj_id,
260
 
                             context, attr_filter_create, attr_filter_update):
 
270
    def sync_single_resource(self, operation, object_type, context):
261
271
        """Sync over a single resource from Neutron to OpenDaylight.
262
272
 
263
273
        Handle syncing a single operation over to OpenDaylight, and correctly
264
274
        filter attributes out which are not required for the requisite
265
275
        operation (create or update) being handled.
266
276
        """
267
 
        dbcontext = context._plugin_context
268
 
        if operation == 'create':
269
 
            urlpath = object_type
270
 
            method = 'post'
271
 
        else:
272
 
            urlpath = object_type + '/' + obj_id
273
 
            method = 'put'
274
 
 
275
277
        try:
276
 
            obj_getter = getattr(context._plugin, 'get_%s' % object_type[:-1])
277
 
            resource = obj_getter(dbcontext, obj_id)
278
 
        except not_found_exception_map[object_type]:
279
 
            LOG.debug(_('%(object_type)s not found (%(obj_id)s)'),
280
 
                      {'object_type': object_type.capitalize(),
281
 
                      'obj_id': obj_id})
282
 
        else:
283
 
            if operation == 'create':
284
 
                attr_filter_create(self, resource, context, dbcontext)
285
 
            elif operation == 'update':
286
 
                attr_filter_update(self, resource, context, dbcontext)
287
 
            try:
 
278
            obj_id = context.current['id']
 
279
            if operation == 'delete':
 
280
                self.sendjson('delete', object_type + '/' + obj_id, None)
 
281
            else:
 
282
                if operation == 'create':
 
283
                    urlpath = object_type
 
284
                    method = 'post'
 
285
                    attr_filter = self.create_object_map[object_type]
 
286
                elif operation == 'update':
 
287
                    urlpath = object_type + '/' + obj_id
 
288
                    method = 'put'
 
289
                    attr_filter = self.update_object_map[object_type]
 
290
                resource = context.current.copy()
 
291
                attr_filter(self, resource, context, context._plugin_context)
288
292
                # 400 errors are returned if an object exists, which we ignore.
289
293
                self.sendjson(method, urlpath, {object_type[:-1]: resource},
290
 
                              [400])
291
 
            except Exception:
292
 
                with excutils.save_and_reraise_exception():
293
 
                    self.out_of_sync = True
294
 
 
295
 
    def sync_object(self, operation, object_type, context):
296
 
        """Synchronize the single modified record to ODL."""
297
 
        obj_id = context.current['id']
298
 
 
299
 
        self.sync_single_resource(operation, object_type, obj_id, context,
300
 
                                  self.create_object_map[object_type],
301
 
                                  self.update_object_map[object_type])
 
294
                              [requests.codes.bad_request])
 
295
        except Exception:
 
296
            with excutils.save_and_reraise_exception():
 
297
                self.out_of_sync = True
302
298
 
303
299
    def add_security_groups(self, context, dbcontext, port):
304
300
        """Populate the 'security_groups' field with entire records."""