Browse Source

Revert "Integration of (Distributed) Port Binding OVO"

This reverts commit febeaf5d40.

This patch broke postgres tempest jobs, as well as introduced potential
race conditions in database layer because of mixed usage of old and new
engine facades.

Related-Bug: #1744829
Change-Id: Ic142ae7faf4e5f10cbdf761d7e6f3d442e94a3eb
tags/12.0.0.0rc1
Ihar Hrachyshka 1 year ago
parent
commit
906eda44d2

+ 2
- 14
neutron/objects/base.py View File

@@ -27,7 +27,6 @@ from oslo_versionedobjects import base as obj_base
27 27
 from oslo_versionedobjects import exception as obj_exception
28 28
 from oslo_versionedobjects import fields as obj_fields
29 29
 import six
30
-from sqlalchemy import exc as sql_exc
31 30
 
32 31
 from neutron._i18n import _
33 32
 from neutron.db import api as db_api
@@ -319,11 +318,7 @@ def _detach_db_obj(func):
319 318
             # TODO(ihrachys) consider refreshing just changed attributes
320 319
             self.obj_context.session.refresh(self.db_obj)
321 320
         # detach the model so that consequent fetches don't reuse it
322
-        try:
323
-            self.obj_context.session.expunge(self.db_obj)
324
-        except sql_exc.InvalidRequestError:
325
-            # already detached
326
-            pass
321
+        self.obj_context.session.expunge(self.db_obj)
327 322
         return res
328 323
     return decorator
329 324
 
@@ -350,8 +345,6 @@ class DeclarativeObject(abc.ABCMeta):
350 345
                 if key in cls.fields or key in cls.obj_extra_fields:
351 346
                     fields_no_update_set.add(key)
352 347
         cls.fields_no_update = list(fields_no_update_set)
353
-        if name in ('PortBinding', 'DistributedPortBinding'):
354
-            cls.fields_no_update.remove('host')
355 348
 
356 349
         model = getattr(cls, 'db_model', None)
357 350
         if model:
@@ -502,12 +495,7 @@ class NeutronDbObject(NeutronObject):
502 495
         obj = cls(context)
503 496
         obj.from_db_object(db_obj)
504 497
         # detach the model so that consequent fetches don't reuse it
505
-        # TODO(lujinluo): remove the try block when Port OVO is in place.
506
-        try:
507
-            context.session.expunge(obj.db_obj)
508
-        except sql_exc.InvalidRequestError:
509
-            # already detached
510
-            pass
498
+        context.session.expunge(obj.db_obj)
511 499
         return obj
512 500
 
513 501
     def obj_load_attr(self, attrname):

+ 1
- 17
neutron/objects/ports.py View File

@@ -36,22 +36,6 @@ class PortBindingBase(base.NeutronDbObject):
36 36
         'Port': {'port_id': 'id'},
37 37
     }
38 38
 
39
-    def update(self):
40
-        """Override to handle host update in Port Binding.
41
-        Delete old Port Binding entry, update the hostname and create new
42
-        Port Binding with all values saved in DB.
43
-        This is done due to host being a primary key, and OVO is not able
44
-        to update primary key fields.
45
-        """
46
-        if self.db_obj and self.host != self.db_obj.host:
47
-            with self.obj_context.session.begin(subtransactions=True):
48
-                old_obj = self._load_object(self.obj_context, self.db_obj)
49
-                old_obj.delete()
50
-                self._changed_fields = set(self.fields.keys())
51
-                self.create()
52
-        else:
53
-            super(PortBindingBase, self).update()
54
-
55 39
     @classmethod
56 40
     def modify_fields_to_db(cls, fields):
57 41
         result = super(PortBindingBase, cls).modify_fields_to_db(fields)
@@ -85,7 +69,7 @@ class PortBinding(PortBindingBase):
85 69
 
