From 8ae8897aa785459cdd50f8ef848f38d0c20812af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Szczepa=C5=84ski?= Date: Fri, 27 Jul 2018 13:09:43 +0200 Subject: [PATCH] vMotion VLAN ID fix Check VLAN availability after vMotion Change-Id: I739e77dcee6f89fad67fbb529ad75e5dcba4f6d0 Closes-Bug: #1783979 --- cvm/services.py | 7 +++- tests/functional/test_vm_created_vlan_id.py | 41 +++++++++++++++++++-- tests/unit/services/test_vlan_ids.py | 15 ++++++-- 3 files changed, 54 insertions(+), 9 deletions(-) diff --git a/cvm/services.py b/cvm/services.py index f9ee2b6..8a73a80 100644 --- a/cvm/services.py +++ b/cvm/services.py @@ -230,8 +230,11 @@ def _create_or_update(self, vmi_model): def _assign_vlan_id(self, vmi_model): with self._vcenter_api_client: current_vlan_id = self._vcenter_api_client.get_vlan_id(vmi_model.vcenter_port) - vmi_model.vcenter_port.vlan_id = current_vlan_id or self._vlan_id_pool.get_available() - if not current_vlan_id: + if current_vlan_id and self._vlan_id_pool.is_available(current_vlan_id): + vmi_model.vcenter_port.vlan_id = current_vlan_id + self._vlan_id_pool.reserve(current_vlan_id) + else: + vmi_model.vcenter_port.vlan_id = self._vlan_id_pool.get_available() self._vcenter_api_client.set_vlan_id(vmi_model.vcenter_port) def _add_vnc_info_to(self, vmi_model): diff --git a/tests/functional/test_vm_created_vlan_id.py b/tests/functional/test_vm_created_vlan_id.py index 25bb494..cd29ce8 100644 --- a/tests/functional/test_vm_created_vlan_id.py +++ b/tests/functional/test_vm_created_vlan_id.py @@ -4,8 +4,8 @@ def test_vm_created_vlan_id(controller, database, vcenter_api_client, vm_created_update, vn_model_1, vlan_id_pool): """ What happens when the created interface is already using an overriden VLAN ID? - We should keep it, not removing old/adding new VLAN ID, since it breaks the connectivity - for a moment. + We should keep it (if it's available on the host), not removing old/adding new VLAN ID, + since it breaks the connectivity for a moment. """ # Virtual Networks are already created for us and after synchronization, @@ -13,7 +13,7 @@ def test_vm_created_vlan_id(controller, database, vcenter_api_client, vm_created database.save(vn_model_1) # Some vlan ids should be already reserved - reserve_vlan_ids(vlan_id_pool, [0, 1, 5]) + reserve_vlan_ids(vlan_id_pool, [0, 1]) # When we ask vCenter for the VLAN ID it turns out that the VLAN ID has already been overridden vcenter_api_client.get_vlan_id.return_value = 5 @@ -25,7 +25,7 @@ def test_vm_created_vlan_id(controller, database, vcenter_api_client, vm_created vcenter_api_client.set_vlan_id.assert_not_called() # Check inner VMI model state - vm_model = database.get_vm_model_by_uuid('12345678-1234-1234-1234-123456789012') + vm_model = database.get_vm_model_by_uuid('vmware-vm-uuid-1') vmi_model = database.get_all_vmi_models()[0] assert_vmi_model_state( vmi_model, @@ -36,3 +36,36 @@ def test_vm_created_vlan_id(controller, database, vcenter_api_client, vm_created vn_model=vn_model_1, vm_model=vm_model ) + + +def test_vmotion_vlan_unavailable(controller, database, vcenter_api_client, vm_created_update, vn_model_1, + vlan_id_pool): + """ When the VLAN ID is unavailable on a host, we should change it to a new value""" + # Virtual Networks are already created for us and after synchronization, + # their models are stored in our database + database.save(vn_model_1) + + # Some vlan ids should be already reserved + reserve_vlan_ids(vlan_id_pool, [0, 1, 5]) + + # When we ask vCenter for the VLAN ID it turns out that the VLAN ID has already been overridden + vcenter_api_client.get_vlan_id.return_value = 5 + + # A new update containing VmCreatedEvent arrives and is being handled by the controller + controller.handle_update(vm_created_update) + + # Check if VLAN ID has been changed + vmi_model = database.get_all_vmi_models()[0] + vcenter_api_client.set_vlan_id.assert_called_once_with(vmi_model.vcenter_port) + + # Check inner VMI model state + vm_model = database.get_vm_model_by_uuid('vmware-vm-uuid-1') + assert_vmi_model_state( + vmi_model, + mac_address='mac-address', + ip_address='192.168.100.5', + vlan_id=2, + display_name='vmi-DPG1-VM1', + vn_model=vn_model_1, + vm_model=vm_model + ) diff --git a/tests/unit/services/test_vlan_ids.py b/tests/unit/services/test_vlan_ids.py index bd0bf77..ba13a36 100644 --- a/tests/unit/services/test_vlan_ids.py +++ b/tests/unit/services/test_vlan_ids.py @@ -30,10 +30,8 @@ def test_assign_new_vlan_id(vmi_service, database, vcenter_api_client, assert vmi_model.vcenter_port.vlan_id == 2 -def test_retain_old_vlan_id(vmi_service, database, vcenter_api_client, - vlan_id_pool, vmi_model): +def test_retain_old_vlan_id(vmi_service, database, vcenter_api_client, vmi_model): database.vmis_to_update.append(vmi_model) - reserve_vlan_ids(vlan_id_pool, [20]) vcenter_api_client.get_vlan_id.return_value = 20 vmi_service.update_vmis() @@ -41,6 +39,17 @@ def test_retain_old_vlan_id(vmi_service, database, vcenter_api_client, assert vmi_model.vcenter_port.vlan_id == 20 +def test_current_not_available(vmi_service, database, vcenter_api_client, + vlan_id_pool, vmi_model): + database.vmis_to_update.append(vmi_model) + vcenter_api_client.get_vlan_id.return_value = 20 + reserve_vlan_ids(vlan_id_pool, [20]) + + vmi_service.update_vmis() + + assert vmi_model.vcenter_port.vlan_id == 0 + + def test_restore_vlan_id(vmi_service, database, vcenter_api_client, vlan_id_pool, vmi_model): reserve_vlan_ids(vlan_id_pool, [20])