summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIhar Hrachyshka <ihrachys@redhat.com>2018-01-23 17:46:40 +0000
committerMiguel Lavalle <miguel.lavalle@huawei.com>2018-01-27 18:19:20 -0600
commit906eda44d2c230be99fc5c61daa0f359ab46a3ad (patch)
treec635e1fabf82daa91d8710832c17927fd70c353e
parent03b1cca794592a4899ccb0a16474f9681f203e29 (diff)
Revert "Integration of (Distributed) Port Binding OVO"
This reverts commit febeaf5d4016157d0cca41023e64b91e550453e8. 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
Notes
Notes (review): Verified+1: Arista CI <arista-openstack-test@aristanetworks.com> Code-Review+2: Miguel Lavalle <miguel.lavalle@huawei.com> Workflow+1: Miguel Lavalle <miguel.lavalle@huawei.com> Verified+2: Zuul Submitted-by: Zuul Submitted-at: Thu, 01 Feb 2018 06:41:47 +0000 Reviewed-on: https://review.openstack.org/536913 Project: openstack/neutron Branch: refs/heads/master
-rw-r--r--neutron/objects/base.py16
-rw-r--r--neutron/objects/ports.py18
-rw-r--r--neutron/plugins/ml2/db.py85
-rw-r--r--neutron/plugins/ml2/driver_context.py7
-rw-r--r--neutron/plugins/ml2/models.py2
-rw-r--r--neutron/plugins/ml2/plugin.py72
-rw-r--r--neutron/tests/unit/objects/test_objects.py2
-rw-r--r--neutron/tests/unit/plugins/ml2/test_db.py119
-rw-r--r--neutron/tests/unit/plugins/ml2/test_plugin.py124
-rw-r--r--neutron/tests/unit/plugins/ml2/test_port_binding.py19
10 files changed, 200 insertions, 264 deletions
diff --git a/neutron/objects/base.py b/neutron/objects/base.py
index fbd63ef..844b11d 100644
--- a/neutron/objects/base.py
+++ b/neutron/objects/base.py
@@ -27,7 +27,6 @@ from oslo_versionedobjects import base as obj_base
27from oslo_versionedobjects import exception as obj_exception 27from oslo_versionedobjects import exception as obj_exception
28from oslo_versionedobjects import fields as obj_fields 28from oslo_versionedobjects import fields as obj_fields
29import six 29import six
30from sqlalchemy import exc as sql_exc
31 30
32from neutron._i18n import _ 31from neutron._i18n import _
33from neutron.db import api as db_api 32from neutron.db import api as db_api
@@ -319,11 +318,7 @@ def _detach_db_obj(func):
319 # TODO(ihrachys) consider refreshing just changed attributes 318 # TODO(ihrachys) consider refreshing just changed attributes
320 self.obj_context.session.refresh(self.db_obj) 319 self.obj_context.session.refresh(self.db_obj)
321 # detach the model so that consequent fetches don't reuse it 320 # detach the model so that consequent fetches don't reuse it
322 try: 321 self.obj_context.session.expunge(self.db_obj)
323 self.obj_context.session.expunge(self.db_obj)
324 except sql_exc.InvalidRequestError:
325 # already detached
326 pass
327 return res 322 return res
328 return decorator 323 return decorator
329 324
@@ -350,8 +345,6 @@ class DeclarativeObject(abc.ABCMeta):
350 if key in cls.fields or key in cls.obj_extra_fields: 345 if key in cls.fields or key in cls.obj_extra_fields:
351 fields_no_update_set.add(key) 346 fields_no_update_set.add(key)
352 cls.fields_no_update = list(fields_no_update_set) 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 model = getattr(cls, 'db_model', None) 349 model = getattr(cls, 'db_model', None)
357 if model: 350 if model:
@@ -502,12 +495,7 @@ class NeutronDbObject(NeutronObject):
502 obj = cls(context) 495 obj = cls(context)
503 obj.from_db_object(db_obj) 496 obj.from_db_object(db_obj)
504 # detach the model so that consequent fetches don't reuse it 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. 498 context.session.expunge(obj.db_obj)
506 try:
507 context.session.expunge(obj.db_obj)
508 except sql_exc.InvalidRequestError:
509 # already detached
510 pass
511 return obj 499 return obj
512 500
513 def obj_load_attr(self, attrname): 501 def obj_load_attr(self, attrname):
diff --git a/neutron/objects/ports.py b/neutron/objects/ports.py
index 117d788..a62f305 100644
--- a/neutron/objects/ports.py
+++ b/neutron/objects/ports.py
@@ -36,22 +36,6 @@ class PortBindingBase(base.NeutronDbObject):
36 'Port': {'port_id': 'id'}, 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 @classmethod 39 @classmethod
56 def modify_fields_to_db(cls, fields): 40 def modify_fields_to_db(cls, fields):
57 result = super(PortBindingBase, cls).modify_fields_to_db(fields) 41 result = super(PortBindingBase, cls).modify_fields_to_db(fields)
@@ -85,7 +69,7 @@ class PortBinding(PortBindingBase):
85 69
86 fields = { 70 fields = {
87 'port_id': common_types.UUIDField(), 71 'port_id': common_types.UUIDField(),
88 'host': obj_fields.StringField(default=''), 72 'host': obj_fields.StringField(),
89 'profile': common_types.DictOfMiscValuesField(), 73 'profile': common_types.DictOfMiscValuesField(),
90 'vif_type': obj_fields.StringField(), 74 'vif_type': obj_fields.StringField(),
91 'vif_details': common_types.DictOfMiscValuesField(nullable=True), 75 'vif_details': common_types.DictOfMiscValuesField(nullable=True),
diff --git a/neutron/plugins/ml2/db.py b/neutron/plugins/ml2/db.py
index aa4e574..7694efb 100644
--- a/neutron/plugins/ml2/db.py
+++ b/neutron/plugins/ml2/db.py
@@ -18,8 +18,8 @@ from neutron_lib.callbacks import events
18from neutron_lib.callbacks import registry 18from neutron_lib.callbacks import registry
19from neutron_lib.callbacks import resources 19from neutron_lib.callbacks import resources
20from neutron_lib import constants as n_const 20from neutron_lib import constants as n_const
21from neutron_lib.objects import exceptions
22from neutron_lib.plugins import directory 21from neutron_lib.plugins import directory
22from oslo_db import exception as db_exc
23from oslo_log import log 23from oslo_log import log
24from oslo_utils import uuidutils 24from oslo_utils import uuidutils
25import six 25import six
@@ -31,7 +31,6 @@ from neutron.db import api as db_api
31from neutron.db.models import securitygroup as sg_models 31from neutron.db.models import securitygroup as sg_models
32from neutron.db import models_v2 32from neutron.db import models_v2
33from neutron.objects import ports as port_obj 33from neutron.objects import ports as port_obj
34from neutron.objects import utils as obj_utils
35from neutron.plugins.ml2 import models 34from neutron.plugins.ml2 import models
36from neutron.services.segments import exceptions as seg_exc 35from neutron.services.segments import exceptions as seg_exc
37 36
@@ -43,10 +42,11 @@ MAX_PORTS_PER_QUERY = 500
43 42
44@db_api.context_manager.writer 43@db_api.context_manager.writer
45def add_port_binding(context, port_id): 44def add_port_binding(context, port_id):
46 binding = port_obj.PortBinding( 45 record = models.PortBinding(
47 context, port_id=port_id, vif_type=portbindings.VIF_TYPE_UNBOUND) 46 port_id=port_id,
48 binding.create() 47 vif_type=portbindings.VIF_TYPE_UNBOUND)
49 return binding 48 context.session.add(record)
49 return record
50 50
51 51
52@db_api.context_manager.writer 52@db_api.context_manager.writer
@@ -91,32 +91,35 @@ def clear_binding_levels(context, port_id, host):
91 91
92 92
93def ensure_distributed_port_binding(context, port_id, host, router_id=None): 93def ensure_distributed_port_binding(context, port_id, host, router_id=None):
94 binding_obj = port_obj.DistributedPortBinding.get_object( 94 with db_api.context_manager.reader.using(context):
95 context, port_id=port_id, host=host) 95 record = (context.session.query(models.DistributedPortBinding).
96 if binding_obj: 96 filter_by(port_id=port_id, host=host).first())
97 return binding_obj 97 if record:
98 return record
98 99
99 try: 100 try:
100 binding_obj = port_obj.DistributedPortBinding( 101 with db_api.context_manager.writer.using(context):
101 context, 102 record = models.DistributedPortBinding(
102 port_id=port_id, 103 port_id=port_id,
103 host=host, 104 host=host,
104 router_id=router_id, 105 router_id=router_id,
105 vif_type=portbindings.VIF_TYPE_UNBOUND, 106 vif_type=portbindings.VIF_TYPE_UNBOUND,
106 vnic_type=portbindings.VNIC_NORMAL, 107 vnic_type=portbindings.VNIC_NORMAL,
107 status=n_const.PORT_STATUS_DOWN) 108 status=n_const.PORT_STATUS_DOWN)
108 binding_obj.create() 109 context.session.add(record)
109 return binding_obj 110 return record
110 except exceptions.NeutronDbObjectDuplicateEntry: 111 except db_exc.DBDuplicateEntry:
111 LOG.debug("Distributed Port %s already bound", port_id) 112 LOG.debug("Distributed Port %s already bound", port_id)
112 return port_obj.DistributedPortBinding.get_object( 113 with db_api.context_manager.reader.using(context):
113 context, port_id=port_id, host=host) 114 return (context.session.query(models.DistributedPortBinding).
115 filter_by(port_id=port_id, host=host).one())
114 116
115 117
116def delete_distributed_port_binding_if_stale(context, binding): 118def delete_distributed_port_binding_if_stale(context, binding):
117 if not binding.router_id and binding.status == n_const.PORT_STATUS_DOWN: 119 if not binding.router_id and binding.status == n_const.PORT_STATUS_DOWN:
118 LOG.debug("Distributed port: Deleting binding %s", binding) 120 with db_api.context_manager.writer.using(context):
119 binding.delete() 121 LOG.debug("Distributed port: Deleting binding %s", binding)
122 context.session.delete(binding)
120 123
121 124
122def get_port(context, port_id): 125def get_port(context, port_id):
@@ -209,27 +212,29 @@ def make_port_dict_with_security_groups(port, sec_groups):
209 212
210 213
211def get_port_binding_host(context, port_id): 214def get_port_binding_host(context, port_id):
212 binding = port_obj.PortBinding.get_objects( 215 try:
213 context, port_id=obj_utils.StringStarts(port_id)) 216 with db_api.context_manager.reader.using(context):
214 if not binding: 217 query = (context.session.query(models.PortBinding).
218 filter(models.PortBinding.port_id.startswith(port_id)).
219 one())
220 except exc.NoResultFound:
215 LOG.debug("No binding found for port %(port_id)s", 221 LOG.debug("No binding found for port %(port_id)s",
216 {'port_id': port_id}) 222 {'port_id': port_id})
217 return 223 return
218 if len(binding) > 1: 224 except exc.MultipleResultsFound:
219 LOG.error("Multiple ports have port_id starting with %s", 225 LOG.error("Multiple ports have port_id starting with %s",
220 port_id) 226 port_id)
221 return 227 return
222 return binding[0].host 228 return query.host
223 229
224 230
225@db_api.context_manager.reader 231@db_api.context_manager.reader
226def generate_distributed_port_status(context, port_id): 232def generate_distributed_port_status(context, port_id):
227 # an OR'ed value of status assigned to parent port from the 233 # an OR'ed value of status assigned to parent port from the
228 # distributedportbinding bucket 234 # distributedportbinding bucket
235 query = context.session.query(models.DistributedPortBinding)
229 final_status = n_const.PORT_STATUS_BUILD 236 final_status = n_const.PORT_STATUS_BUILD
230 bindings = port_obj.DistributedPortBinding.get_objects(context, 237 for bind in query.filter(models.DistributedPortBinding.port_id == port_id):
231 port_id=port_id)
232 for bind in bindings:
233 if bind.status == n_const.PORT_STATUS_ACTIVE: 238 if bind.status == n_const.PORT_STATUS_ACTIVE:
234 return bind.status 239 return bind.status
235 elif bind.status == n_const.PORT_STATUS_DOWN: 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
240def get_distributed_port_binding_by_host(context, port_id, host): 245def get_distributed_port_binding_by_host(context, port_id, host):
241 bindings = port_obj.DistributedPortBinding.get_objects( 246 with db_api.context_manager.reader.using(context):
242 context, port_id=obj_utils.StringStarts(port_id), host=host) 247 binding = (context.session.query(models.DistributedPortBinding).
243 binding = bindings.pop() if bindings else None 248 filter(models.DistributedPortBinding.port_id.startswith(port_id),
244 249 models.DistributedPortBinding.host == host).first())
245 if not binding: 250 if not binding:
246 LOG.debug("No binding for distributed port %(port_id)s with host " 251 LOG.debug("No binding for distributed port %(port_id)s with host "
247 "%(host)s", {'port_id': port_id, 'host': host}) 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
251def get_distributed_port_bindings(context, port_id): 256def get_distributed_port_bindings(context, port_id):
252 bindings = port_obj.DistributedPortBinding.get_objects( 257 with db_api.context_manager.reader.using(context):
253 context, port_id=obj_utils.StringStarts(port_id)) 258 bindings = (context.session.query(models.DistributedPortBinding).
259 filter(models.DistributedPortBinding.port_id.startswith(
260 port_id)).all())
254 if not bindings: 261 if not bindings:
255 LOG.debug("No bindings for distributed port %s", port_id) 262 LOG.debug("No bindings for distributed port %s", port_id)
256 return bindings 263 return bindings
diff --git a/neutron/plugins/ml2/driver_context.py b/neutron/plugins/ml2/driver_context.py
index 593a08f..68da335 100644
--- a/neutron/plugins/ml2/driver_context.py
+++ b/neutron/plugins/ml2/driver_context.py
@@ -17,6 +17,7 @@ from neutron_lib.api.definitions import portbindings
17from neutron_lib import constants 17from neutron_lib import constants
18from neutron_lib.plugins.ml2 import api 18from neutron_lib.plugins.ml2 import api
19from oslo_log import log 19from oslo_log import log
20from oslo_serialization import jsonutils
20import sqlalchemy 21import sqlalchemy
21 22
22from neutron.db import segments_db 23from neutron.db import segments_db
@@ -123,7 +124,9 @@ class PortContext(MechanismDriverContext, api.PortContext):
123 else: 124 else:
124 self._network_context = NetworkContext( 125 self._network_context = NetworkContext(
125 plugin, plugin_context, network) if network else None 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 self._binding_levels = [InstanceSnapshot(l) 130 self._binding_levels = [InstanceSnapshot(l)
128 for l in (binding_levels or [])] 131 for l in (binding_levels or [])]
129 self._segments_to_bind = None 132 self._segments_to_bind = None
@@ -292,7 +295,7 @@ class PortContext(MechanismDriverContext, api.PortContext):
292 # TODO(rkukura) Verify binding allowed, segment in network 295 # TODO(rkukura) Verify binding allowed, segment in network
293 self._new_bound_segment = segment_id 296 self._new_bound_segment = segment_id
294 self._binding.vif_type = vif_type 297 self._binding.vif_type = vif_type
295 self._binding.vif_details = vif_details 298 self._binding.vif_details = jsonutils.dumps(vif_details)
296 self._new_port_status = status 299 self._new_port_status = status
297 300
298 def continue_binding(self, segment_id, next_segments_to_bind): 301 def continue_binding(self, segment_id, next_segments_to_bind):
diff --git a/neutron/plugins/ml2/models.py b/neutron/plugins/ml2/models.py
index 9964048..8922e21 100644
--- a/neutron/plugins/ml2/models.py
+++ b/neutron/plugins/ml2/models.py
@@ -125,6 +125,6 @@ class DistributedPortBinding(model_base.BASEV2):
125 models_v2.Port, 125 models_v2.Port,
126 load_on_pending=True, 126 load_on_pending=True,
127 backref=orm.backref("distributed_port_binding", 127 backref=orm.backref("distributed_port_binding",
128 lazy='joined', 128 lazy='subquery',
129 cascade='delete')) 129 cascade='delete'))
130 revises_on_change = ('port', ) 130 revises_on_change = ('port', )
diff --git a/neutron/plugins/ml2/plugin.py b/neutron/plugins/ml2/plugin.py
index 586dafa..6599b84 100644
--- a/neutron/plugins/ml2/plugin.py
+++ b/neutron/plugins/ml2/plugin.py
@@ -83,7 +83,6 @@ from neutron.db import subnet_service_type_db_models as service_type_db
83from neutron.db import vlantransparent_db 83from neutron.db import vlantransparent_db
84from neutron.extensions import providernet as provider 84from neutron.extensions import providernet as provider
85from neutron.extensions import vlantransparent 85from neutron.extensions import vlantransparent
86from neutron.objects import ports as obj_port
87from neutron.plugins.common import utils as p_utils 86from neutron.plugins.common import utils as p_utils
88from neutron.plugins.ml2.common import exceptions as ml2_exc 87from neutron.plugins.ml2.common import exceptions as ml2_exc
89from neutron.plugins.ml2 import db 88from neutron.plugins.ml2 import db
@@ -317,6 +316,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
317 port = mech_context.current 316 port = mech_context.current
318 port_id = port['id'] 317 port_id = port['id']
319 changes = False 318 changes = False
319
320 host = const.ATTR_NOT_SPECIFIED 320 host = const.ATTR_NOT_SPECIFIED
321 if attrs and portbindings.HOST_ID in attrs: 321 if attrs and portbindings.HOST_ID in attrs:
322 host = attrs.get(portbindings.HOST_ID) or '' 322 host = attrs.get(portbindings.HOST_ID) or ''
@@ -340,9 +340,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
340 340
341 if profile not in (None, const.ATTR_NOT_SPECIFIED, 341 if profile not in (None, const.ATTR_NOT_SPECIFIED,
342 self._get_profile(binding)): 342 self._get_profile(binding)):
343 binding.profile = profile 343 binding.profile = jsonutils.dumps(profile)
344 if (len(jsonutils.dumps(binding.profile)) > 344 if len(binding.profile) > models.BINDING_PROFILE_LEN:
345 models.BINDING_PROFILE_LEN):
346 msg = _("binding:profile value too large") 345 msg = _("binding:profile value too large")
347 raise exc.InvalidInput(error_message=msg) 346 raise exc.InvalidInput(error_message=msg)
348 changes = True 347 changes = True
@@ -350,8 +349,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
350 # Unbind the port if needed. 349 # Unbind the port if needed.
351 if changes: 350 if changes:
352 binding.vif_type = portbindings.VIF_TYPE_UNBOUND 351 binding.vif_type = portbindings.VIF_TYPE_UNBOUND
353 binding.vif_details = None 352 binding.vif_details = ''
354 binding.update()
355 db.clear_binding_levels(plugin_context, port_id, original_host) 353 db.clear_binding_levels(plugin_context, port_id, original_host)
356 mech_context._clear_binding_levels() 354 mech_context._clear_binding_levels()
357 port['status'] = const.PORT_STATUS_DOWN 355 port['status'] = const.PORT_STATUS_DOWN
@@ -361,14 +359,13 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
361 359
362 if port['device_owner'] == const.DEVICE_OWNER_DVR_INTERFACE: 360 if port['device_owner'] == const.DEVICE_OWNER_DVR_INTERFACE:
363 binding.vif_type = portbindings.VIF_TYPE_UNBOUND 361 binding.vif_type = portbindings.VIF_TYPE_UNBOUND
364 binding.vif_details = None 362 binding.vif_details = ''
365 db.clear_binding_levels(plugin_context, port_id, original_host) 363 db.clear_binding_levels(plugin_context, port_id, original_host)
366 mech_context._clear_binding_levels() 364 mech_context._clear_binding_levels()
367 binding.host = '' 365 binding.host = ''
368 binding.update()
369 366
370 self._update_port_dict_binding(port, binding) 367 self._update_port_dict_binding(port, binding)
371 binding.update() 368 binding.persist_state_to_session(plugin_context.session)
372 return changes 369 return changes
373 370
374 @db_api.retry_db_errors 371 @db_api.retry_db_errors
@@ -440,15 +437,12 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
440 # transaction. 437 # transaction.
441 port = orig_context.current 438 port = orig_context.current
442 orig_binding = orig_context._binding 439 orig_binding = orig_context._binding
443 profile = orig_binding.profile or {} 440 new_binding = models.PortBinding(
444 new_binding = obj_port.PortBinding(
445 orig_context._plugin_context,
446 port_id=orig_binding.port_id,
447 host=orig_binding.host, 441 host=orig_binding.host,
448 vnic_type=orig_binding.vnic_type, 442 vnic_type=orig_binding.vnic_type,
449 profile=profile, 443 profile=orig_binding.profile,
450 vif_type=portbindings.VIF_TYPE_UNBOUND, 444 vif_type=portbindings.VIF_TYPE_UNBOUND,
451 vif_details=None 445 vif_details=''
452 ) 446 )
453 self._update_port_dict_binding(port, new_binding) 447 self._update_port_dict_binding(port, new_binding)
454 new_context = driver_context.PortContext( 448 new_context = driver_context.PortContext(
@@ -485,13 +479,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
485 # mechanism driver update_port_*commit() calls. 479 # mechanism driver update_port_*commit() calls.
486 try: 480 try:
487 port_db = self._get_port(plugin_context, port_id) 481 port_db = self._get_port(plugin_context, port_id)
488 plugin_context.session.refresh(port_db) 482 cur_binding = port_db.port_binding
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
495 except exc.PortNotFound: 483 except exc.PortNotFound:
496 port_db, cur_binding = None, None 484 port_db, cur_binding = None, None
497 if not port_db or not cur_binding: 485 if not port_db or not cur_binding:
@@ -558,10 +546,10 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
558 cur_binding.host) 546 cur_binding.host)
559 db.set_binding_levels(plugin_context, 547 db.set_binding_levels(plugin_context,
560 bind_context._binding_levels) 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 cur_context._binding_levels = bind_context._binding_levels 552 cur_context._binding_levels = bind_context._binding_levels
563 cur_binding.update()
564 plugin_context.session.refresh(port_db)
565 553
566 # Update PortContext's port dictionary to reflect the 554 # Update PortContext's port dictionary to reflect the
567 # updated binding state. 555 # updated binding state.
@@ -612,10 +600,6 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
612 def _get_vif_details(self, binding): 600 def _get_vif_details(self, binding):
613 if binding.vif_details: 601 if binding.vif_details:
614 try: 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 return jsonutils.loads(binding.vif_details) 603 return jsonutils.loads(binding.vif_details)
620 except Exception: 604 except Exception:
621 LOG.error("Serialized vif_details DB value '%(value)s' " 605 LOG.error("Serialized vif_details DB value '%(value)s' "
@@ -627,10 +611,6 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
627 def _get_profile(self, binding): 611 def _get_profile(self, binding):
628 if binding.profile: 612 if binding.profile:
629 try: 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 return jsonutils.loads(binding.profile) 614 return jsonutils.loads(binding.profile)
635 except Exception: 615 except Exception:
636 LOG.error("Serialized profile DB value '%(value)s' for " 616 LOG.error("Serialized profile DB value '%(value)s' for "
@@ -1314,12 +1294,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
1314 original_port=original_port) 1294 original_port=original_port)
1315 with db_api.context_manager.writer.using(context): 1295 with db_api.context_manager.writer.using(context):
1316 port_db = self._get_port(context, id) 1296 port_db = self._get_port(context, id)
1317 context.session.refresh(port_db) 1297 binding = port_db.port_binding
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
1323 if not binding: 1298 if not binding:
1324 raise exc.PortNotFound(port_id=id) 1299 raise exc.PortNotFound(port_id=id)
1325 mac_address_updated = self._check_mac_update_allowed( 1300 mac_address_updated = self._check_mac_update_allowed(
@@ -1458,21 +1433,19 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
1458 binding = mech_context._binding 1433 binding = mech_context._binding
1459 port = mech_context.current 1434 port = mech_context.current
1460 port_id = port['id'] 1435 port_id = port['id']
1461 clear_host = None
1462 1436
1463 if binding.vif_type != portbindings.VIF_TYPE_UNBOUND: 1437 if binding.vif_type != portbindings.VIF_TYPE_UNBOUND:
1464 binding.vif_details = None 1438 binding.vif_details = ''
1465 binding.vif_type = portbindings.VIF_TYPE_UNBOUND 1439 binding.vif_type = portbindings.VIF_TYPE_UNBOUND
1466 if binding.host: 1440 if binding.host:
1467 db.clear_binding_levels(plugin_context, port_id, binding.host) 1441 db.clear_binding_levels(plugin_context, port_id, binding.host)
1468 clear_host = '' 1442 binding.host = ''
1469 1443
1470 self._update_port_dict_binding(port, binding) 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 binding.router_id = attrs and attrs.get('device_id') 1446 binding.router_id = attrs and attrs.get('device_id')
1473 if new_host: 1447 # merge into session to reflect changes
1474 binding.host = new_host 1448 binding.persist_state_to_session(plugin_context.session)
1475 binding.update()
1476 1449
1477 @utils.transaction_guard 1450 @utils.transaction_guard
1478 @db_api.retry_if_session_inactive() 1451 @db_api.retry_if_session_inactive()
@@ -1543,11 +1516,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
1543 with db_api.context_manager.writer.using(context): 1516 with db_api.context_manager.writer.using(context):
1544 try: 1517 try:
1545 port_db = self._get_port(context, id) 1518 port_db = self._get_port(context, id)
1546 # TODO(korzen) replace get_objects with port_obj.binding when 1519 binding = port_db.port_binding
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
1551 except exc.PortNotFound: 1520 except exc.PortNotFound:
1552 LOG.debug("The port '%s' was deleted", id) 1521 LOG.debug("The port '%s' was deleted", id)
1553 return 1522 return
@@ -1791,7 +1760,6 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
1791 return 1760 return
1792 if binding.status != status: 1761 if binding.status != status:
1793 binding.status = status 1762 binding.status = status
1794 binding.update()
1795 updated = True 1763 updated = True
1796 1764
1797 if (updated and 1765 if (updated and
diff --git a/neutron/tests/unit/objects/test_objects.py b/neutron/tests/unit/objects/test_objects.py
index 21a0977..984cea9 100644
--- a/neutron/tests/unit/objects/test_objects.py
+++ b/neutron/tests/unit/objects/test_objects.py
@@ -62,7 +62,7 @@ object_data = {
62 'NetworkPortSecurity': '1.0-b30802391a87945ee9c07582b4ff95e3', 62 'NetworkPortSecurity': '1.0-b30802391a87945ee9c07582b4ff95e3',
63 'NetworkSegment': '1.0-57b7f2960971e3b95ded20cbc59244a8', 63 'NetworkSegment': '1.0-57b7f2960971e3b95ded20cbc59244a8',
64 'Port': '1.1-5bf48d12a7bf7f5b7a319e8003b437a5', 64 'Port': '1.1-5bf48d12a7bf7f5b7a319e8003b437a5',
65 'PortBinding': '1.0-0ad9727c4e72d609d5b4f70bcd3bc727', 65 'PortBinding': '1.0-3306deeaa6deb01e33af06777d48d578',
66 'PortBindingLevel': '1.0-de66a4c61a083b8f34319fa9dde5b060', 66 'PortBindingLevel': '1.0-de66a4c61a083b8f34319fa9dde5b060',
67 'PortDataPlaneStatus': '1.0-25be74bda46c749653a10357676c0ab2', 67 'PortDataPlaneStatus': '1.0-25be74bda46c749653a10357676c0ab2',
68 'PortDNS': '1.1-c5ca2dc172bdd5fafee3fc986d1d7023', 68 'PortDNS': '1.1-c5ca2dc172bdd5fafee3fc986d1d7023',
diff --git a/neutron/tests/unit/plugins/ml2/test_db.py b/neutron/tests/unit/plugins/ml2/test_db.py
index 6b893d8..2a55115 100644
--- a/neutron/tests/unit/plugins/ml2/test_db.py
+++ b/neutron/tests/unit/plugins/ml2/test_db.py
@@ -23,6 +23,7 @@ from neutron_lib import context
23from neutron_lib.plugins.ml2 import api 23from neutron_lib.plugins.ml2 import api
24from oslo_utils import uuidutils 24from oslo_utils import uuidutils
25from sqlalchemy.orm import exc 25from sqlalchemy.orm import exc
26from sqlalchemy.orm import query
26 27
27from neutron.db import api as db_api 28from neutron.db import api as db_api
28from neutron.db import db_base_plugin_v2 29from neutron.db import db_base_plugin_v2
@@ -32,6 +33,7 @@ from neutron.db import segments_db
32from neutron.objects import network as network_obj 33from neutron.objects import network as network_obj
33from neutron.objects import ports as port_obj 34from neutron.objects import ports as port_obj
34from neutron.plugins.ml2 import db as ml2_db 35from neutron.plugins.ml2 import db as ml2_db
36from neutron.plugins.ml2 import models
35from neutron.tests.unit import testlib_api 37from neutron.tests.unit import testlib_api
36 38
37 39
@@ -62,8 +64,10 @@ class Ml2DBTestCase(testlib_api.SqlTestCase):
62 return port 64 return port
63 65
64 def _setup_neutron_portbinding(self, port_id, vif_type, host): 66 def _setup_neutron_portbinding(self, port_id, vif_type, host):
65 port_obj.PortBinding( 67 with db_api.context_manager.writer.using(self.ctx):
66 self.ctx, port_id=port_id, vif_type=vif_type, host=host).create() 68 self.ctx.session.add(models.PortBinding(port_id=port_id,
69 vif_type=vif_type,
70 host=host))
67 71
68 @staticmethod 72 @staticmethod
69 def _sort_segments(segments): 73 def _sort_segments(segments):
@@ -314,45 +318,44 @@ class Ml2DvrDBTestCase(testlib_api.SqlTestCase):
314 318
315 def _setup_distributed_binding(self, network_id, 319 def _setup_distributed_binding(self, network_id,
316 port_id, router_id, host_id): 320 port_id, router_id, host_id):
317 binding_obj = port_obj.DistributedPortBinding( 321 with db_api.context_manager.writer.using(self.ctx):
318 self.ctx, 322 record = models.DistributedPortBinding(
319 port_id=port_id, 323 port_id=port_id,
320 host=host_id, 324 host=host_id,
321 router_id=router_id, 325 router_id=router_id,
322 vif_type=portbindings.VIF_TYPE_UNBOUND, 326 vif_type=portbindings.VIF_TYPE_UNBOUND,
323 vnic_type=portbindings.VNIC_NORMAL, 327 vnic_type=portbindings.VNIC_NORMAL,
324 status='DOWN') 328 status='DOWN')
325 binding_obj.create() 329 self.ctx.session.add(record)
326 return binding_obj 330 return record
327 331
328 def test_ensure_distributed_port_binding_deals_with_db_duplicate(self): 332 def test_ensure_distributed_port_binding_deals_with_db_duplicate(self):
329 network_id = uuidutils.generate_uuid() 333 network_id = uuidutils.generate_uuid()
330 port_id = uuidutils.generate_uuid() 334 port_id = uuidutils.generate_uuid()
331 router_id = uuidutils.generate_uuid() 335 router_id = 'foo_router_id'
332 host_id = uuidutils.generate_uuid() 336 host_id = 'foo_host_id'
333 self._setup_neutron_network(network_id, [port_id]) 337 self._setup_neutron_network(network_id, [port_id])
334 dpb = self._setup_distributed_binding(network_id, port_id, 338 self._setup_distributed_binding(network_id, port_id,
335 router_id, host_id) 339 router_id, host_id)
336 with mock.patch.object(port_obj.DistributedPortBinding, 340 with mock.patch.object(query.Query, 'first') as query_first:
337 'get_object') as get_object: 341 query_first.return_value = []
338 get_object.side_effect = [None, dpb] 342 with mock.patch.object(ml2_db.LOG, 'debug') as log_trace:
339 binding = ml2_db.ensure_distributed_port_binding( 343 binding = ml2_db.ensure_distributed_port_binding(
340 self.ctx, port_id, host_id, router_id) 344 self.ctx, port_id, host_id, router_id)
341 self.assertTrue(get_object.called) 345 self.assertTrue(query_first.called)
346 self.assertTrue(log_trace.called)
342 self.assertEqual(port_id, binding.port_id) 347 self.assertEqual(port_id, binding.port_id)
343 348
344 def test_ensure_distributed_port_binding(self): 349 def test_ensure_distributed_port_binding(self):
345 network_id = uuidutils.generate_uuid() 350 network_id = uuidutils.generate_uuid()
346 expected_port_id = uuidutils.generate_uuid() 351 port_id = uuidutils.generate_uuid()
347 self._setup_neutron_network(network_id, [expected_port_id]) 352 self._setup_neutron_network(network_id, [port_id])
348 router = self._setup_neutron_router() 353 router = self._setup_neutron_router()
349 ml2_db.ensure_distributed_port_binding( 354 ml2_db.ensure_distributed_port_binding(
350 self.ctx, expected_port_id, 'foo_host', router.id) 355 self.ctx, port_id, 'foo_host', router.id)
351 actual_objs = port_obj.DistributedPortBinding.get_objects( 356 expected = (self.ctx.session.query(models.DistributedPortBinding).
352 self.ctx, port_id=expected_port_id) 357 filter_by(port_id=port_id).one())
353 self.assertEqual(1, len(actual_objs)) 358 self.assertEqual(port_id, expected.port_id)
354 actual_obj = actual_objs.pop()
355 self.assertEqual(expected_port_id, actual_obj.port_id)
356 359
357 def test_ensure_distributed_port_binding_multiple_bindings(self): 360 def test_ensure_distributed_port_binding_multiple_bindings(self):
358 network_id = uuidutils.generate_uuid() 361 network_id = uuidutils.generate_uuid()
@@ -363,9 +366,9 @@ class Ml2DvrDBTestCase(testlib_api.SqlTestCase):
363 self.ctx, port_id, 'foo_host_1', router.id) 366 self.ctx, port_id, 'foo_host_1', router.id)
364 ml2_db.ensure_distributed_port_binding( 367 ml2_db.ensure_distributed_port_binding(
365 self.ctx, port_id, 'foo_host_2', router.id) 368 self.ctx, port_id, 'foo_host_2', router.id)
366 count_objs = port_obj.DistributedPortBinding.count( 369 bindings = (self.ctx.session.query(models.DistributedPortBinding).
367 self.ctx, port_id=port_id) 370 filter_by(port_id=port_id).all())
368 self.assertEqual(2, count_objs) 371 self.assertEqual(2, len(bindings))
369 372
370 def test_delete_distributed_port_binding_if_stale(self): 373 def test_delete_distributed_port_binding_if_stale(self):
371 network_id = uuidutils.generate_uuid() 374 network_id = uuidutils.generate_uuid()
@@ -374,23 +377,21 @@ class Ml2DvrDBTestCase(testlib_api.SqlTestCase):
374 binding = self._setup_distributed_binding( 377 binding = self._setup_distributed_binding(
375 network_id, port_id, None, 'foo_host_id') 378 network_id, port_id, None, 'foo_host_id')
376 379
377 ml2_db.delete_distributed_port_binding_if_stale(self.ctx, binding) 380 ml2_db.delete_distributed_port_binding_if_stale(self.ctx,
378 381 binding)
379 obj_exists = port_obj.DistributedPortBinding.objects_exist( 382 count = (self.ctx.session.query(models.DistributedPortBinding).
380 self.ctx, port_id=binding.port_id) 383 filter_by(port_id=binding.port_id).count())
381 self.assertFalse(obj_exists) 384 self.assertFalse(count)
382 385
383 def test_get_distributed_port_binding_by_host_not_found(self): 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 port = ml2_db.get_distributed_port_binding_by_host( 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 self.assertIsNone(port) 389 self.assertIsNone(port)
389 390
390 def test_get_distributed_port_bindings_not_found(self): 391 def test_get_distributed_port_bindings_not_found(self):
391 port = ml2_db.get_distributed_port_bindings(self.ctx, 392 port = ml2_db.get_distributed_port_bindings(self.ctx,
392 uuidutils.generate_uuid()) 393 'foo_port_id')
393 self.assertEqual(0, len(port)) 394 self.assertFalse(len(port))
394 395
395 def test_get_distributed_port_bindings(self): 396 def test_get_distributed_port_bindings(self):
396 network_id = uuidutils.generate_uuid() 397 network_id = uuidutils.generate_uuid()
@@ -411,9 +412,8 @@ class Ml2DvrDBTestCase(testlib_api.SqlTestCase):
411 network_obj.Network(self.ctx, id=network_id).create() 412 network_obj.Network(self.ctx, id=network_id).create()
412 with db_api.context_manager.writer.using(self.ctx): 413 with db_api.context_manager.writer.using(self.ctx):
413 device_owner = constants.DEVICE_OWNER_DVR_INTERFACE 414 device_owner = constants.DEVICE_OWNER_DVR_INTERFACE
414 port_id = uuidutils.generate_uuid()
415 port = models_v2.Port( 415 port = models_v2.Port(
416 id=port_id, 416 id='port_id',
417 network_id=network_id, 417 network_id=network_id,
418 mac_address='00:11:22:33:44:55', 418 mac_address='00:11:22:33:44:55',
419 admin_state_up=True, 419 admin_state_up=True,
@@ -421,22 +421,25 @@ class Ml2DvrDBTestCase(testlib_api.SqlTestCase):
421 device_id='device_id', 421 device_id='device_id',
422 device_owner=device_owner) 422 device_owner=device_owner)
423 self.ctx.session.add(port) 423 self.ctx.session.add(port)
424 binding_kwarg = { 424 binding_kwarg = {
425 'port_id': port_id, 425 'port_id': 'port_id',
426 'host': 'host', 426 'host': 'host',
427 'vif_type': portbindings.VIF_TYPE_UNBOUND, 427 'vif_type': portbindings.VIF_TYPE_UNBOUND,
428 'vnic_type': portbindings.VNIC_NORMAL, 428 'vnic_type': portbindings.VNIC_NORMAL,
429 'router_id': 'router_id', 429 'router_id': 'router_id',
430 'status': constants.PORT_STATUS_DOWN 430 'status': constants.PORT_STATUS_DOWN
431 } 431 }
432 port_obj.DistributedPortBinding(self.ctx, **binding_kwarg).create() 432 self.ctx.session.add(models.DistributedPortBinding(
433 binding_kwarg['host'] = 'another-host' 433 **binding_kwarg))
434 port_obj.DistributedPortBinding(self.ctx, **binding_kwarg).create() 434 binding_kwarg['host'] = 'another-host'
435 self.ctx.session.add(models.DistributedPortBinding(
436 **binding_kwarg))
435 with warnings.catch_warnings(record=True) as warning_list: 437 with warnings.catch_warnings(record=True) as warning_list:
436 with db_api.context_manager.writer.using(self.ctx): 438 with db_api.context_manager.writer.using(self.ctx):
437 self.ctx.session.delete(port) 439 self.ctx.session.delete(port)
438 self.assertEqual( 440 self.assertEqual(
439 [], warning_list, 441 [], warning_list,
440 'Warnings: %s' % ';'.join([str(w) for w in warning_list])) 442 'Warnings: %s' % ';'.join([str(w) for w in warning_list]))
441 bindings = ml2_db.get_distributed_port_bindings(self.ctx, port_id) 443 ports = ml2_db.get_distributed_port_bindings(self.ctx,
442 self.assertEqual(0, len(bindings)) 444 'port_id')
445 self.assertEqual(0, len(ports))
diff --git a/neutron/tests/unit/plugins/ml2/test_plugin.py b/neutron/tests/unit/plugins/ml2/test_plugin.py
index e139e2b..ce74e8b 100644
--- a/neutron/tests/unit/plugins/ml2/test_plugin.py
+++ b/neutron/tests/unit/plugins/ml2/test_plugin.py
@@ -47,7 +47,6 @@ from neutron.db import provisioning_blocks
47from neutron.db import segments_db 47from neutron.db import segments_db
48from neutron.extensions import multiprovidernet as mpnet 48from neutron.extensions import multiprovidernet as mpnet
49from neutron.objects import base as base_obj 49from neutron.objects import base as base_obj
50from neutron.objects import ports as obj_port
51from neutron.objects import router as l3_obj 50from neutron.objects import router as l3_obj
52from neutron.plugins.ml2.common import exceptions as ml2_exc 51from neutron.plugins.ml2.common import exceptions as ml2_exc
53from neutron.plugins.ml2 import db as ml2_db 52from neutron.plugins.ml2 import db as ml2_db
@@ -1692,10 +1691,9 @@ class TestMl2PortBinding(Ml2PluginV2TestCase,
1692 # create a port and delete it so we have an expired mechanism context 1691 # create a port and delete it so we have an expired mechanism context
1693 with self.port() as port: 1692 with self.port() as port:
1694 plugin = directory.get_plugin() 1693 plugin = directory.get_plugin()
1695 binding = obj_port.PortBinding.get_object( 1694 binding = plugin._get_port(self.context,
1696 self.context, port_id=port['port']['id'], host='') 1695 port['port']['id']).port_binding
1697 binding.host = 'test' 1696 binding['host'] = 'test'
1698 binding.update()
1699 mech_context = driver_context.PortContext( 1697 mech_context = driver_context.PortContext(
1700 plugin, self.context, port['port'], 1698 plugin, self.context, port['port'],
1701 plugin.get_network(self.context, port['port']['network_id']), 1699 plugin.get_network(self.context, port['port']['network_id']),
@@ -1714,11 +1712,10 @@ class TestMl2PortBinding(Ml2PluginV2TestCase,
1714 def _create_port_and_bound_context(self, port_vif_type, bound_vif_type): 1712 def _create_port_and_bound_context(self, port_vif_type, bound_vif_type):
1715 with self.port() as port: 1713 with self.port() as port:
1716 plugin = directory.get_plugin() 1714 plugin = directory.get_plugin()
1717 binding = obj_port.PortBinding.get_object( 1715 binding = plugin._get_port(
1718 self.context, port_id=port['port']['id'], host='') 1716 self.context, port['port']['id']).port_binding
1719 binding.host = 'fake_host' 1717 binding['host'] = 'fake_host'
1720 binding['vif_type'] = port_vif_type 1718 binding['vif_type'] = port_vif_type
1721 binding.update()
1722 # Generates port context to be used before the bind. 1719 # Generates port context to be used before the bind.
1723 port_context = driver_context.PortContext( 1720 port_context = driver_context.PortContext(
1724 plugin, self.context, port['port'], 1721 plugin, self.context, port['port'],
@@ -1830,10 +1827,10 @@ class TestMl2PortBinding(Ml2PluginV2TestCase,
1830 def test_update_port_binding_host_id_none(self): 1827 def test_update_port_binding_host_id_none(self):
1831 with self.port() as port: 1828 with self.port() as port:
1832 plugin = directory.get_plugin() 1829 plugin = directory.get_plugin()
1833 binding = obj_port.PortBinding.get_object( 1830 binding = plugin._get_port(
1834 self.context, port_id=port['port']['id'], host='') 1831 self.context, port['port']['id']).port_binding
1835 binding.host = 'test' 1832 with self.context.session.begin(subtransactions=True):
1836 binding.update() 1833 binding.host = 'test'
1837 mech_context = driver_context.PortContext( 1834 mech_context = driver_context.PortContext(
1838 plugin, self.context, port['port'], 1835 plugin, self.context, port['port'],
1839 plugin.get_network(self.context, port['port']['network_id']), 1836 plugin.get_network(self.context, port['port']['network_id']),
@@ -1844,18 +1841,15 @@ class TestMl2PortBinding(Ml2PluginV2TestCase,
1844 self.assertEqual('test', binding.host) 1841 self.assertEqual('test', binding.host)
1845 with self.context.session.begin(subtransactions=True): 1842 with self.context.session.begin(subtransactions=True):
1846 plugin._process_port_binding(mech_context, attrs) 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 self.assertTrue(update_mock.mock_calls) 1844 self.assertTrue(update_mock.mock_calls)
1850 self.assertEqual('', updated_binding.host) 1845 self.assertEqual('', binding.host)
1851 1846
1852 def test_update_port_binding_host_id_not_changed(self): 1847 def test_update_port_binding_host_id_not_changed(self):
1853 with self.port() as port: 1848 with self.port() as port:
1854 plugin = directory.get_plugin() 1849 plugin = directory.get_plugin()
1855 binding = obj_port.PortBinding.get_object( 1850 binding = plugin._get_port(
1856 self.context, port_id=port['port']['id'], host='') 1851 self.context, port['port']['id']).port_binding
1857 binding.host = 'test' 1852 binding['host'] = 'test'
1858 binding.update()
1859 mech_context = driver_context.PortContext( 1853 mech_context = driver_context.PortContext(
1860 plugin, self.context, port['port'], 1854 plugin, self.context, port['port'],
1861 plugin.get_network(self.context, port['port']['network_id']), 1855 plugin.get_network(self.context, port['port']['network_id']),
@@ -1868,34 +1862,30 @@ class TestMl2PortBinding(Ml2PluginV2TestCase,
1868 self.assertEqual('test', binding.host) 1862 self.assertEqual('test', binding.host)
1869 1863
1870 def test_process_distributed_port_binding_update_router_id(self): 1864 def test_process_distributed_port_binding_update_router_id(self):
1871 with self.port() as port: 1865 host_id = 'host'
1872 host_id = 'host' 1866 binding = models.DistributedPortBinding(
1873 ctxt = context.get_admin_context() 1867 port_id='port_id',
1874 binding_obj = obj_port.DistributedPortBinding( 1868 host=host_id,
1875 ctxt, 1869 router_id='old_router_id',
1876 port_id=port['port']['id'], 1870 vif_type=portbindings.VIF_TYPE_OVS,
1877 host=host_id, 1871 vnic_type=portbindings.VNIC_NORMAL,
1878 profile={}, 1872 status=constants.PORT_STATUS_DOWN)
1879 router_id='old_router_id', 1873 plugin = directory.get_plugin()
1880 vif_type=portbindings.VIF_TYPE_OVS, 1874 mock_network = {'id': 'net_id'}
1881 vnic_type=portbindings.VNIC_NORMAL, 1875 mock_port = {'id': 'port_id'}
1882 status=constants.PORT_STATUS_DOWN) 1876 ctxt = context.get_admin_context()
1883 binding_obj.create() 1877 new_router_id = 'new_router'
1884 plugin = directory.get_plugin() 1878 attrs = {'device_id': new_router_id, portbindings.HOST_ID: host_id}
1885 mock_network = {'id': 'net_id'} 1879 with mock.patch.object(plugin, '_update_port_dict_binding'):
1886 mock_port = {'id': 'port_id'} 1880 with mock.patch.object(segments_db, 'get_network_segments',
1887 new_router_id = 'new_router' 1881 return_value=[]):
1888 attrs = {'device_id': new_router_id, portbindings.HOST_ID: host_id} 1882 mech_context = driver_context.PortContext(
1889 with mock.patch.object(plugin, '_update_port_dict_binding'): 1883 self, ctxt, mock_port, mock_network, binding, None)
1890 with mock.patch.object(segments_db, 'get_network_segments', 1884 plugin._process_distributed_port_binding(mech_context,
1891 return_value=[]): 1885 ctxt, attrs)
1892 mech_context = driver_context.PortContext( 1886 self.assertEqual(new_router_id,
1893 self, ctxt, mock_port, mock_network, binding_obj, None) 1887 mech_context._binding.router_id)
1894 plugin._process_distributed_port_binding(mech_context, 1888 self.assertEqual(host_id, mech_context._binding.host)
1895 ctxt, attrs)
1896 self.assertEqual(new_router_id,
1897 mech_context._binding.router_id)
1898 self.assertEqual(host_id, mech_context._binding.host)
1899 1889
1900 def test_update_distributed_port_binding_on_concurrent_port_delete(self): 1890 def test_update_distributed_port_binding_on_concurrent_port_delete(self):
1901 plugin = directory.get_plugin() 1891 plugin = directory.get_plugin()
@@ -1926,20 +1916,9 @@ class TestMl2PortBinding(Ml2PluginV2TestCase,
1926 def test__bind_port_original_port_set(self): 1916 def test__bind_port_original_port_set(self):
1927 plugin = directory.get_plugin() 1917 plugin = directory.get_plugin()
1928 plugin.mechanism_manager = mock.Mock() 1918 plugin.mechanism_manager = mock.Mock()
1929 mock_port = {'id': uuidutils.generate_uuid()} 1919 mock_port = {'id': 'port_id'}
1930 context = mock.Mock() 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 context.network.current = {'id': 'net_id'} 1921 context.network.current = {'id': 'net_id'}
1942 context._binding = binding_obj
1943 context.original = mock_port 1922 context.original = mock_port
1944 with mock.patch.object(plugin, '_update_port_dict_binding'), \ 1923 with mock.patch.object(plugin, '_update_port_dict_binding'), \
1945 mock.patch.object(segments_db, 'get_network_segments', 1924 mock.patch.object(segments_db, 'get_network_segments',
@@ -2615,15 +2594,13 @@ class TestFaultyMechansimDriver(Ml2PluginV2FaultyDriverTestCase):
2615 def test_update_distributed_router_interface_port(self): 2594 def test_update_distributed_router_interface_port(self):
2616 """Test validate distributed router interface update succeeds.""" 2595 """Test validate distributed router interface update succeeds."""
2617 host_id = 'host' 2596 host_id = 'host'
2618 binding_obj = obj_port.DistributedPortBinding( 2597 binding = models.DistributedPortBinding(
2619 mock.MagicMock(), 2598 port_id='port_id',
2620 port_id=uuidutils.generate_uuid(), 2599 host=host_id,
2621 host=host_id, 2600 router_id='old_router_id',
2622 router_id='old_router_id', 2601 vif_type=portbindings.VIF_TYPE_OVS,
2623 vif_type=portbindings.VIF_TYPE_OVS, 2602 vnic_type=portbindings.VNIC_NORMAL,
2624 vnic_type=portbindings.VNIC_NORMAL, 2603 status=constants.PORT_STATUS_DOWN)
2625 status=constants.PORT_STATUS_DOWN)
2626 binding_obj.create()
2627 with mock.patch.object( 2604 with mock.patch.object(
2628 mech_test.TestMechanismDriver, 2605 mech_test.TestMechanismDriver,
2629 'update_port_postcommit', 2606 'update_port_postcommit',
@@ -2633,7 +2610,7 @@ class TestFaultyMechansimDriver(Ml2PluginV2FaultyDriverTestCase):
2633 'update_port_precommit') as port_pre,\ 2610 'update_port_precommit') as port_pre,\
2634 mock.patch.object( 2611 mock.patch.object(
2635 ml2_db, 'get_distributed_port_bindings') as dist_bindings: 2612 ml2_db, 'get_distributed_port_bindings') as dist_bindings:
2636 dist_bindings.return_value = [binding_obj] 2613 dist_bindings.return_value = [binding]
2637 port_pre.return_value = True 2614 port_pre.return_value = True
2638 with self.network() as network: 2615 with self.network() as network:
2639 with self.subnet(network=network) as subnet: 2616 with self.subnet(network=network) as subnet:
@@ -2856,10 +2833,9 @@ class TestML2Segments(Ml2PluginV2TestCase):
2856 # add writer here to make sure that the following operations are 2833 # add writer here to make sure that the following operations are
2857 # performed in the same session 2834 # performed in the same session
2858 with db_api.context_manager.writer.using(self.context): 2835 with db_api.context_manager.writer.using(self.context):
2859 binding = obj_port.PortBinding.get_object( 2836 binding = plugin._get_port(
2860 self.context, port_id=port['port']['id'], host='') 2837 self.context, port['port']['id']).port_binding
2861 binding.host = 'host-ovs-no_filter' 2838 binding['host'] = 'host-ovs-no_filter'
2862 binding.update()
2863 mech_context = driver_context.PortContext( 2839 mech_context = driver_context.PortContext(
2864 plugin, self.context, port['port'], 2840 plugin, self.context, port['port'],
2865 plugin.get_network(self.context, 2841 plugin.get_network(self.context,
diff --git a/neutron/tests/unit/plugins/ml2/test_port_binding.py b/neutron/tests/unit/plugins/ml2/test_port_binding.py
index c0b734d..a26ed5e 100644
--- a/neutron/tests/unit/plugins/ml2/test_port_binding.py
+++ b/neutron/tests/unit/plugins/ml2/test_port_binding.py
@@ -19,10 +19,11 @@ from neutron_lib import constants as const
19from neutron_lib import context 19from neutron_lib import context
20from neutron_lib.plugins import directory 20from neutron_lib.plugins import directory
21from oslo_config import cfg 21from oslo_config import cfg
22from oslo_serialization import jsonutils
22 23
23from neutron.conf.plugins.ml2.drivers import driver_type 24from neutron.conf.plugins.ml2.drivers import driver_type
24from neutron.objects import ports as obj_port
25from neutron.plugins.ml2 import driver_context 25from neutron.plugins.ml2 import driver_context
26from neutron.plugins.ml2 import models as ml2_models
26from neutron.tests.unit.db import test_db_base_plugin_v2 as test_plugin 27from 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 ctx = context.get_admin_context() 111 ctx = context.get_admin_context()
111 with self.port(name='name') as port: 112 with self.port(name='name') as port:
112 # emulating concurrent binding deletion 113 # emulating concurrent binding deletion
113 obj_port.PortBinding.delete_objects( 114 with ctx.session.begin():
114 ctx, port_id=port['port']['id']) 115 for item in (ctx.session.query(ml2_models.PortBinding).
116 filter_by(port_id=port['port']['id'])):
117 ctx.session.delete(item)
115 self.assertIsNone( 118 self.assertIsNone(
116 self.plugin.get_bound_port_context(ctx, port['port']['id'])) 119 self.plugin.get_bound_port_context(ctx, port['port']['id']))
117 120
@@ -188,9 +191,13 @@ class PortBindingTestCase(test_plugin.NeutronDbPluginV2TestCase):
188 attrs['binding:host_id'] = 'host2' 191 attrs['binding:host_id'] = 'host2'
189 updated_port = attrs.copy() 192 updated_port = attrs.copy()
190 network = {'id': attrs['network_id']} 193 network = {'id': attrs['network_id']}
191 binding = obj_port.PortBinding.get_object( 194 binding = ml2_models.PortBinding(
192 ctx, port_id=original_port['id'], 195 port_id=original_port['id'],
193 host=original_port['binding:host_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 levels = [] 201 levels = []
195 mech_context = driver_context.PortContext( 202 mech_context = driver_context.PortContext(
196 plugin, ctx, updated_port, network, binding, levels, 203 plugin, ctx, updated_port, network, binding, levels,