From 7c968936006fa51a8a463482412346a8f71f17dd Mon Sep 17 00:00:00 2001 From: Ravi Kota Date: Sun, 30 Oct 2016 08:48:19 -0400 Subject: [PATCH] Clean up of OVS port on source host post migration After live migration of an instance, as part of the cleanup, the deletion of port from OVS is not happening on source host. With this fix, the OVS port is cleaned up as part of the post live migration on source. Change-Id: I83ac822c39b4dcc023f71d7f3766ceefe52a8022 Closes-Bug: #1637551 --- .../tests/virt/powervm/test_live_migration.py | 12 +++++++ nova_powervm/tests/virt/powervm/test_vif.py | 30 ++++++++++++++-- nova_powervm/virt/powervm/live_migration.py | 4 +++ nova_powervm/virt/powervm/vif.py | 34 +++++++++++++++++++ 4 files changed, 78 insertions(+), 2 deletions(-) diff --git a/nova_powervm/tests/virt/powervm/test_live_migration.py b/nova_powervm/tests/virt/powervm/test_live_migration.py index 64705b01..3fe4360b 100644 --- a/nova_powervm/tests/virt/powervm/test_live_migration.py +++ b/nova_powervm/tests/virt/powervm/test_live_migration.py @@ -298,3 +298,15 @@ class TestLPM(test.TestCase): self.lpmsrc.lpar_w = mock.Mock() self.lpmsrc.migration_recover() mock_mig_recover.called_once_with(self.lpmsrc.lpar_w, force=True) + + @mock.patch('nova_powervm.virt.powervm.vif.post_live_migrate_at_source') + def test_post_live_migration_at_source(self, mock_vif_post_lpm_at_source): + network_infos = [{'devname': 'tap-dev1', 'address': 'mac-addr1', + 'network': {'bridge': 'br-int'}, 'id': 'vif_id_1'}, + {'devname': 'tap-dev2', 'address': 'mac-addr2', + 'network': {'bridge': 'br-int'}, 'id': 'vif_id_2'}] + self.lpmsrc.post_live_migration_at_source(network_infos) + # Assertions + for network_info in network_infos: + mock_vif_post_lpm_at_source.assert_any_call(mock.ANY, mock.ANY, + mock.ANY, network_info) diff --git a/nova_powervm/tests/virt/powervm/test_vif.py b/nova_powervm/tests/virt/powervm/test_vif.py index 19970b20..012103ad 100644 --- a/nova_powervm/tests/virt/powervm/test_vif.py +++ b/nova_powervm/tests/virt/powervm/test_vif.py @@ -287,6 +287,16 @@ class TestVifFunctions(test.TestCase): mock_drv.pre_live_migrate_at_destination.assert_called_once_with( mock_vif, {}) + @mock.patch('nova_powervm.virt.powervm.vif._build_vif_driver') + def test_post_live_migrate_at_source(self, mock_build_vif_drv): + mock_drv = mock.MagicMock() + mock_build_vif_drv.return_value = mock_drv + mock_vif = mock.MagicMock() + + vif.post_live_migrate_at_source(self.adpt, 'host_uuid', mock.Mock(), + mock_vif) + mock_drv.post_live_migrate_at_source.assert_called_once_with(mock_vif) + class TestVifSriovDriver(test.TestCase): @@ -775,15 +785,18 @@ class TestVifOvsDriver(test.TestCase): mock_crt_ovs_port.assert_called_once_with( 'br-int', 'tap-dev', 'vif_id', 'aa:bb:cc:dd:ee:ff', self.inst.uuid) + @mock.patch('nova.network.linux_net.delete_ovs_vif_port') @mock.patch('pypowervm.wrappers.network.CNA.search') @mock.patch('pypowervm.tasks.partition.get_this_partition') @mock.patch('pypowervm.wrappers.network.VSwitch.search') def test_rollback_live_migration_at_destination( - self, mock_vs_search, mock_get_part, mock_cna_search): + self, mock_vs_search, mock_get_part, mock_cna_search, + mock_delete_ovs_port): # All the fun mocking mock_vs_search.return_value = mock.MagicMock(switch_id=5) vea_vlan_mappings = {'aa:bb:cc:dd:ee:ff': 3, 'aa:bb:cc:dd:ee:ee': 4} - vif = {'address': 'aa:bb:cc:dd:ee:ee'} + vif = {'devname': 'tap-dev', 'address': 'aa:bb:cc:dd:ee:ee', + 'network': {'bridge': 'br-int'}, 'id': 'vif_id'} mock_get_part.return_value = mock.MagicMock(schema_type='VIO', uuid='uuid') mock_trunk = mock.MagicMock() @@ -792,6 +805,9 @@ class TestVifOvsDriver(test.TestCase): # Invoke self.drv.rollback_live_migration_at_destination(vif, vea_vlan_mappings) + # Make sure the OVS port was deleted + mock_delete_ovs_port.assert_called_once_with('br-int', 'tap-dev') + # Make sure the trunk was deleted mock_trunk.delete.assert_called_once() @@ -804,3 +820,13 @@ class TestVifOvsDriver(test.TestCase): mock_cna_search.assert_called_once_with( self.drv.adapter, parent_type='VIO', parent_uuid='uuid', vswitch_id=5, pvid=4, one_result=True) + + @mock.patch('nova.network.linux_net.delete_ovs_vif_port') + def test_post_live_migrate_at_source(self, mock_delete_ovs_port): + # Mock the vif + vif = {'devname': 'tap-dev', 'address': 'aa:bb:cc:dd:ee:ff', + 'network': {'bridge': 'br-int'}, 'id': 'vif_id'} + # Invoke and test + self.drv.post_live_migrate_at_source(vif) + # Now validate it called the things it needed to + mock_delete_ovs_port.assert_called_once_with('br-int', 'tap-dev') diff --git a/nova_powervm/virt/powervm/live_migration.py b/nova_powervm/virt/powervm/live_migration.py index e51eae3d..5f109b01 100644 --- a/nova_powervm/virt/powervm/live_migration.py +++ b/nova_powervm/virt/powervm/live_migration.py @@ -413,6 +413,10 @@ class LiveMigrationSrc(LiveMigration): :param network_infos: instance network information """ LOG.debug("Post live migration at source.", instance=self.instance) + for network_info in network_infos: + vif.post_live_migrate_at_source( + self.drvr.adapter, self.drvr.host_uuid, self.instance, + network_info) def rollback_live_migration(self, context): """Roll back a failed migration. diff --git a/nova_powervm/virt/powervm/vif.py b/nova_powervm/virt/powervm/vif.py index 852c6c27..580b4fe6 100644 --- a/nova_powervm/virt/powervm/vif.py +++ b/nova_powervm/virt/powervm/vif.py @@ -233,6 +233,19 @@ def pre_live_migrate_at_source(adapter, host_uuid, instance, vif): return vif_drv.pre_live_migrate_at_source(vif) +def post_live_migrate_at_source(adapter, host_uuid, instance, vif): + """Performs the post live migrate on the source host. + + :param adapter: The pypowervm adapter. + :param host_uuid: The host UUID for the PowerVM API. + :param instance: The nova instance object. + :param vif: The virtual interface of the instance. This may be + called network_info in other portions of the code. + """ + vif_drv = _build_vif_driver(adapter, host_uuid, instance, vif) + return vif_drv.post_live_migrate_at_source(vif) + + def get_secure_rmc_vswitch(adapter, host_uuid): """Returns the vSwitch that is used for secure RMC. @@ -403,6 +416,14 @@ class PvmVifDriver(object): """ return [] + def post_live_migrate_at_source(self, vif): + """Performs the post live migrate on the source host. + + :param vif: The virtual interface of an instance. This may be + called network_info in other portions of the code. + """ + pass + class PvmSeaVifDriver(PvmVifDriver): """The PowerVM Shared Ethernet Adapter VIF Driver.""" @@ -780,6 +801,10 @@ class PvmOvsVifDriver(PvmLioVifDriver): self.adapter, parent_type=pvm_ms.System, one_result=True, name=CONF.powervm.pvm_vswitch_for_novalink_io).switch_id + # Delete port from OVS + linux_net.delete_ovs_vif_port(vif['network']['bridge'], + self.get_trunk_dev_name(vif)) + # Find the trunk mgmt_wrap = pvm_par.get_this_partition(self.adapter) trunk = pvm_net.CNA.search( @@ -815,3 +840,12 @@ class PvmOvsVifDriver(PvmLioVifDriver): mac=mac) return pvm_cna.find_trunks(self.adapter, cna_w) + + def post_live_migrate_at_source(self, vif): + """Performs the post live migrate on the source host. + + :param vif: The virtual interface of an instance. This may be + called network_info in other portions of the code. + """ + linux_net.delete_ovs_vif_port(vif['network']['bridge'], + self.get_trunk_dev_name(vif))