86 70
     fields = {
87 71
         'port_id': common_types.UUIDField(),
88
-        'host': obj_fields.StringField(default=''),
72
+        'host': obj_fields.StringField(),
89 73
         'profile': common_types.DictOfMiscValuesField(),
90 74
         'vif_type': obj_fields.StringField(),
91 75
         'vif_details': common_types.DictOfMiscValuesField(nullable=True),

+ 46
- 39
neutron/plugins/ml2/db.py View File

@@ -18,8 +18,8 @@ from neutron_lib.callbacks import events
18 18
 from neutron_lib.callbacks import registry
19 19
 from neutron_lib.callbacks import resources
20 20
 from neutron_lib import constants as n_const
21
-from neutron_lib.objects import exceptions
22 21
 from neutron_lib.plugins import directory
22
+from oslo_db import exception as db_exc
23 23
 from oslo_log import log
24 24
 from oslo_utils import uuidutils
25 25
 import six
@@ -31,7 +31,6 @@ from neutron.db import api as db_api
31 31
 from neutron.db.models import securitygroup as sg_models
32 32
 from neutron.db import models_v2
33 33
 from neutron.objects import ports as port_obj
34
-from neutron.objects import utils as obj_utils
35 34
 from neutron.plugins.ml2 import models
36 35
 from neutron.services.segments import exceptions as seg_exc
37 36
 
@@ -43,10 +42,11 @@ MAX_PORTS_PER_QUERY = 500
43 42
 
44 43
 @db_api.context_manager.writer
45 44
 def add_port_binding(context, port_id):
46
-    binding = port_obj.PortBinding(
47
-        context, port_id=port_id, vif_type=portbindings.VIF_TYPE_UNBOUND)
48
-    binding.create()
49
-    return binding
45
+    record = models.PortBinding(
46
+        port_id=port_id,
47
+        vif_type=portbindings.VIF_TYPE_UNBOUND)
48
+    context.session.add(record)
49
+    return record
50 50
 
51 51
 
52 52
 @db_api.context_manager.writer
@@ -91,32 +91,35 @@ def clear_binding_levels(context, port_id, host):
91 91
 
92 92
 
93 93
 def ensure_distributed_port_binding(context, port_id, host, router_id=None):
94
-    binding_obj = port_obj.DistributedPortBinding.get_object(
95
-        context, port_id=port_id, host=host)
96
-    if binding_obj:
97
-        return binding_obj
94
+    with db_api.context_manager.reader.using(context):
95
+        record = (context.session.query(models.DistributedPortBinding).
96
+                  filter_by(port_id=port_id, host=host).first())
97
+    if record:
98
+        return record
98 99
 
99 100
     try:
100
-        binding_obj = port_obj.DistributedPortBinding(
101
-            context,
102
-            port_id=port_id,
103
-            host=host,
104
-            router_id=router_id,
105
-            vif_type=portbindings.VIF_TYPE_UNBOUND,
106
-            vnic_type=portbindings.VNIC_NORMAL,
107
-            status=n_const.PORT_STATUS_DOWN)
108
-        binding_obj.create()
109
-        return binding_obj
110
-    except exceptions.NeutronDbObjectDuplicateEntry:
101
+        with db_api.context_manager.writer.using(context):
102
+            record = models.DistributedPortBinding(
103
+                port_id=port_id,
104
+                host=host,
105
+                router_id=router_id,
106
+                vif_type=portbindings.VIF_TYPE_UNBOUND,
107
+                vnic_type=portbindings.VNIC_NORMAL,
108
+                status=n_const.PORT_STATUS_DOWN)
109
+            context.session.add(record)
110
+            return record
111
+    except db_exc.DBDuplicateEntry:
111 112
         LOG.debug("Distributed Port %s already bound", port_id)
112
-        return port_obj.DistributedPortBinding.get_object(
113
-            context, port_id=port_id, host=host)
113
+        with db_api.context_manager.reader.using(context):
114
+            return (context.session.query(models.DistributedPortBinding).
115
+                    filter_by(port_id=port_id, host=host).one())
114 116
 
115 117
 
116 118
 def delete_distributed_port_binding_if_stale(context, binding):
117 119
     if not binding.router_id and binding.status == n_const.PORT_STATUS_DOWN:
118
-        LOG.debug("Distributed port: Deleting binding %s", binding)
119
-        binding.delete()
120
+        with db_api.context_manager.writer.using(context):
121
+            LOG.debug("Distributed port: Deleting binding %s", binding)
122
+            context.session.delete(binding)
120 123
 
121 124
 
122 125
 def get_port(context, port_id):
@@ -209,27 +212,29 @@ def make_port_dict_with_security_groups(port, sec_groups):
209 212
 
210 213
 
211 214
 def get_port_binding_host(context, port_id):
212
-    binding = port_obj.PortBinding.get_objects(
213
-        context, port_id=obj_utils.StringStarts(port_id))
214
-    if not binding:
215
+    try:
216
+        with db_api.context_manager.reader.using(context):
217
+            query = (context.session.query(models.PortBinding).
218
+                     filter(models.PortBinding.port_id.startswith(port_id)).
219
+                     one())
220
+    except exc.NoResultFound:
215 221
         LOG.debug("No binding found for port %(port_id)s",
216 222
                   {'port_id': port_id})
217 223
         return
218
-    if len(binding) > 1:
224
+    except exc.MultipleResultsFound:
219 225
         LOG.error("Multiple ports have port_id starting with %s",
220 226
                   port_id)
221 227
         return
222
-    return binding[0].host
228
+    return query.host
223 229
 
224 230
 
225 231
 @db_api.context_manager.reader
226 232
 def generate_distributed_port_status(context, port_id):
227 233
     # an OR'ed value of status assigned to parent port from the
228 234
     # distributedportbinding bucket
235
+    query = context.session.query(models.DistributedPortBinding)
229 236
     final_status = n_const.PORT_STATUS_BUILD
230
-    bindings = port_obj.DistributedPortBinding.get_objects(context,
231
-                                                           port_id=port_id)
232
-    for bind in bindings:
237
+    for bind in query.filter(models.DistributedPortBinding.port_id == port_id):
233 238
         if bind.status == n_const.PORT_STATUS_ACTIVE:
234 239
             return bind.status
235 240
         elif bind.status == n_const.PORT_STATUS_DOWN:
@@ -238,10 +243,10 @@ def generate_distributed_port_status(context, port_id):
238 243
 
239 244
 
240 245
 def get_distributed_port_binding_by_host(context, port_id, host):
241
-    bindings = port_obj.DistributedPortBinding.get_objects(
242
-        context, port_id=obj_utils.StringStarts(port_id), host=host)
243
-    binding = bindings.pop() if bindings else None
244
-
246
+    with db_api.context_manager.reader.using(context):
247
+        binding = (context.session.query(models.DistributedPortBinding).
248
+            filter(models.DistributedPortBinding.port_id.startswith(port_id),
249
+                   models.DistributedPortBinding.host == host).first())
245 250
     if not binding:
246 251
         LOG.debug("No binding for distributed port %(port_id)s with host "
247 252
                   "%(host)s", {'port_id': port_id, 'host': host})
@@ -249,8 +254,10 @@ def get_distributed_port_binding_by_host(context, port_id, host):
249 254
 
250 255
 
251 256
 def get_distributed_port_bindings(context, port_id):
252
-    bindings = port_obj.DistributedPortBinding.get_objects(
253
-        context, port_id=obj_utils.StringStarts(port_id))
257
+    with db_api.context_manager.reader.using(context):
258
+        bindings = (context.session.query(models.DistributedPortBinding).
259
+                    filter(models.DistributedPortBinding.port_id.startswith(
260
+                           port_id)).all())
254 261
     if not bindings:
255 262
         LOG.debug("No bindings for distributed port %s", port_id)
256 263
     return bindings

+ 5
- 2
neutron/plugins/ml2/driver_context.py View File

@@ -17,6 +17,7 @@ from neutron_lib.api.definitions import portbindings
17 17
 from neutron_lib import constants
18 18
 from neutron_lib.plugins.ml2 import api
19 19
 from oslo_log import log
20
+from oslo_serialization import jsonutils
20 21
 import sqlalchemy
21 22
 
22 23
 from neutron.db import segments_db
@@ -123,7 +124,9 @@ class PortContext(MechanismDriverContext, api.PortContext):
123 124
         else:
124 125
             self._network_context = NetworkContext(
125 126
                 plugin, plugin_context, network) if network else None
126
-        self._binding = binding
127
+        # NOTE(kevinbenton): InstanceSnapshot can go away once we are working
128
+        # with OVO objects instead of native SQLA objects.
129
+        self._binding = InstanceSnapshot(binding)
127 130
         self._binding_levels = [InstanceSnapshot(l)
128 131
                                 for l in (binding_levels or [])]
129 132
         self._segments_to_bind = None
@@ -292,7 +295,7 @@ class PortContext(MechanismDriverContext, api.PortContext):
292 295
         # TODO(rkukura) Verify binding allowed, segment in network
293 296
         self._new_bound_segment = segment_id
294 297
         self._binding.vif_type = vif_type
295
-        self._binding.vif_details = vif_details
298
+        self._binding.vif_details = jsonutils.dumps(vif_details)
296 299
         self._new_port_status = status
297 300
 
298 301
     def continue_binding(self, segment_id, next_segments_to_bind):

+ 1
- 1
neutron/plugins/ml2/models.py View File

@@ -125,6 +125,6 @@ class DistributedPortBinding(model_base.BASEV2):
125 125
         models_v2.Port,
126 126
         load_on_pending=True,
127 127
         backref=orm.backref("distributed_port_binding",
128
-                            lazy='joined',
128
+                            lazy='subquery',
129 129
                             cascade='delete'))
