From 5bdbfc2e52ac8d97e8421d0f8c74993de08191f5 Mon Sep 17 00:00:00 2001 From: armando-migliaccio Date: Mon, 6 Jan 2014 04:42:30 -0800 Subject: [PATCH] VMware NSX: Fix db integrity error on dhcp port operations If the dhcp port and network disappear, ensure that the integrity constraint violation that results from inserting the neutron/nsx port mapping to the DB does not propagate the exception all the way through, but instead is caught and handled correctly. Closes-bug: #1265472 Change-Id: I3ae072729d579def0bd9658241eda1011a3dcfa0 --- neutron/plugins/nicira/NeutronPlugin.py | 18 ++++++++++++++++++ .../tests/unit/nicira/test_nicira_plugin.py | 13 +++++++++++++ 2 files changed, 31 insertions(+) diff --git a/neutron/plugins/nicira/NeutronPlugin.py b/neutron/plugins/nicira/NeutronPlugin.py index 671f6743d1..a44b73d8df 100644 --- a/neutron/plugins/nicira/NeutronPlugin.py +++ b/neutron/plugins/nicira/NeutronPlugin.py @@ -24,6 +24,7 @@ import logging import os from oslo.config import cfg +from sqlalchemy import exc as sql_exc from sqlalchemy.orm import exc as sa_exc import webob.exc @@ -56,6 +57,7 @@ from neutron.extensions import portbindings as pbin from neutron.extensions import portsecurity as psec from neutron.extensions import providernet as pnet from neutron.extensions import securitygroup as ext_sg +from neutron.openstack.common.db import exception as db_exc from neutron.openstack.common import excutils from neutron.openstack.common import lockutils from neutron.plugins.common import constants as plugin_const @@ -490,6 +492,22 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin, context, port_data['id'], selected_lswitch and selected_lswitch['uuid'], lport and lport['uuid']) + except db_exc.DBError as e: + if (port_data['device_owner'] == constants.DEVICE_OWNER_DHCP and + isinstance(e.inner_exception, sql_exc.IntegrityError)): + msg = (_("Concurrent network deletion detected; Back-end Port " + "%(nsx_id)s creation to be rolled back for Neutron " + "port: %(neutron_id)s") + % {'nsx_id': lport['uuid'], + 'neutron_id': port_data['id']}) + LOG.warning(msg) + if selected_lswitch and lport: + try: + nvplib.delete_port(self.cluster, + selected_lswitch['uuid'], + lport['uuid']) + except q_exc.NotFound: + LOG.debug(_("NSX Port %s already gone"), lport['uuid']) def _nvp_delete_port(self, context, port_data): # FIXME(salvatore-orlando): On the NVP platform we do not really have diff --git a/neutron/tests/unit/nicira/test_nicira_plugin.py b/neutron/tests/unit/nicira/test_nicira_plugin.py index 544cbd5868..075a3501fd 100644 --- a/neutron/tests/unit/nicira/test_nicira_plugin.py +++ b/neutron/tests/unit/nicira/test_nicira_plugin.py @@ -20,6 +20,7 @@ import contextlib import mock import netaddr from oslo.config import cfg +from sqlalchemy import exc as sql_exc import webob.exc from neutron.api.v2 import attributes @@ -36,6 +37,7 @@ from neutron.extensions import providernet as pnet from neutron.extensions import securitygroup as secgrp from neutron import manager from neutron.manager import NeutronManager +from neutron.openstack.common.db import exception as db_exc from neutron.openstack.common import uuidutils from neutron.plugins.nicira.common import exceptions as nvp_exc from neutron.plugins.nicira.common import sync @@ -251,6 +253,17 @@ class TestNiciraPortsV2(NiciraPluginV2TestCase, webob.exc.HTTPInternalServerError.code) self._verify_no_orphan_left(net_id) + def test_create_port_db_error_no_orphan_left(self): + db_exception = db_exc.DBError( + inner_exception=sql_exc.IntegrityError(mock.ANY, + mock.ANY, + mock.ANY)) + with mock.patch.object(nicira_db, 'add_neutron_nsx_port_mapping', + side_effect=db_exception): + with self.network() as net: + with self.port(device_owner='network:dhcp'): + self._verify_no_orphan_left(net['network']['id']) + def test_create_port_maintenance_returns_503(self): with self.network() as net: with mock.patch.object(nvplib, 'do_request',