NSX|V: don't throw exception when same vnic is configured
In the event of a nova retry we should not throw an exception for for a port update Change-Id: Ic4df033952e3dddd170e0fb7b57499750a6155b0 Closes-bug: #1606809
This commit is contained in:
parent
91fecee67c
commit
e51421f5ca
@ -18,6 +18,7 @@ from sqlalchemy.orm import exc
|
|||||||
from neutron.api.v2 import attributes as attr
|
from neutron.api.v2 import attributes as attr
|
||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
|
|
||||||
|
from oslo_db import exception as db_exc
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
from vmware_nsx.db import nsxv_models
|
from vmware_nsx.db import nsxv_models
|
||||||
@ -47,7 +48,14 @@ class VnicIndexDbMixin(object):
|
|||||||
except exc.NoResultFound:
|
except exc.NoResultFound:
|
||||||
LOG.debug("No record in DB for vnic-index of port %s", port_id)
|
LOG.debug("No record in DB for vnic-index of port %s", port_id)
|
||||||
|
|
||||||
def _set_port_vnic_index_mapping(self, context, port_id, device_id, index):
|
def _get_mappings_for_device_id(self, context, device_id):
|
||||||
|
session = context.session
|
||||||
|
mappings = (session.query(nsxv_models.NsxvPortIndexMapping).
|
||||||
|
filter_by(device_id=device_id))
|
||||||
|
return mappings
|
||||||
|
|
||||||
|
def _create_port_vnic_index_mapping(self, context, port_id,
|
||||||
|
device_id, index):
|
||||||
"""Save the port vnic-index to DB."""
|
"""Save the port vnic-index to DB."""
|
||||||
session = context.session
|
session = context.session
|
||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
@ -55,6 +63,38 @@ class VnicIndexDbMixin(object):
|
|||||||
port_id=port_id, device_id=device_id, index=index)
|
port_id=port_id, device_id=device_id, index=index)
|
||||||
session.add(index_mapping_model)
|
session.add(index_mapping_model)
|
||||||
|
|
||||||
|
def _update_port_vnic_index_mapping(self, context, port_id,
|
||||||
|
device_id, index):
|
||||||
|
session = context.session
|
||||||
|
# delete original entry
|
||||||
|
query = (session.query(nsxv_models.NsxvPortIndexMapping).
|
||||||
|
filter_by(device_id=device_id, index=index))
|
||||||
|
query.delete()
|
||||||
|
# create a new one
|
||||||
|
self._create_port_vnic_index_mapping(context, port_id, device_id,
|
||||||
|
index)
|
||||||
|
|
||||||
|
def _set_port_vnic_index_mapping(self, context, port_id, device_id, index):
|
||||||
|
"""Save the port vnic-index to DB."""
|
||||||
|
try:
|
||||||
|
self._create_port_vnic_index_mapping(context, port_id,
|
||||||
|
device_id, index)
|
||||||
|
except db_exc.DBDuplicateEntry:
|
||||||
|
# A retry for the nova scheduling could result in this error.
|
||||||
|
LOG.debug("Entry already exists for %s %s %s", port_id,
|
||||||
|
device_id, index)
|
||||||
|
mappings = self._get_mappings_for_device_id(context, device_id)
|
||||||
|
for mapping in mappings:
|
||||||
|
if (mapping['port_id'] != port_id and
|
||||||
|
mapping['index'] == index):
|
||||||
|
# a new port is using this device - update!
|
||||||
|
self._update_port_vnic_index_mapping(context, port_id,
|
||||||
|
device_id, index)
|
||||||
|
return
|
||||||
|
if (mapping['port_id'] == port_id and
|
||||||
|
mapping['index'] != index):
|
||||||
|
raise
|
||||||
|
|
||||||
def _delete_port_vnic_index_mapping(self, context, port_id):
|
def _delete_port_vnic_index_mapping(self, context, port_id):
|
||||||
"""Delete the port vnic-index association."""
|
"""Delete the port vnic-index association."""
|
||||||
session = context.session
|
session = context.session
|
||||||
|
@ -93,16 +93,46 @@ class VnicIndexDbTestCase(test_db_plugin.NeutronDbPluginV2TestCase):
|
|||||||
self.assertRaises(d_exc.DBDuplicateEntry,
|
self.assertRaises(d_exc.DBDuplicateEntry,
|
||||||
plugin._set_port_vnic_index_mapping,
|
plugin._set_port_vnic_index_mapping,
|
||||||
context, port_id, device_id, 1)
|
context, port_id, device_id, 1)
|
||||||
# Only one Port can be associated with a specific index on a device
|
|
||||||
self.assertRaises(d_exc.DBDuplicateEntry,
|
|
||||||
plugin._set_port_vnic_index_mapping,
|
|
||||||
context, _uuid(), device_id, vnic_index)
|
|
||||||
# Check that the call for _delete_port_vnic_index remove the row from
|
# Check that the call for _delete_port_vnic_index remove the row from
|
||||||
# the table
|
# the table
|
||||||
|
|
||||||
# TODO(kobis): deletion was removed from port - fix this assert
|
# TODO(kobis): deletion was removed from port - fix this assert
|
||||||
# self.assertIsNone(plugin._get_port_vnic_index(context, port_id))
|
# self.assertIsNone(plugin._get_port_vnic_index(context, port_id))
|
||||||
|
|
||||||
|
def test_vnic_index_db_duplicate(self):
|
||||||
|
plugin = manager.NeutronManager.get_plugin()
|
||||||
|
vnic_index = 2
|
||||||
|
device_id = _uuid()
|
||||||
|
context = neutron_context.get_admin_context()
|
||||||
|
with self.port(device_id=device_id,
|
||||||
|
device_owner='compute:None') as port:
|
||||||
|
port_id = port['port']['id']
|
||||||
|
res = self._port_index_update(port_id, vnic_index)
|
||||||
|
self.assertEqual(res['port'][vnicidx.VNIC_INDEX], vnic_index)
|
||||||
|
plugin._set_port_vnic_index_mapping(context, port_id, device_id,
|
||||||
|
vnic_index)
|
||||||
|
|
||||||
|
def test_vnic_index_db_duplicate_new_port(self):
|
||||||
|
plugin = manager.NeutronManager.get_plugin()
|
||||||
|
vnic_index = 2
|
||||||
|
device_id = _uuid()
|
||||||
|
context = neutron_context.get_admin_context()
|
||||||
|
with self.port(device_id=device_id,
|
||||||
|
device_owner='compute:None') as port:
|
||||||
|
with self.port(device_id=device_id,
|
||||||
|
device_owner='compute:None') as port1:
|
||||||
|
port_id = port['port']['id']
|
||||||
|
res = self._port_index_update(port_id, vnic_index)
|
||||||
|
self.assertEqual(res['port'][vnicidx.VNIC_INDEX], vnic_index)
|
||||||
|
port_id1 = port1['port']['id']
|
||||||
|
plugin._set_port_vnic_index_mapping(context, port_id1,
|
||||||
|
device_id, 2)
|
||||||
|
self.assertIsNone(plugin._get_port_vnic_index(context,
|
||||||
|
port_id))
|
||||||
|
self.assertEqual(vnic_index,
|
||||||
|
plugin._get_port_vnic_index(context,
|
||||||
|
port_id1))
|
||||||
|
|
||||||
|
|
||||||
class TestVnicIndex(VnicIndexDbTestCase):
|
class TestVnicIndex(VnicIndexDbTestCase):
|
||||||
pass
|
pass
|
||||||
|
Loading…
Reference in New Issue
Block a user