Integration of Port Binding Level OVO
This patch integrates Port Binding Level OVO in /plugin/ml2/db.py and introduces context instead of session for usage in object operations. Change-Id: Ifa779f5f70a7502bd96b34d64a84d272af2a6886 Partially-Implements: blueprint adopt-oslo-versioned-objects-for-db Co-Authored-By: Anindita Das <anindita.das@intel.com> Co-Authored-By: Slawek Kaplonski <slawek@kaplonski.pl>
This commit is contained in:
parent
317cdbf408
commit
cfec395b8f
@ -407,6 +407,16 @@ class Port(base.NeutronDbObject):
|
||||
return super(Port, cls).get_objects(context, _pager, validate_filters,
|
||||
**kwargs)
|
||||
|
||||
@classmethod
|
||||
def get_port_ids_filter_by_segment_id(cls, context, segment_id):
|
||||
query = context.session.query(models_v2.Port.id)
|
||||
query = query.join(
|
||||
ml2_models.PortBindingLevel,
|
||||
ml2_models.PortBindingLevel.port_id == models_v2.Port.id)
|
||||
query = query.filter(
|
||||
ml2_models.PortBindingLevel.segment_id == segment_id)
|
||||
return [p.id for p in query]
|
||||
|
||||
@classmethod
|
||||
def modify_fields_to_db(cls, fields):
|
||||
result = super(Port, cls).modify_fields_to_db(fields)
|
||||
|
@ -13,6 +13,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from debtcollector import removals
|
||||
from neutron_lib.api.definitions import portbindings
|
||||
from neutron_lib.callbacks import events
|
||||
from neutron_lib.callbacks import registry
|
||||
@ -30,6 +31,7 @@ from neutron._i18n import _
|
||||
from neutron.db import api as db_api
|
||||
from neutron.db.models import securitygroup as sg_models
|
||||
from neutron.db import models_v2
|
||||
from neutron.objects import base as objects_base
|
||||
from neutron.objects import ports as port_obj
|
||||
from neutron.plugins.ml2 import models
|
||||
from neutron.services.segments import exceptions as seg_exc
|
||||
@ -53,7 +55,7 @@ def add_port_binding(context, port_id):
|
||||
def set_binding_levels(context, levels):
|
||||
if levels:
|
||||
for level in levels:
|
||||
level.persist_state_to_session(context.session)
|
||||
level.create()
|
||||
LOG.debug("For port %(port_id)s, host %(host)s, "
|
||||
"set binding levels %(levels)s",
|
||||
{'port_id': levels[0].port_id,
|
||||
@ -63,6 +65,10 @@ def set_binding_levels(context, levels):
|
||||
LOG.debug("Attempted to set empty binding levels")
|
||||
|
||||
|
||||
@removals.remove(
|
||||
version="Stein", removal_version="T",
|
||||
message="Function get_binding_levels is deprecated. Please use "
|
||||
"get_binding_level_objs instead as it makes use of OVOs.")
|
||||
@db_api.context_manager.reader
|
||||
def get_binding_levels(context, port_id, host):
|
||||
if host:
|
||||
@ -78,12 +84,25 @@ def get_binding_levels(context, port_id, host):
|
||||
return result
|
||||
|
||||
|
||||
@db_api.context_manager.reader
|
||||
def get_binding_level_objs(context, port_id, host):
|
||||
if host:
|
||||
pager = objects_base.Pager(sorts=[('level', True)])
|
||||
port_bl_objs = port_obj.PortBindingLevel.get_objects(
|
||||
context, _pager=pager, port_id=port_id, host=host)
|
||||
LOG.debug("For port %(port_id)s, host %(host)s, "
|
||||
"got binding levels %(levels)s",
|
||||
{'port_id': port_id,
|
||||
'host': host,
|
||||
'levels': port_bl_objs})
|
||||
return port_bl_objs
|
||||
|
||||
|
||||
@db_api.context_manager.writer
|
||||
def clear_binding_levels(context, port_id, host):
|
||||
if host:
|
||||
for l in (context.session.query(models.PortBindingLevel).
|
||||
filter_by(port_id=port_id, host=host)):
|
||||
context.session.delete(l)
|
||||
port_obj.PortBindingLevel.delete_objects(
|
||||
context, port_id=port_id, host=host)
|
||||
LOG.debug("For port %(port_id)s, host %(host)s, "
|
||||
"cleared binding levels",
|
||||
{'port_id': port_id,
|
||||
@ -322,20 +341,15 @@ def _prevent_segment_delete_with_port_bound(resource, event, trigger,
|
||||
return
|
||||
|
||||
with db_api.context_manager.reader.using(context):
|
||||
segment_id = segment['id']
|
||||
query = context.session.query(models_v2.Port.id)
|
||||
query = query.join(
|
||||
models.PortBindingLevel,
|
||||
models.PortBindingLevel.port_id == models_v2.Port.id)
|
||||
query = query.filter(models.PortBindingLevel.segment_id == segment_id)
|
||||
port_ids = [p.id for p in query]
|
||||
port_ids = port_obj.Port.get_port_ids_filter_by_segment_id(
|
||||
context, segment_id=segment['id'])
|
||||
|
||||
# There are still some ports in the segment, segment should not be deleted
|
||||
# TODO(xiaohhui): Should we delete the dhcp port automatically here?
|
||||
if port_ids:
|
||||
reason = _("The segment is still bound with port(s) "
|
||||
"%s") % ", ".join(port_ids)
|
||||
raise seg_exc.SegmentInUse(segment_id=segment_id, reason=reason)
|
||||
raise seg_exc.SegmentInUse(segment_id=segment['id'], reason=reason)
|
||||
|
||||
|
||||
def subscribe():
|
||||
|
@ -132,8 +132,7 @@ class PortContext(MechanismDriverContext, api.PortContext):
|
||||
# NOTE(kevinbenton): InstanceSnapshot can go away once we are working
|
||||
# with OVO objects instead of native SQLA objects.
|
||||
self._binding = InstanceSnapshot(binding)
|
||||
self._binding_levels = [InstanceSnapshot(l)
|
||||
for l in (binding_levels or [])]
|
||||
self._binding_levels = binding_levels or []
|
||||
self._segments_to_bind = None
|
||||
self._new_bound_segment = None
|
||||
self._next_segments_to_bind = None
|
||||
@ -159,7 +158,9 @@ class PortContext(MechanismDriverContext, api.PortContext):
|
||||
self._binding_levels = []
|
||||
|
||||
def _push_binding_level(self, binding_level):
|
||||
self._binding_levels.append(InstanceSnapshot(binding_level))
|
||||
# NOTE(slaweq): binding_level should be always OVO with no reference
|
||||
# to DB object
|
||||
self._binding_levels.append(binding_level)
|
||||
|
||||
def _pop_binding_level(self):
|
||||
return self._binding_levels.pop()
|
||||
|
@ -32,8 +32,8 @@ from neutron._i18n import _
|
||||
from neutron.conf.plugins.ml2 import config
|
||||
from neutron.db import api as db_api
|
||||
from neutron.db import segments_db
|
||||
from neutron.objects import ports
|
||||
from neutron.plugins.ml2.common import exceptions as ml2_exc
|
||||
from neutron.plugins.ml2 import models
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
@ -783,12 +783,15 @@ class MechanismManager(stevedore.named.NamedExtensionManager):
|
||||
driver.obj.bind_port(context)
|
||||
segment = context._new_bound_segment
|
||||
if segment:
|
||||
context._push_binding_level(
|
||||
models.PortBindingLevel(port_id=port_id,
|
||||
host=context.host,
|
||||
level=level,
|
||||
driver=driver.name,
|
||||
segment_id=segment))
|
||||
pbl_obj = ports.PortBindingLevel(
|
||||
context._plugin_context,
|
||||
port_id=port_id,
|
||||
host=context.host,
|
||||
level=level,
|
||||
driver=driver.name,
|
||||
segment_id=segment
|
||||
)
|
||||
context._push_binding_level(pbl_obj)
|
||||
next_segments = context._next_segments_to_bind
|
||||
if next_segments:
|
||||
# Continue binding another level.
|
||||
|
@ -487,7 +487,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
return new_context
|
||||
|
||||
def _commit_port_binding(self, orig_context, bind_context,
|
||||
need_notify, try_again):
|
||||
need_notify, try_again,
|
||||
update_binding_levels=True):
|
||||
port_id = orig_context.current['id']
|
||||
plugin_context = orig_context._plugin_context
|
||||
orig_binding = orig_context._binding
|
||||
@ -584,10 +585,11 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
else:
|
||||
cur_context_binding.vif_type = new_binding.vif_type
|
||||
cur_context_binding.vif_details = new_binding.vif_details
|
||||
db.clear_binding_levels(plugin_context, port_id,
|
||||
cur_binding.host)
|
||||
db.set_binding_levels(plugin_context,
|
||||
bind_context._binding_levels)
|
||||
if update_binding_levels:
|
||||
db.clear_binding_levels(plugin_context, port_id,
|
||||
cur_binding.host)
|
||||
db.set_binding_levels(plugin_context,
|
||||
bind_context._binding_levels)
|
||||
# refresh context with a snapshot of updated state
|
||||
cur_context._binding = driver_context.InstanceSnapshot(
|
||||
cur_context_binding)
|
||||
@ -1375,7 +1377,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
network = self.get_network(context, original_port['network_id'])
|
||||
need_port_update_notify |= self._update_extra_dhcp_opts_on_port(
|
||||
context, id, port, updated_port)
|
||||
levels = db.get_binding_levels(context, id, binding.host)
|
||||
levels = db.get_binding_level_objs(context, id, binding.host)
|
||||
# one of the operations above may have altered the model call
|
||||
# _make_port_dict again to ensure latest state is reflected so mech
|
||||
# drivers, callback handlers, and the API caller see latest state.
|
||||
@ -1411,8 +1413,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
dist_binding_list = db.get_distributed_port_bindings(context,
|
||||
id)
|
||||
for dist_binding in dist_binding_list:
|
||||
levels = db.get_binding_levels(context, id,
|
||||
dist_binding.host)
|
||||
levels = db.get_binding_level_objs(context, id,
|
||||
dist_binding.host)
|
||||
dist_mech_context = driver_context.PortContext(
|
||||
self, context, updated_port, network,
|
||||
dist_binding, levels, original_port=original_port)
|
||||
@ -1517,7 +1519,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
context, id, host, router_id=device_id)
|
||||
network = self.get_network(context,
|
||||
orig_port['network_id'])
|
||||
levels = db.get_binding_levels(context, id, host)
|
||||
levels = db.get_binding_level_objs(context, id, host)
|
||||
mech_context = driver_context.PortContext(self,
|
||||
context, orig_port, network,
|
||||
binding, levels, original_port=orig_port)
|
||||
@ -1581,8 +1583,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
bindings = db.get_distributed_port_bindings(context,
|
||||
id)
|
||||
for bind in bindings:
|
||||
levels = db.get_binding_levels(context, id,
|
||||
bind.host)
|
||||
levels = db.get_binding_level_objs(context, id, bind.host)
|
||||
kwargs['bind'] = bind
|
||||
kwargs['levels'] = levels
|
||||
registry.notify(resources.PORT, events.PRECOMMIT_DELETE,
|
||||
@ -1592,8 +1593,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
self.mechanism_manager.delete_port_precommit(mech_context)
|
||||
bound_mech_contexts.append(mech_context)
|
||||
else:
|
||||
levels = db.get_binding_levels(context, id,
|
||||
binding.host)
|
||||
levels = db.get_binding_level_objs(context, id, binding.host)
|
||||
kwargs['bind'] = None
|
||||
kwargs['levels'] = levels
|
||||
registry.notify(resources.PORT, events.PRECOMMIT_DELETE,
|
||||
@ -1669,8 +1669,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
LOG.error("Binding info for DVR port %s not found",
|
||||
port_id)
|
||||
return None
|
||||
levels = db.get_binding_levels(plugin_context,
|
||||
port_db.id, host)
|
||||
levels = db.get_binding_level_objs(
|
||||
plugin_context, port_db.id, host)
|
||||
port_context = driver_context.PortContext(
|
||||
self, plugin_context, port, network, binding, levels)
|
||||
else:
|
||||
@ -1685,8 +1685,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
"it might have been deleted already.",
|
||||
port_id)
|
||||
return
|
||||
levels = db.get_binding_levels(plugin_context, port_db.id,
|
||||
binding.host)
|
||||
levels = db.get_binding_level_objs(
|
||||
plugin_context, port_db.id, binding.host)
|
||||
port_context = driver_context.PortContext(
|
||||
self, plugin_context, port, network, binding, levels)
|
||||
|
||||
@ -1811,7 +1811,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
binding = p_utils.get_port_binding_by_status_and_host(
|
||||
port.port_bindings, const.ACTIVE, raise_if_not_found=True,
|
||||
port_id=port_id)
|
||||
levels = db.get_binding_levels(context, port.id, binding.host)
|
||||
levels = db.get_binding_level_objs(
|
||||
context, port.id, binding.host)
|
||||
mech_context = driver_context.PortContext(
|
||||
self, context, updated_port, network, binding, levels,
|
||||
original_port=original_port)
|
||||
@ -1840,7 +1841,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
port.status = db.generate_distributed_port_status(context,
|
||||
port['id'])
|
||||
updated_port = self._make_port_dict(port)
|
||||
levels = db.get_binding_levels(context, port_id, host)
|
||||
levels = db.get_binding_level_objs(context, port_id, host)
|
||||
mech_context = (driver_context.PortContext(
|
||||
self, context, updated_port, network,
|
||||
binding, levels, original_port=original_port))
|
||||
@ -2184,8 +2185,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
raise n_exc.PortBindingNotFound(port_id=port_id, host=host)
|
||||
network = self.get_network(context, port_db['network_id'])
|
||||
port_dict = self._make_port_dict(port_db)
|
||||
levels = db.get_binding_levels(context, port_id,
|
||||
active_binding.host)
|
||||
levels = db.get_binding_level_objs(context, port_id,
|
||||
active_binding.host)
|
||||
original_context = driver_context.PortContext(self, context,
|
||||
port_dict, network,
|
||||
active_binding,
|
||||
@ -2197,15 +2198,15 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
context, port_dict['id'],
|
||||
{port_def.RESOURCE_NAME:
|
||||
{'status': const.PORT_STATUS_DOWN}})
|
||||
levels = db.get_binding_levels(context, port_id,
|
||||
inactive_binding.host)
|
||||
levels = db.get_binding_level_objs(context, port_id,
|
||||
inactive_binding.host)
|
||||
bind_context = driver_context.PortContext(self, context, port_dict,
|
||||
network,
|
||||
inactive_binding, levels)
|
||||
for count in range(MAX_BIND_TRIES):
|
||||
cur_context, _, try_again = self._commit_port_binding(
|
||||
original_context, bind_context, need_notify=True,
|
||||
try_again=True)
|
||||
try_again=True, update_binding_levels=False)
|
||||
if not try_again:
|
||||
self.notifier.binding_deactivate(context, port_id,
|
||||
active_binding.host,
|
||||
|
@ -199,6 +199,7 @@ class TestCacheBackedPluginApi(base.BaseTestCase):
|
||||
profile={})],
|
||||
binding_levels=[ports.PortBindingLevel(port_id=self._port_id,
|
||||
host='host1',
|
||||
level=0,
|
||||
segment=self._segment)])
|
||||
|
||||
def test__legacy_notifier_resource_delete(self):
|
||||
|
@ -197,9 +197,6 @@ class PortBindingLevelIfaceObjTestCase(
|
||||
super(PortBindingLevelIfaceObjTestCase, self).setUp()
|
||||
self.pager_map[self._test_class.obj_name()] = (
|
||||
obj_base.Pager(sorts=[('port_id', True), ('level', True)]))
|
||||
self.pager_map[network.NetworkSegment.obj_name()] = (
|
||||
obj_base.Pager(
|
||||
sorts=[('network_id', True), ('segment_index', True)]))
|
||||
|
||||
|
||||
class PortBindingLevelDbObjectTestCase(
|
||||
@ -232,10 +229,13 @@ class PortDbObjectTestCase(obj_test_base.BaseDbObjectTestCase,
|
||||
def setUp(self):
|
||||
super(PortDbObjectTestCase, self).setUp()
|
||||
network_id = self._create_test_network_id()
|
||||
segment_id = self._create_test_segment_id(network_id)
|
||||
subnet_id = self._create_test_subnet_id(network_id)
|
||||
self.update_obj_fields(
|
||||
{'network_id': network_id,
|
||||
'fixed_ips': {'subnet_id': subnet_id, 'network_id': network_id}})
|
||||
'fixed_ips': {'subnet_id': subnet_id,
|
||||
'network_id': network_id},
|
||||
'binding_levels': {'segment_id': segment_id}})
|
||||
|
||||
def test_security_group_ids(self):
|
||||
groups = []
|
||||
|
@ -858,7 +858,7 @@ class TestMl2PortsV2(test_plugin.TestPortsV2, Ml2PluginV2TestCase):
|
||||
ctx = context.get_admin_context()
|
||||
plugin = directory.get_plugin()
|
||||
with self.port() as port:
|
||||
with mock.patch.object(ml2_db, 'get_binding_levels',
|
||||
with mock.patch.object(ml2_db, 'get_binding_level_objs',
|
||||
return_value=[]) as mock_gbl:
|
||||
port_id = port['port']['id']
|
||||
short_id = port_id[:11]
|
||||
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
deprecations:
|
||||
- |
|
||||
Function ``get_binding_levels`` from ``neutron.plugins.ml2.db`` module is
|
||||
deprecated and will be removed in the future.
|
||||
New function ``get_binding_levels_objs`` should be used instead.
|
||||
This new function returns ``PortBindingLevel`` OVO objects.
|
Loading…
x
Reference in New Issue
Block a user