Merge "Add rollback for Cisco plugin update_port failure"
This commit is contained in:
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
import inspect
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
|
import sys
|
||||||
|
|
||||||
from novaclient.v1_1 import client as nova_client
|
from novaclient.v1_1 import client as nova_client
|
||||||
from oslo.config import cfg
|
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
|
Perform this operation in the context of the configured device
|
||||||
plugins.
|
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"))
|
LOG.debug(_("update_network() called"))
|
||||||
args = [context, id, network]
|
args = [context, id, network]
|
||||||
ovs_output = self._invoke_plugin_per_device(const.VSWITCH_PLUGIN,
|
ovs_output = self._invoke_plugin_per_device(const.VSWITCH_PLUGIN,
|
||||||
self._func_name(),
|
self._func_name(),
|
||||||
args)
|
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]
|
return ovs_output[0]
|
||||||
|
|
||||||
def delete_network(self, context, id):
|
def delete_network(self, context, id):
|
||||||
@@ -304,9 +294,10 @@ class VirtualPhysicalSwitchModelV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
|
|||||||
self._invoke_nexus_for_net_create(
|
self._invoke_nexus_for_net_create(
|
||||||
context, tenant_id, net_id, instance_id)
|
context, tenant_id, net_id, instance_id)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
# Create network on the Nexus plugin has failed, so we need
|
# Create network on the Nexus plugin has failed, so we need
|
||||||
# to rollback the port creation on the VSwitch plugin.
|
# to rollback the port creation on the VSwitch plugin.
|
||||||
|
exc_info = sys.exc_info()
|
||||||
try:
|
try:
|
||||||
id = ovs_output[0]['id']
|
id = ovs_output[0]['id']
|
||||||
args = [context, id]
|
args = [context, id]
|
||||||
@@ -316,7 +307,7 @@ class VirtualPhysicalSwitchModelV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
|
|||||||
args)
|
args)
|
||||||
finally:
|
finally:
|
||||||
# Re-raise the original exception
|
# Re-raise the original exception
|
||||||
raise e
|
raise exc_info[0], exc_info[1], exc_info[2]
|
||||||
return ovs_output[0]
|
return ovs_output[0]
|
||||||
|
|
||||||
def get_port(self, context, id, fields=None):
|
def get_port(self, context, id, fields=None):
|
||||||
@@ -354,12 +345,19 @@ class VirtualPhysicalSwitchModelV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
|
|||||||
|
|
||||||
return ovs_output[0]
|
return ovs_output[0]
|
||||||
except Exception:
|
except Exception:
|
||||||
# TODO(dane): The call to the nexus plugin create network
|
exc_info = sys.exc_info()
|
||||||
# failed, so the OVS plugin should be rolled back, that is,
|
LOG.error(_("Unable to update port '%s' on Nexus switch"),
|
||||||
# "re-updated" back to the original port config.
|
old_port['name'], exc_info=exc_info)
|
||||||
LOG.exception(_("Unable to update port '%s' on Nexus switch"),
|
try:
|
||||||
port['port']['name'])
|
# Roll back vSwitch plugin to original port attributes.
|
||||||
raise
|
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):
|
def delete_port(self, context, id):
|
||||||
"""Delete port.
|
"""Delete port.
|
||||||
@@ -379,7 +377,8 @@ class VirtualPhysicalSwitchModelV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
|
|||||||
ovs_output = self._invoke_plugin_per_device(const.VSWITCH_PLUGIN,
|
ovs_output = self._invoke_plugin_per_device(const.VSWITCH_PLUGIN,
|
||||||
self._func_name(),
|
self._func_name(),
|
||||||
args)
|
args)
|
||||||
except Exception as e:
|
except Exception:
|
||||||
|
exc_info = sys.exc_info()
|
||||||
# Roll back the delete port on the Nexus plugin
|
# Roll back the delete port on the Nexus plugin
|
||||||
try:
|
try:
|
||||||
tenant_id = port['tenant_id']
|
tenant_id = port['tenant_id']
|
||||||
@@ -389,7 +388,7 @@ class VirtualPhysicalSwitchModelV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
|
|||||||
net_id, instance_id)
|
net_id, instance_id)
|
||||||
finally:
|
finally:
|
||||||
# Raise the original exception.
|
# Raise the original exception.
|
||||||
raise e
|
raise exc_info[0], exc_info[1], exc_info[2]
|
||||||
|
|
||||||
return ovs_output[0]
|
return ovs_output[0]
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import webob.exc as wexc
|
|||||||
from quantum.api.v2 import base
|
from quantum.api.v2 import base
|
||||||
from quantum.common import exceptions as q_exc
|
from quantum.common import exceptions as q_exc
|
||||||
from quantum import context
|
from quantum import context
|
||||||
|
from quantum.db import db_base_plugin_v2 as base_plugin
|
||||||
from quantum.db import l3_db
|
from quantum.db import l3_db
|
||||||
from quantum.manager import QuantumManager
|
from quantum.manager import QuantumManager
|
||||||
from quantum.plugins.cisco.common import cisco_constants as const
|
from quantum.plugins.cisco.common import cisco_constants as const
|
||||||
@@ -407,6 +408,41 @@ class TestCiscoPortsV2(CiscoNetworkPluginV2TestCase,
|
|||||||
)
|
)
|
||||||
self._assertExpectedHTTP(res.status_int, KeyError)
|
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):
|
def test_model_delete_port_rollback(self):
|
||||||
"""Test for proper rollback for OVS plugin delete port failure.
|
"""Test for proper rollback for OVS plugin delete port failure.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user