]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Add rollback for Cisco plugin update_port failure
authorDane LeBlanc <leblancd@cisco.com>
Fri, 17 May 2013 15:42:59 +0000 (11:42 -0400)
committerDane LeBlanc <leblancd@cisco.com>
Fri, 31 May 2013 20:38:18 +0000 (16:38 -0400)
Fixes bug 1174433

This fix adds a rollback of the OVS plugin update_port operation
following a failure to update the port in the Cisco Nexus sub-plugin.

Also, this fix removes an unneccessary call to the Nexus sub-plugin's
update_network method within the Cisco plugin model layer's
update_network method (as well as the associated argument setup).
The Nexus sub-plugin's update_network is a no-op, so there's no
need to call it.

Change-Id: I10cba0d7f1d632c7f77eb6c4a94ea82b958bc6a2

quantum/plugins/cisco/models/virt_phy_sw_v2.py
quantum/tests/unit/cisco/test_network_plugin.py

index 835d72961820fdfbdf54bac5f6558d46ddbc44a4..fe0bd91782aa4439170d2c15b5788a3986067f2f 100644 (file)
@@ -21,6 +21,7 @@
 
 import inspect
 import logging
+import sys
 
 from novaclient.v1_1 import client as nova_client
 from oslo.config import cfg
@@ -213,31 +214,20 @@ class VirtualPhysicalSwitchModelV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
 
         Perform this operation in the context of the configured device
         plugins.
+
+        Note that the Nexus sub-plugin does not need to be notified
+        (and the Nexus switch does not need to be [re]configured)
+        for an update network operation because the Nexus sub-plugin
+        is agnostic of all network-level attributes except the
+        segmentation ID. Furthermore, updating of the segmentation ID
+        is not supported by the OVS plugin since it is considered a
+        provider attribute, so it is not supported by this method.
         """
         LOG.debug(_("update_network() called"))
         args = [context, id, network]
         ovs_output = self._invoke_plugin_per_device(const.VSWITCH_PLUGIN,
                                                     self._func_name(),
                                                     args)
-        try:
-            vlan_id = self._get_segmentation_id(ovs_output[0]['id'])
-            if not self._validate_vlan_id(vlan_id):
-                return ovs_output[0]
-            vlan_ids = self._get_all_segmentation_ids()
-            args = [ovs_output[0]['tenant_id'], id, {'vlan_id': vlan_id},
-                    {'net_admin_state': ovs_output[0]['admin_state_up']},
-                    {'vlan_ids': vlan_ids}]
-            self._invoke_plugin_per_device(const.NEXUS_PLUGIN,
-                                           self._func_name(),
-                                           args)
-        except Exception:
-            # TODO(dane): The call to the nexus plugin update network
-            # failed, so the OVS plugin should be rolled back, that is,
-            # "re-updated" back to the original network config.
-            LOG.exception(_("Unable to update network '%s' on Nexus switch"),
-                          network['network']['name'])
-            raise
-
         return ovs_output[0]
 
     def delete_network(self, context, id):
@@ -304,9 +294,10 @@ class VirtualPhysicalSwitchModelV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
                 self._invoke_nexus_for_net_create(
                     context, tenant_id, net_id, instance_id)
 
-        except Exception as e:
+        except Exception:
             # Create network on the Nexus plugin has failed, so we need
             # to rollback the port creation on the VSwitch plugin.
+            exc_info = sys.exc_info()
             try:
                 id = ovs_output[0]['id']
                 args = [context, id]
@@ -316,7 +307,7 @@ class VirtualPhysicalSwitchModelV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
                     args)
             finally:
                 # Re-raise the original exception
-                raise e
+                raise exc_info[0], exc_info[1], exc_info[2]
         return ovs_output[0]
 
     def get_port(self, context, id, fields=None):
@@ -354,12 +345,19 @@ class VirtualPhysicalSwitchModelV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
 
             return ovs_output[0]
         except Exception:
-            # TODO(dane): The call to the nexus plugin create network
-            # failed, so the OVS plugin should be rolled back, that is,
-            # "re-updated" back to the original port config.
-            LOG.exception(_("Unable to update port '%s' on Nexus switch"),
-                          port['port']['name'])
-            raise
+            exc_info = sys.exc_info()
+            LOG.error(_("Unable to update port '%s' on Nexus switch"),
+                      old_port['name'], exc_info=exc_info)
+            try:
+                # Roll back vSwitch plugin to original port attributes.
+                args = [context, id, {'port': old_port}]
+                ovs_output = self._invoke_plugin_per_device(
+                    const.VSWITCH_PLUGIN,
+                    self._func_name(),
+                    args)
+            finally:
+                # Re-raise the original exception
+                raise exc_info[0], exc_info[1], exc_info[2]
 
     def delete_port(self, context, id):
         """Delete port.
