import inspect
import logging
+import sys
from novaclient.v1_1 import client as nova_client
from oslo.config import cfg
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):
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]
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):
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.
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']
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]
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
)
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.