130 130
     revises_on_change = ('port', )

+ 20
- 52
neutron/plugins/ml2/plugin.py View File

@@ -83,7 +83,6 @@ from neutron.db import subnet_service_type_db_models as service_type_db
83 83
 from neutron.db import vlantransparent_db
84 84
 from neutron.extensions import providernet as provider
85 85
 from neutron.extensions import vlantransparent
86
-from neutron.objects import ports as obj_port
87 86
 from neutron.plugins.common import utils as p_utils
88 87
 from neutron.plugins.ml2.common import exceptions as ml2_exc
89 88
 from neutron.plugins.ml2 import db
@@ -317,6 +316,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
317 316
         port = mech_context.current
318 317
         port_id = port['id']
319 318
         changes = False
319
+
320 320
         host = const.ATTR_NOT_SPECIFIED
321 321
         if attrs and portbindings.HOST_ID in attrs:
322 322
             host = attrs.get(portbindings.HOST_ID) or ''
@@ -340,9 +340,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
340 340
 
341 341
         if profile not in (None, const.ATTR_NOT_SPECIFIED,
342 342
                            self._get_profile(binding)):
343
-            binding.profile = profile
344
-            if (len(jsonutils.dumps(binding.profile)) >
345
-                    models.BINDING_PROFILE_LEN):
343
+            binding.profile = jsonutils.dumps(profile)
344
+            if len(binding.profile) > models.BINDING_PROFILE_LEN:
346 345
                 msg = _("binding:profile value too large")
347 346
                 raise exc.InvalidInput(error_message=msg)
348 347
             changes = True
@@ -350,8 +349,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
350 349
         # Unbind the port if needed.
351 350
         if changes:
352 351
             binding.vif_type = portbindings.VIF_TYPE_UNBOUND
353
-            binding.vif_details = None
354
-            binding.update()
352
+            binding.vif_details = ''
355 353
             db.clear_binding_levels(plugin_context, port_id, original_host)
356 354
             mech_context._clear_binding_levels()
357 355
             port['status'] = const.PORT_STATUS_DOWN
@@ -361,14 +359,13 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
361 359
 
362 360
         if port['device_owner'] == const.DEVICE_OWNER_DVR_INTERFACE:
363 361
             binding.vif_type = portbindings.VIF_TYPE_UNBOUND
364
-            binding.vif_details = None
362
+            binding.vif_details = ''
365 363
             db.clear_binding_levels(plugin_context, port_id, original_host)
366 364
             mech_context._clear_binding_levels()
367 365
             binding.host = ''
368
-            binding.update()
369 366
 
370 367
         self._update_port_dict_binding(port, binding)
371
-        binding.update()
368
+        binding.persist_state_to_session(plugin_context.session)
372 369
         return changes
373 370
 
374 371
     @db_api.retry_db_errors
@@ -440,15 +437,12 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
440 437
         # transaction.
441 438
         port = orig_context.current
442 439
         orig_binding = orig_context._binding
