from sqlalchemy.orm import exc
+from oslo.db import exception as db_exc
+
from neutron.common import constants as n_const
from neutron.db import api as db_api
from neutron.db import models_v2
def ensure_dvr_port_binding(session, port_id, host, router_id=None):
- # FIXME(armando-migliaccio): take care of LP #1335226
- # DVR ports are slightly different from the others in
- # that binding happens at a later stage via L3 agent
- # therefore we need to keep this logic of creation on
- # missing binding.
- with session.begin(subtransactions=True):
- try:
- record = (session.query(models.DVRPortBinding).
- filter_by(port_id=port_id, host=host).one())
- except exc.NoResultFound:
+ record = (session.query(models.DVRPortBinding).
+ filter_by(port_id=port_id, host=host).first())
+ if record:
+ return record
+
+ try:
+ with session.begin(subtransactions=True):
record = models.DVRPortBinding(
port_id=port_id,
host=host,
cap_port_filter=False,
status=n_const.PORT_STATUS_DOWN)
session.add(record)
- return record
+ return record
+ except db_exc.DBDuplicateEntry:
+ LOG.debug("DVR Port %s already bound", port_id)
+ return (session.query(models.DVRPortBinding).
+ filter_by(port_id=port_id, host=host).one())
def delete_dvr_port_binding(session, port_id, host):
# See the License for the specific language governing permissions and
# limitations under the License.
+import mock
+
+from sqlalchemy.orm import query
+
from neutron import context
from neutron.db import api as db_api
from neutron.db import l3_db
self.ctx.session.add(record)
return record
+ def test_ensure_dvr_port_binding_deals_with_db_duplicate(self):
+ network_id = 'foo_network_id'
+ port_id = 'foo_port_id'
+ router_id = 'foo_router_id'
+ host_id = 'foo_host_id'
+ self._setup_neutron_network(network_id, [port_id])
+ self._setup_dvr_binding(network_id, port_id, router_id, host_id)
+ with mock.patch.object(query.Query, 'first') as query_first:
+ query_first.return_value = []
+ with mock.patch.object(ml2_db.LOG, 'debug') as log_trace:
+ binding = ml2_db.ensure_dvr_port_binding(
+ self.ctx.session, port_id, host_id, router_id)
+ self.assertTrue(query_first.called)
+ self.assertTrue(log_trace.called)
+ self.assertEqual(port_id, binding.port_id)
+
def test_ensure_dvr_port_binding(self):
network_id = 'foo_network_id'
port_id = 'foo_port_id'