Merge "Fixes Hyper-V agent port disconnect issue" into stable/juno
This commit is contained in:
commit
61044f835b
|
@ -310,7 +310,7 @@ class HyperVNeutronAgent(n_rpc.RpcCallback):
|
|||
self._utils.enable_port_metrics_collection(port_id)
|
||||
self._port_metric_retries[port_id] = CONF.AGENT.metrics_max_retries
|
||||
|
||||
def _port_unbound(self, port_id):
|
||||
def _port_unbound(self, port_id, vnic_deleted=False):
|
||||
(net_uuid, map) = self._get_network_vswitch_map_by_port_id(port_id)
|
||||
if net_uuid not in self._network_vswitch_map:
|
||||
LOG.info(_('Network %s is not avalailable on this agent'),
|
||||
|
@ -318,7 +318,8 @@ class HyperVNeutronAgent(n_rpc.RpcCallback):
|
|||
return
|
||||
|
||||
LOG.debug(_("Unbinding port %s"), port_id)
|
||||
self._utils.disconnect_switch_port(map['vswitch_name'], port_id, True)
|
||||
self._utils.disconnect_switch_port(map['vswitch_name'], port_id,
|
||||
vnic_deleted, True)
|
||||
|
||||
if not map['ports']:
|
||||
self._reclaim_local_network(net_uuid)
|
||||
|
@ -417,7 +418,7 @@ class HyperVNeutronAgent(n_rpc.RpcCallback):
|
|||
dict(device=device, e=e))
|
||||
resync = True
|
||||
continue
|
||||
self._port_unbound(device)
|
||||
self._port_unbound(device, vnic_deleted=True)
|
||||
return resync
|
||||
|
||||
def _process_network_ports(self, port_info):
|
||||
|
|
|
@ -173,7 +173,7 @@ class HyperVUtils(object):
|
|||
pass
|
||||
|
||||
def disconnect_switch_port(
|
||||
self, vswitch_name, switch_port_name, delete_port):
|
||||
self, vswitch_name, switch_port_name, vnic_deleted, delete_port):
|
||||
"""Disconnects the switch port."""
|
||||
switch_svc = self._conn.Msvm_VirtualSwitchManagementService()[0]
|
||||
switch_port_path = self._get_switch_port_path_by_name(
|
||||
|
@ -182,16 +182,17 @@ class HyperVUtils(object):
|
|||
# Port not found. It happens when the VM was already deleted.
|
||||
return
|
||||
|
||||
(ret_val, ) = switch_svc.DisconnectSwitchPort(
|
||||
SwitchPort=switch_port_path)
|
||||
if ret_val != 0:
|
||||
data = {'switch_port_name': switch_port_name,
|
||||
'vswitch_name': vswitch_name,
|
||||
'ret_val': ret_val}
|
||||
raise HyperVException(
|
||||
msg=_('Failed to disconnect port %(switch_port_name)s '
|
||||
'from switch %(vswitch_name)s '
|
||||
'with error %(ret_val)s') % data)
|
||||
if not vnic_deleted:
|
||||
(ret_val, ) = switch_svc.DisconnectSwitchPort(
|
||||
SwitchPort=switch_port_path)
|
||||
if ret_val != 0:
|
||||
data = {'switch_port_name': switch_port_name,
|
||||
'vswitch_name': vswitch_name,
|
||||
'ret_val': ret_val}
|
||||
raise HyperVException(
|
||||
msg=_('Failed to disconnect port %(switch_port_name)s '
|
||||
'from switch %(vswitch_name)s '
|
||||
'with error %(ret_val)s') % data)
|
||||
if delete_port:
|
||||
(ret_val, ) = switch_svc.DeleteSwitchPort(
|
||||
SwitchPort=switch_port_path)
|
||||
|
|
|
@ -113,7 +113,7 @@ class HyperVUtilsV2(utils.HyperVUtils):
|
|||
self._check_job_status(ret_val, job_path)
|
||||
|
||||
def disconnect_switch_port(
|
||||
self, vswitch_name, switch_port_name, delete_port):
|
||||
self, vswitch_name, switch_port_name, vnic_deleted, delete_port):
|
||||
"""Disconnects the switch port."""
|
||||
sw_port, found = self._get_switch_port_allocation(switch_port_name)
|
||||
if not sw_port:
|
||||
|
|
|
@ -34,6 +34,77 @@ class HyperVUtilsTestCase(base.BaseTestCase):
|
|||
self.utils = utils.HyperVUtils()
|
||||
self.utils._wmi_conn = mock.MagicMock()
|
||||
|
||||
@mock.patch.object(utils.HyperVUtils, "_get_switch_port_path_by_name")
|
||||
def test_disconnect_switch_port_not_found(self, mock_get_swp_path):
|
||||
mock_svc = self.utils._conn.Msvm_VirtualSwitchManagementService()[0]
|
||||
mock_get_swp_path.return_value = None
|
||||
|
||||
self.utils.disconnect_switch_port(mock.sentinel.FAKE_VSWITCH_NAME,
|
||||
mock.sentinel.FAKE_PORT_NAME,
|
||||
True, True)
|
||||
self.assertFalse(mock_svc.DisconnectSwitchPort.called)
|
||||
self.assertFalse(mock_svc.DeleteSwitchPort.called)
|
||||
|
||||
@mock.patch.object(utils.HyperVUtils, "_get_switch_port_path_by_name")
|
||||
def test_disconnect_switch_port(self, mock_get_swp_path):
|
||||
mock_svc = self.utils._conn.Msvm_VirtualSwitchManagementService()[0]
|
||||
mock_svc.DisconnectSwitchPort.return_value = (0, )
|
||||
mock_svc.DeleteSwitchPort.return_value = (0, )
|
||||
mock_get_swp_path.return_value = mock.sentinel.FAKE_PATH
|
||||
|
||||
self.utils.disconnect_switch_port(mock.sentinel.FAKE_VSWITCH_NAME,
|
||||
mock.sentinel.FAKE_PORT_NAME,
|
||||
False, True)
|
||||
mock_svc.DisconnectSwitchPort.assert_called_once_with(
|
||||
SwitchPort=mock.sentinel.FAKE_PATH)
|
||||
mock_svc.DeleteSwitchPort.assert_called_once_with(
|
||||
SwitchPort=mock.sentinel.FAKE_PATH)
|
||||
|
||||
@mock.patch.object(utils.HyperVUtils, "_get_switch_port_path_by_name")
|
||||
def test_disconnect_switch_port_disconnected(self, mock_get_swp_path):
|
||||
mock_svc = self.utils._conn.Msvm_VirtualSwitchManagementService()[0]
|
||||
mock_svc.DeleteSwitchPort.return_value = (0, )
|
||||
mock_get_swp_path.return_value = mock.sentinel.FAKE_PATH
|
||||
|
||||
self.utils.disconnect_switch_port(mock.sentinel.FAKE_VSWITCH_NAME,
|
||||
mock.sentinel.FAKE_PORT_NAME,
|
||||
True, True)
|
||||
|
||||
self.assertFalse(mock_svc.DisconnectSwitchPort.called)
|
||||
mock_svc.DeleteSwitchPort.assert_called_once_with(
|
||||
SwitchPort=mock.sentinel.FAKE_PATH)
|
||||
|
||||
@mock.patch.object(utils.HyperVUtils, "_get_switch_port_path_by_name")
|
||||
def test_disconnect_switch_port_disconnect_ex(self, mock_get_swp_path):
|
||||
mock_svc = self.utils._conn.Msvm_VirtualSwitchManagementService()[0]
|
||||
mock_svc.DisconnectSwitchPort.return_value = (
|
||||
mock.sentinel.FAKE_VAL, )
|
||||
mock_get_swp_path.return_value = mock.sentinel.FAKE_PATH
|
||||
|
||||
self.assertRaises(utils.HyperVException,
|
||||
self.utils.disconnect_switch_port,
|
||||
mock.sentinel.FAKE_VSWITCH_NAME,
|
||||
mock.sentinel.FAKE_PORT_NAME,
|
||||
False, True)
|
||||
|
||||
mock_svc.DisconnectSwitchPort.assert_called_once_with(
|
||||
SwitchPort=mock.sentinel.FAKE_PATH)
|
||||
|
||||
@mock.patch.object(utils.HyperVUtils, "_get_switch_port_path_by_name")
|
||||
def test_disconnect_switch_port_delete_ex(self, mock_get_swp_path):
|
||||
mock_svc = self.utils._conn.Msvm_VirtualSwitchManagementService()[0]
|
||||
mock_svc.DeleteSwitchPort.return_value = (mock.sentinel.FAKE_VAL, )
|
||||
mock_get_swp_path.return_value = mock.sentinel.FAKE_PATH
|
||||
|
||||
self.assertRaises(utils.HyperVException,
|
||||
self.utils.disconnect_switch_port,
|
||||
mock.sentinel.FAKE_VSWITCH_NAME,
|
||||
mock.sentinel.FAKE_PORT_NAME,
|
||||
True, True)
|
||||
|
||||
mock_svc.DeleteSwitchPort.assert_called_once_with(
|
||||
SwitchPort=mock.sentinel.FAKE_PATH)
|
||||
|
||||
def test_get_vswitch_external_port(self):
|
||||
ext_port = mock.MagicMock()
|
||||
self.utils._conn.Msvm_ExternalEthernetPort.return_value = [ext_port]
|
||||
|
|
|
@ -161,7 +161,7 @@ class TestHyperVUtilsV2(base.BaseTestCase):
|
|||
|
||||
self._utils.disconnect_switch_port(self._FAKE_VSWITCH_NAME,
|
||||
self._FAKE_PORT_NAME,
|
||||
delete_port)
|
||||
True, delete_port)
|
||||
|
||||
if delete_port:
|
||||
self._utils._remove_virt_resource.assert_called_with(mock_sw_port)
|
||||
|
|
Loading…
Reference in New Issue