@@ -379,7 +377,8 @@ class VirtualPhysicalSwitchModelV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
             ovs_output = self._invoke_plugin_per_device(const.VSWITCH_PLUGIN,
                                                         self._func_name(),
                                                         args)
-        except Exception as e:
+        except Exception:
+            exc_info = sys.exc_info()
             # Roll back the delete port on the Nexus plugin
             try:
                 tenant_id = port['tenant_id']
@@ -389,7 +388,7 @@ class VirtualPhysicalSwitchModelV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
                                                   net_id, instance_id)
             finally:
                 # Raise the original exception.
-                raise e
+                raise exc_info[0], exc_info[1], exc_info[2]
 
         return ovs_output[0]
 
index d1b8de8f89f339744c0a4d1c68756be5a355a4eb..bca3e83cc00f997a2713b93d177eb88e7188c605 100644 (file)
@@ -23,6 +23,7 @@ import webob.exc as wexc
 from quantum.api.v2 import base
 from quantum.common import exceptions as q_exc
 from quantum import context
+from quantum.db import db_base_plugin_v2 as base_plugin
 from quantum.db import l3_db
 from quantum.manager import QuantumManager
 from quantum.plugins.cisco.common import cisco_constants as const
@@ -407,6 +408,41 @@ class TestCiscoPortsV2(CiscoNetworkPluginV2TestCase,
                 )
                 self._assertExpectedHTTP(res.status_int, KeyError)
 
+    def test_model_update_port_rollback(self):
+        """Test for proper rollback for Cisco model layer update port failure.
+
+        Test that the vSwitch plugin port configuration is rolled back
+        (restored) by the Cisco plugin model layer when there is a
+        failure in the Nexus sub-plugin for an update port operation.
+
+        """
+        with self.port(fmt=self.fmt) as orig_port:
+
+            inserted_exc = ValueError
+            with mock.patch.object(
+                virt_phy_sw_v2.VirtualPhysicalSwitchModelV2,
+                '_invoke_nexus_for_net_create',
+                side_effect=inserted_exc):
+
+                # Send an update port request with a new device ID
+                device_id = "00fff4d0-e4a8-4a3a-8906-4c4cdafb59f1"
+                if orig_port['port']['device_id'] == device_id:
+                    device_id = "600df00d-e4a8-4a3a-8906-feed600df00d"
+                data = {'port': {'device_id': device_id}}
+                port_id = orig_port['port']['id']
+                req = self.new_update_request('ports', data, port_id)
+                res = req.get_response(self.api)
+
+                # Sanity check failure result code
+                self._assertExpectedHTTP(res.status_int, inserted_exc)
+
+                # Check that the port still has the original device ID
+                plugin = base_plugin.QuantumDbPluginV2()
+                ctx = context.get_admin_context()
+                db_port = plugin._get_port(ctx, port_id)
+                self.assertEqual(db_port['device_id'],
+                                 orig_port['port']['device_id'])
+
     def test_model_delete_port_rollback(self):
         """Test for proper rollback for OVS plugin delete port failure.