443
-        profile = orig_binding.profile or {}
444
-        new_binding = obj_port.PortBinding(
445
-            orig_context._plugin_context,
446
-            port_id=orig_binding.port_id,
440
+        new_binding = models.PortBinding(
447 441
             host=orig_binding.host,
448 442
             vnic_type=orig_binding.vnic_type,
449
-            profile=profile,
443
+            profile=orig_binding.profile,
450 444
             vif_type=portbindings.VIF_TYPE_UNBOUND,
451
-            vif_details=None
445
+            vif_details=''
452 446
         )
453 447
         self._update_port_dict_binding(port, new_binding)
454 448
         new_context = driver_context.PortContext(
@@ -485,13 +479,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
485 479
             # mechanism driver update_port_*commit() calls.
486 480
             try:
487 481
                 port_db = self._get_port(plugin_context, port_id)
488
-                plugin_context.session.refresh(port_db)
489
-                # TODO(korzen) replace get_objects with port_obj.binding when
490
-                # Port OVO is integrated in _get_port
491
-                bindings = obj_port.PortBinding.get_objects(
492
-                    plugin_context, port_id=port_db.id,
493
-                    status=const.ACTIVE)
494
-                cur_binding = bindings.pop() if bindings else None
482
+                cur_binding = port_db.port_binding
495 483
             except exc.PortNotFound:
496 484
                 port_db, cur_binding = None, None
497 485
             if not port_db or not cur_binding:
@@ -558,10 +546,10 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
558 546
                                         cur_binding.host)
559 547
                 db.set_binding_levels(plugin_context,
560 548
                                       bind_context._binding_levels)
561
-                cur_context._binding = cur_binding
549
+                # refresh context with a snapshot of updated state
550
+                cur_context._binding = driver_context.InstanceSnapshot(
551
+                    cur_binding)
562 552
                 cur_context._binding_levels = bind_context._binding_levels
563
-                cur_binding.update()
564
-                plugin_context.session.refresh(port_db)
565 553
 
566 554
                 # Update PortContext's port dictionary to reflect the
567 555
                 # updated binding state.
@@ -612,10 +600,6 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
612 600
     def _get_vif_details(self, binding):
613 601
         if binding.vif_details:
614 602
             try:
615
-                # TODO(lujinluo): remove isinstance check once we switch to
616
-                # objects for all operations.
617
-                if isinstance(binding.vif_details, dict):
618
-                    return binding.vif_details
619 603
                 return jsonutils.loads(binding.vif_details)
620 604
             except Exception:
621 605
                 LOG.error("Serialized vif_details DB value '%(value)s' "
@@ -627,10 +611,6 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
627 611
     def _get_profile(self, binding):
628 612
         if binding.profile:
629 613
             try:
630
-                # TODO(lujinluo): remove isinstance check once we switch to
631
-                # objects for all operations.
632
-                if isinstance(binding.profile, dict):
633
-                    return binding.profile
634 614
                 return jsonutils.loads(binding.profile)
635 615
             except Exception:
636 616
                 LOG.error("Serialized profile DB value '%(value)s' for "
@@ -1314,12 +1294,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
1314 1294
                         original_port=original_port)
1315 1295
         with db_api.context_manager.writer.using(context):
1316 1296
             port_db = self._get_port(context, id)
1317
-            context.session.refresh(port_db)
1318
-            # TODO(korzen) replace _get_objects with port_obj.binding when
1319
-            # Port OVO is integrated in _get_port
1320
-            bindings = obj_port.PortBinding.get_objects(
1321
-                context, port_id=port_db.id)
1322
-            binding = bindings.pop() if bindings else None
1297
+            binding = port_db.port_binding
1323 1298
             if not binding:
1324 1299
                 raise exc.PortNotFound(port_id=id)
1325 1300
             mac_address_updated = self._check_mac_update_allowed(
@@ -1458,21 +1433,19 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
1458 1433
         binding = mech_context._binding
1459 1434
         port = mech_context.current
1460 1435
         port_id = port['id']
1461
-        clear_host = None
1462 1436
 
1463 1437
         if binding.vif_type != portbindings.VIF_TYPE_UNBOUND:
1464
-            binding.vif_details = None
1438
+            binding.vif_details = ''
1465 1439
             binding.vif_type = portbindings.VIF_TYPE_UNBOUND
1466 1440
             if binding.host:
1467 1441
                 db.clear_binding_levels(plugin_context, port_id, binding.host)
1468
-            clear_host = ''
1442
+            binding.host = ''
1469 1443
 
1470 1444
         self._update_port_dict_binding(port, binding)
1471
-        new_host = attrs and attrs.get(portbindings.HOST_ID) or clear_host
1445
+        binding.host = attrs and attrs.get(portbindings.HOST_ID)
1472 1446
         binding.router_id = attrs and attrs.get('device_id')
1473
-        if new_host:
1474
-            binding.host = new_host
1475
-        binding.update()
1447
+        # merge into session to reflect changes
1448
+        binding.persist_state_to_session(plugin_context.session)
1476 1449
 
1477 1450
     @utils.transaction_guard
1478 1451
     @db_api.retry_if_session_inactive()
@@ -1543,11 +1516,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
1543 1516
         with db_api.context_manager.writer.using(context):
1544 1517
             try:
1545 1518
                 port_db = self._get_port(context, id)
1546
-                # TODO(korzen) replace get_objects with port_obj.binding when
1547
-                # Port OVO is integrated in _get_port
1548
-                bindings = obj_port.PortBinding.get_objects(
1549
-                    context, port_id=port_db.id)
1550
-                binding = bindings.pop() if bindings else None
1519
+                binding = port_db.port_binding
1551 1520
             except exc.PortNotFound:
1552 1521
                 LOG.debug("The port '%s' was deleted", id)
1553 1522
                 return
@@ -1791,7 +1760,6 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
1791 1760
                     return
1792 1761
                 if binding.status != status:
1793 1762
                     binding.status = status
1794
-                    binding.update()
1795 1763
                     updated = True
1796 1764
 
1797 1765
         if (updated and

+ 1
- 1
neutron/tests/unit/objects/test_objects.py View File

@@ -62,7 +62,7 @@ object_data = {
62 62
     'NetworkPortSecurity': '1.0-b30802391a87945ee9c07582b4ff95e3',
63 63
     'NetworkSegment': '1.0-57b7f2960971e3b95ded20cbc59244a8',
64 64
     'Port': '1.1-5bf48d12a7bf7f5b7a319e8003b437a5',
65
-    'PortBinding': '1.0-0ad9727c4e72d609d5b4f70bcd3bc727',
65
+    'PortBinding': '1.0-3306deeaa6deb01e33af06777d48d578',
66 66
     'PortBindingLevel': '1.0-de66a4c61a083b8f34319fa9dde5b060',
67 67
     'PortDataPlaneStatus': '1.0-25be74bda46c749653a10357676c0ab2',
68 68
     'PortDNS': '1.1-c5ca2dc172bdd5fafee3fc986d1d7023',

+ 61
- 58
neutron/tests/unit/plugins/ml2/test_db.py View File

@@ -23,6 +23,7 @@ from neutron_lib import context
23 23
 from neutron_lib.plugins.ml2 import api
24 24
 from oslo_utils import uuidutils
25 25
 from sqlalchemy.orm import exc
26
+from sqlalchemy.orm import query
26 27
 
27 28
 from neutron.db import api as db_api
28 29
 from neutron.db import db_base_plugin_v2
@@ -32,6 +33,7 @@ from neutron.db import segments_db
32 33
 from neutron.objects import network as network_obj
33 34
 from neutron.objects import ports as port_obj
34 35
 from neutron.plugins.ml2 import db as ml2_db
36
+from neutron.plugins.ml2 import models
35 37
 from neutron.tests.unit import testlib_api
36 38
 
37 39
 
@@ -62,8 +64,10 @@ class Ml2DBTestCase(testlib_api.SqlTestCase):
62 64
         return port
63 65
 
64 66
     def _setup_neutron_portbinding(self, port_id, vif_type, host):
65
-        port_obj.PortBinding(
66
-            self.ctx, port_id=port_id, vif_type=vif_type, host=host).create()
67
+        with db_api.context_manager.writer.using(self.ctx):
68
+            self.ctx.session.add(models.PortBinding(port_id=port_id,
69
+                                                    vif_type=vif_type,
70
+                                                    host=host))
67 71
 
68 72
     @staticmethod
69 73
     def _sort_segments(segments):
@@ -314,45 +318,44 @@ class Ml2DvrDBTestCase(testlib_api.SqlTestCase):
314 318
 
315 319
     def _setup_distributed_binding(self, network_id,
316 320
                                    port_id, router_id, host_id):
317
-        binding_obj = port_obj.DistributedPortBinding(
318
-            self.ctx,
319
-            port_id=port_id,
320
-            host=host_id,
321
-            router_id=router_id,
322
-            vif_type=portbindings.VIF_TYPE_UNBOUND,
323
-            vnic_type=portbindings.VNIC_NORMAL,
324
-            status='DOWN')
325
-        binding_obj.create()
326
-        return binding_obj
321
+        with db_api.context_manager.writer.using(self.ctx):
322
+            record = models.DistributedPortBinding(
323
+                port_id=port_id,
324
+                host=host_id,
325
+                router_id=router_id,
326
+                vif_type=portbindings.VIF_TYPE_UNBOUND,
327
+                vnic_type=portbindings.VNIC_NORMAL,
328
+                status='DOWN')
329
+            self.ctx.session.add(record)
330
+            return record
327 331
 
328 332
     def test_ensure_distributed_port_binding_deals_with_db_duplicate(self):
329 333
         network_id = uuidutils.generate_uuid()
330 334
         port_id = uuidutils.generate_uuid()
331
-        router_id = uuidutils.generate_uuid()
332
-        host_id = uuidutils.generate_uuid()
335
+        router_id = 'foo_router_id'
336
+        host_id = 'foo_host_id'
333 337
         self._setup_neutron_network(network_id, [port_id])
334
-        dpb = self._setup_distributed_binding(network_id, port_id,
335
-                                              router_id, host_id)
336
-        with mock.patch.object(port_obj.DistributedPortBinding,
337
-                'get_object') as get_object:
338
-            get_object.side_effect = [None, dpb]
339
-            binding = ml2_db.ensure_distributed_port_binding(
340
-                self.ctx, port_id, host_id, router_id)
341
-        self.assertTrue(get_object.called)
338
+        self._setup_distributed_binding(network_id, port_id,
339
+                                        router_id, host_id)
340
+        with mock.patch.object(query.Query, 'first') as query_first:
341
+            query_first.return_value = []
342
+            with mock.patch.object(ml2_db.LOG, 'debug') as log_trace:
343
+                binding = ml2_db.ensure_distributed_port_binding(
344
+                    self.ctx, port_id, host_id, router_id)
345
+        self.assertTrue(query_first.called)
346
+        self.assertTrue(log_trace.called)
342 347
         self.assertEqual(port_id, binding.port_id)
343 348
 
344 349
     def test_ensure_distributed_port_binding(self):
345 350
         network_id = uuidutils.generate_uuid()
346
-        expected_port_id = uuidutils.generate_uuid()
347
-        self._setup_neutron_network(network_id, [expected_port_id])
351
+        port_id = uuidutils.generate_uuid()
352
+        self._setup_neutron_network(network_id, [port_id])
348 353
         router = self._setup_neutron_router()
349 354
         ml2_db.ensure_distributed_port_binding(
350
-            self.ctx, expected_port_id, 'foo_host', router.id)
351
-        actual_objs = port_obj.DistributedPortBinding.get_objects(
352
-            self.ctx, port_id=expected_port_id)
353
-        self.assertEqual(1, len(actual_objs))
354
-        actual_obj = actual_objs.pop()
355
-        self.assertEqual(expected_port_id, actual_obj.port_id)
355
+            self.ctx, port_id, 'foo_host', router.id)
356
+        expected = (self.ctx.session.query(models.DistributedPortBinding).
357
+                    filter_by(port_id=port_id).one())
358
+        self.assertEqual(port_id, expected.port_id)
356 359
 
357 360
     def test_ensure_distributed_port_binding_multiple_bindings(self):
358 361
         network_id = uuidutils.generate_uuid()
@@ -363,9 +366,9 @@ class Ml2DvrDBTestCase(testlib_api.SqlTestCase):
363 366
             self.ctx, port_id, 'foo_host_1', router.id)
364 367
         ml2_db.ensure_distributed_port_binding(
365 368
             self.ctx, port_id, 'foo_host_2', router.id)
366
-        count_objs = port_obj.DistributedPortBinding.count(
367
-            self.ctx, port_id=port_id)
368
-        self.assertEqual(2, count_objs)
369
+        bindings = (self.ctx.session.query(models.DistributedPortBinding).
370
+                    filter_by(port_id=port_id).all())
371
+        self.assertEqual(2, len(bindings))
369 372
 
370 373
     def test_delete_distributed_port_binding_if_stale(self):
371 374
         network_id = uuidutils.generate_uuid()
@@ -374,23 +377,21 @@ class Ml2DvrDBTestCase(testlib_api.SqlTestCase):
374 377
         binding = self._setup_distributed_binding(
375 378
             network_id, port_id, None, 'foo_host_id')
376 379
 
377
-        ml2_db.delete_distributed_port_binding_if_stale(self.ctx, binding)
378
-
379
-        obj_exists = port_obj.DistributedPortBinding.objects_exist(
380
-            self.ctx, port_id=binding.port_id)
381
-        self.assertFalse(obj_exists)
380
+        ml2_db.delete_distributed_port_binding_if_stale(self.ctx,
381
+                                                        binding)
382
+        count = (self.ctx.session.query(models.DistributedPortBinding).
383
+            filter_by(port_id=binding.port_id).count())
384
+        self.assertFalse(count)
382 385
 
383 386
     def test_get_distributed_port_binding_by_host_not_found(self):
384
-        port_id = uuidutils.generate_uuid()
385
-        host_id = uuidutils.generate_uuid()
386 387
         port = ml2_db.get_distributed_port_binding_by_host(
387
-            self.ctx, port_id, host_id)
388
+            self.ctx, 'foo_port_id', 'foo_host_id')
388 389
         self.assertIsNone(port)
389 390
 
390 391
     def test_get_distributed_port_bindings_not_found(self):
391 392
         port = ml2_db.get_distributed_port_bindings(self.ctx,
392
-                                                    uuidutils.generate_uuid())
393
-        self.assertEqual(0, len(port))
393
+                                                    'foo_port_id')
394
+        self.assertFalse(len(port))
394 395
 
395 396
     def test_get_distributed_port_bindings(self):
396 397
         network_id = uuidutils.generate_uuid()
@@ -411,9 +412,8 @@ class Ml2DvrDBTestCase(testlib_api.SqlTestCase):
411 412
         network_obj.Network(self.ctx, id=network_id).create()
412 413
         with db_api.context_manager.writer.using(self.ctx):
413 414
             device_owner = constants.DEVICE_OWNER_DVR_INTERFACE
414
-            port_id = uuidutils.generate_uuid()
415 415
             port = models_v2.Port(
416
-                id=port_id,
416
+                id='port_id',
417 417
                 network_id=network_id,
418 418
                 mac_address='00:11:22:33:44:55',
419 419
                 admin_state_up=True,
@@ -421,22 +421,25 @@ class Ml2DvrDBTestCase(testlib_api.SqlTestCase):
421 421
                 device_id='device_id',
422 422
                 device_owner=device_owner)
423 423
             self.ctx.session.add(port)
424
-        binding_kwarg = {
425
-            'port_id': port_id,
426
-            'host': 'host',
427
-            'vif_type': portbindings.VIF_TYPE_UNBOUND,
428
-            'vnic_type': portbindings.VNIC_NORMAL,
429
-            'router_id': 'router_id',
430
-            'status': constants.PORT_STATUS_DOWN
431
-        }
432
-        port_obj.DistributedPortBinding(self.ctx, **binding_kwarg).create()
433
-        binding_kwarg['host'] = 'another-host'
434
-        port_obj.DistributedPortBinding(self.ctx, **binding_kwarg).create()
424
+            binding_kwarg = {
425
+                'port_id': 'port_id',
426
+                'host': 'host',
427
+                'vif_type': portbindings.VIF_TYPE_UNBOUND,
428
+                'vnic_type': portbindings.VNIC_NORMAL,
429
+                'router_id': 'router_id',
430
+                'status': constants.PORT_STATUS_DOWN
431
+            }
432
+            self.ctx.session.add(models.DistributedPortBinding(
433
+                **binding_kwarg))
434
+            binding_kwarg['host'] = 'another-host'
435
+            self.ctx.session.add(models.DistributedPortBinding(
436
+                **binding_kwarg))
435 437
         with warnings.catch_warnings(record=True) as warning_list:
436 438
             with db_api.context_manager.writer.using(self.ctx):
437 439
                 self.ctx.session.delete(port)
438 440
             self.assertEqual(
439 441
                 [], warning_list,
440 442
                 'Warnings: %s' % ';'.join([str(w) for w in warning_list]))
441
-        bindings = ml2_db.get_distributed_port_bindings(self.ctx, port_id)
442
-        self.assertEqual(0, len(bindings))
443
+        ports = ml2_db.get_distributed_port_bindings(self.ctx,
444
+                                                     'port_id')
445
+        self.assertEqual(0, len(ports))

+ 50
- 74
neutron/tests/unit/plugins/ml2/test_plugin.py View File

@@ -47,7 +47,6 @@ from neutron.db import provisioning_blocks
47 47
 from neutron.db import segments_db
48 48
 from neutron.extensions import multiprovidernet as mpnet
49 49
 from neutron.objects import base as base_obj
50
-from neutron.objects import ports as obj_port
51 50
 from neutron.objects import router as l3_obj
52 51
 from neutron.plugins.ml2.common import exceptions as ml2_exc
53 52
 from neutron.plugins.ml2 import db as ml2_db
@@ -1692,10 +1691,9 @@ class TestMl2PortBinding(Ml2PluginV2TestCase,
1692 1691
         # create a port and delete it so we have an expired mechanism context
1693 1692
         with self.port() as port:
1694 1693
             plugin = directory.get_plugin()
1695
-            binding = obj_port.PortBinding.get_object(
1696
-                self.context, port_id=port['port']['id'], host='')
1697
-            binding.host = 'test'
1698
-            binding.update()
1694
+            binding = plugin._get_port(self.context,
1695
+                                       port['port']['id']).port_binding
1696
+            binding['host'] = 'test'
1699 1697
             mech_context = driver_context.PortContext(
1700 1698
                 plugin, self.context, port['port'],
1701 1699
                 plugin.get_network(self.context, port['port']['network_id']),
@@ -1714,11 +1712,10 @@ class TestMl2PortBinding(Ml2PluginV2TestCase,
1714 1712
     def _create_port_and_bound_context(self, port_vif_type, bound_vif_type):
1715 1713
         with self.port() as port:
1716 1714
             plugin = directory.get_plugin()
1717
-            binding = obj_port.PortBinding.get_object(
1718
-                self.context, port_id=port['port']['id'], host='')
1719
-            binding.host = 'fake_host'
1715
+            binding = plugin._get_port(
1716
+                self.context, port['port']['id']).port_binding
1717
+            binding['host'] = 'fake_host'
1720 1718
             binding['vif_type'] = port_vif_type
1721
-            binding.update()
1722 1719
             # Generates port context to be used before the bind.
1723 1720
             port_context = driver_context.PortContext(
1724 1721
                 plugin, self.context, port['port'],
@@ -1830,10 +1827,10 @@ class TestMl2PortBinding(Ml2PluginV2TestCase,
1830 1827
     def test_update_port_binding_host_id_none(self):
1831 1828
         with self.port() as port:
1832 1829
             plugin = directory.get_plugin()
1833
-            binding = obj_port.PortBinding.get_object(
1834
-                self.context, port_id=port['port']['id'], host='')
1835
-            binding.host = 'test'
1836
-            binding.update()
1830
+            binding = plugin._get_port(
1831
+                self.context, port['port']['id']).port_binding
1832
+            with self.context.session.begin(subtransactions=True):
1833
+                binding.host = 'test'
1837 1834
             mech_context = driver_context.PortContext(
1838 1835
                 plugin, self.context, port['port'],
1839 1836
                 plugin.get_network(self.context, port['port']['network_id']),
@@ -1844,18 +1841,15 @@ class TestMl2PortBinding(Ml2PluginV2TestCase,
1844 1841
             self.assertEqual('test', binding.host)
1845 1842
             with self.context.session.begin(subtransactions=True):
1846 1843
                 plugin._process_port_binding(mech_context, attrs)
1847
-            updated_binding = obj_port.PortBinding.get_objects(self.context,
1848
-                port_id=port['port']['id']).pop()
1849 1844
             self.assertTrue(update_mock.mock_calls)
1850
-            self.assertEqual('', updated_binding.host)
1845
+            self.assertEqual('', binding.host)
1851 1846
 
1852 1847
     def test_update_port_binding_host_id_not_changed(self):
1853 1848
         with self.port() as port:
1854 1849
             plugin = directory.get_plugin()
1855
-            binding = obj_port.PortBinding.get_object(
1856
-                self.context, port_id=port['port']['id'], host='')
1857
-            binding.host = 'test'
1858
-            binding.update()
1850
+            binding = plugin._get_port(
1851
+                self.context, port['port']['id']).port_binding
1852
+            binding['host'] = 'test'
1859 1853
             mech_context = driver_context.PortContext(
1860 1854
                 plugin, self.context, port['port'],
1861 1855
                 plugin.get_network(self.context, port['port']['network_id']),
@@ -1868,34 +1862,30 @@ class TestMl2PortBinding(Ml2PluginV2TestCase,
1868 1862
             self.assertEqual('test', binding.host)
1869 1863
 
1870 1864
     def test_process_distributed_port_binding_update_router_id(self):
1871
-        with self.port() as port:
1872
-            host_id = 'host'
1873
-            ctxt = context.get_admin_context()
1874
-            binding_obj = obj_port.DistributedPortBinding(
1875
-                ctxt,
1876
-                port_id=port['port']['id'],
1877
-                host=host_id,
1878
-                profile={},
1879
-                router_id='old_router_id',
1880
-                vif_type=portbindings.VIF_TYPE_OVS,
1881
-                vnic_type=portbindings.VNIC_NORMAL,
1882
-                status=constants.PORT_STATUS_DOWN)
1883
-            binding_obj.create()
1884
-            plugin = directory.get_plugin()
1885
-            mock_network = {'id': 'net_id'}
1886
-            mock_port = {'id': 'port_id'}
1887
-            new_router_id = 'new_router'
1888
-            attrs = {'device_id': new_router_id, portbindings.HOST_ID: host_id}
1889
-            with mock.patch.object(plugin, '_update_port_dict_binding'):
1890
-                with mock.patch.object(segments_db, 'get_network_segments',
1891
-                                       return_value=[]):
1892
-                    mech_context = driver_context.PortContext(
1893
-                        self, ctxt, mock_port, mock_network, binding_obj, None)
1894
-                    plugin._process_distributed_port_binding(mech_context,
1895
-                                                             ctxt, attrs)
1896
-                    self.assertEqual(new_router_id,
1897
-                                     mech_context._binding.router_id)
1898
-                    self.assertEqual(host_id, mech_context._binding.host)
1865
+        host_id = 'host'
1866
+        binding = models.DistributedPortBinding(
1867
+                            port_id='port_id',
1868
+                            host=host_id,
1869
+                            router_id='old_router_id',
1870
+                            vif_type=portbindings.VIF_TYPE_OVS,
1871
+                            vnic_type=portbindings.VNIC_NORMAL,
1872
+                            status=constants.PORT_STATUS_DOWN)
1873
+        plugin = directory.get_plugin()
1874
+        mock_network = {'id': 'net_id'}
1875
+        mock_port = {'id': 'port_id'}
1876
+        ctxt = context.get_admin_context()
1877
+        new_router_id = 'new_router'
1878
+        attrs = {'device_id': new_router_id, portbindings.HOST_ID: host_id}
1879
+        with mock.patch.object(plugin, '_update_port_dict_binding'):
1880
+            with mock.patch.object(segments_db, 'get_network_segments',
1881
+                                   return_value=[]):
1882
+                mech_context = driver_context.PortContext(
1883
+                    self, ctxt, mock_port, mock_network, binding, None)
1884
+                plugin._process_distributed_port_binding(mech_context,
1885
+                                                         ctxt, attrs)
1886
+                self.assertEqual(new_router_id,
1887
+                                 mech_context._binding.router_id)
1888
+                self.assertEqual(host_id, mech_context._binding.host)
1899 1889
 
1900 1890
     def test_update_distributed_port_binding_on_concurrent_port_delete(self):
1901 1891
         plugin = directory.get_plugin()
@@ -1926,20 +1916,9 @@ class TestMl2PortBinding(Ml2PluginV2TestCase,
1926 1916
     def test__bind_port_original_port_set(self):
1927 1917
         plugin = directory.get_plugin()
1928 1918
         plugin.mechanism_manager = mock.Mock()
1929
-        mock_port = {'id': uuidutils.generate_uuid()}
1919
+        mock_port = {'id': 'port_id'}
1930 1920
         context = mock.Mock()
1931
-        binding_obj = obj_port.DistributedPortBinding(
1932
-            mock.MagicMock(),
1933
-            port_id=mock_port['id'],
1934
-            host='vm_host',
1935
-            profile={},
1936
-            router_id='old_router_id',
1937
-            vif_type='',
1938
-            vnic_type=portbindings.VNIC_NORMAL,
1939
-            status=constants.PORT_STATUS_DOWN)
1940
-        binding_obj.create()
1941 1921
         context.network.current = {'id': 'net_id'}
1942
-        context._binding = binding_obj
1943 1922
         context.original = mock_port
1944 1923
         with mock.patch.object(plugin, '_update_port_dict_binding'), \
1945 1924
             mock.patch.object(segments_db, 'get_network_segments',
@@ -2615,15 +2594,13 @@ class TestFaultyMechansimDriver(Ml2PluginV2FaultyDriverTestCase):
2615 2594
     def test_update_distributed_router_interface_port(self):
2616 2595
         """Test validate distributed router interface update succeeds."""
2617 2596
         host_id = 'host'
2618
-        binding_obj = obj_port.DistributedPortBinding(
2619
-            mock.MagicMock(),
2620
-            port_id=uuidutils.generate_uuid(),
2621
-            host=host_id,
2622
-            router_id='old_router_id',
2623
-            vif_type=portbindings.VIF_TYPE_OVS,
2624
-            vnic_type=portbindings.VNIC_NORMAL,
2625
-            status=constants.PORT_STATUS_DOWN)
2626
-        binding_obj.create()
2597
+        binding = models.DistributedPortBinding(
2598
+                            port_id='port_id',
2599
+                            host=host_id,
2600
+                            router_id='old_router_id',
2601
+                            vif_type=portbindings.VIF_TYPE_OVS,
2602
+                            vnic_type=portbindings.VNIC_NORMAL,
2603
+                            status=constants.PORT_STATUS_DOWN)
2627 2604
         with mock.patch.object(
2628 2605
             mech_test.TestMechanismDriver,
2629 2606
             'update_port_postcommit',
@@ -2633,7 +2610,7 @@ class TestFaultyMechansimDriver(Ml2PluginV2FaultyDriverTestCase):
2633 2610
                     'update_port_precommit') as port_pre,\
2634 2611
                 mock.patch.object(
2635 2612
                     ml2_db, 'get_distributed_port_bindings') as dist_bindings:
2636
-                dist_bindings.return_value = [binding_obj]
2613
+                dist_bindings.return_value = [binding]
2637 2614
                 port_pre.return_value = True
2638 2615
                 with self.network() as network:
2639 2616
                     with self.subnet(network=network) as subnet:
@@ -2856,10 +2833,9 @@ class TestML2Segments(Ml2PluginV2TestCase):
2856 2833
             # add writer here to make sure that the following operations are
2857 2834
             # performed in the same session
2858 2835
             with db_api.context_manager.writer.using(self.context):
2859
-                binding = obj_port.PortBinding.get_object(
2860
-                    self.context, port_id=port['port']['id'], host='')
2861
-                binding.host = 'host-ovs-no_filter'
2862
-                binding.update()
2836
+                binding = plugin._get_port(
2837
+                    self.context, port['port']['id']).port_binding
2838
+                binding['host'] = 'host-ovs-no_filter'
2863 2839
                 mech_context = driver_context.PortContext(
2864 2840
                     plugin, self.context, port['port'],
2865 2841
                     plugin.get_network(self.context,

+ 13
- 6
neutron/tests/unit/plugins/ml2/test_port_binding.py View File

@@ -19,10 +19,11 @@ from neutron_lib import constants as const
19 19
 from neutron_lib import context
20 20
 from neutron_lib.plugins import directory
21 21
 from oslo_config import cfg
22
+from oslo_serialization import jsonutils
22 23
 
23 24
 from neutron.conf.plugins.ml2.drivers import driver_type
24
-from neutron.objects import ports as obj_port
25 25
 from neutron.plugins.ml2 import driver_context
26
+from neutron.plugins.ml2 import models as ml2_models
26 27
 from neutron.tests.unit.db import test_db_base_plugin_v2 as test_plugin
27 28
 
28 29
 
@@ -110,8 +111,10 @@ class PortBindingTestCase(test_plugin.NeutronDbPluginV2TestCase):
110 111
         ctx = context.get_admin_context()
111 112
         with self.port(name='name') as port:
112 113
             # emulating concurrent binding deletion
113
-            obj_port.PortBinding.delete_objects(
114
-                ctx, port_id=port['port']['id'])
114
+            with ctx.session.begin():
115
+                for item in (ctx.session.query(ml2_models.PortBinding).
116
+                             filter_by(port_id=port['port']['id'])):
117
+                    ctx.session.delete(item)
115 118
             self.assertIsNone(
116 119
                 self.plugin.get_bound_port_context(ctx, port['port']['id']))
117 120
 
@@ -188,9 +191,13 @@ class PortBindingTestCase(test_plugin.NeutronDbPluginV2TestCase):
188 191
             attrs['binding:host_id'] = 'host2'
189 192
             updated_port = attrs.copy()
190 193
             network = {'id': attrs['network_id']}
191
-            binding = obj_port.PortBinding.get_object(
192
-                ctx, port_id=original_port['id'],
193
-                host=original_port['binding:host_id'])
194
+            binding = ml2_models.PortBinding(
195
+                port_id=original_port['id'],
196
+                host=original_port['binding:host_id'],
197
+                vnic_type=original_port['binding:vnic_type'],
198
+                profile=jsonutils.dumps(original_port['binding:profile']),
199
+                vif_type=original_port['binding:vif_type'],
200
+                vif_details=original_port['binding:vif_details'])
194 201
             levels = []
195 202
             mech_context = driver_context.PortContext(
196 203
                 plugin, ctx, updated_port, network, binding, levels,

Loading…
Cancel
Save