Merge "Add rollback for Cisco plugin update_port failure"
This commit is contained in:
commit
ffbe2cd55e
@ -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]
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user