X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=RO-VIM-openstack%2Fosm_rovim_openstack%2Ftests%2Ftest_vimconn_openstack.py;h=c102ed4b9d1ebf449f22e28f4cfe08e58a63d344;hb=8453602c784e1f2458612d70ff40e19c2ff73d6f;hp=bdd6bed92814df29c38992dbfed2caa9ed6ab470;hpb=4bc8eb99dbadadf5013de93fcb424038149e1576;p=osm%2FRO.git diff --git a/RO-VIM-openstack/osm_rovim_openstack/tests/test_vimconn_openstack.py b/RO-VIM-openstack/osm_rovim_openstack/tests/test_vimconn_openstack.py index bdd6bed9..c102ed4b 100644 --- a/RO-VIM-openstack/osm_rovim_openstack/tests/test_vimconn_openstack.py +++ b/RO-VIM-openstack/osm_rovim_openstack/tests/test_vimconn_openstack.py @@ -32,6 +32,7 @@ import mock from mock import MagicMock, patch from neutronclient.v2_0.client import Client from novaclient import exceptions as nvExceptions +from novaclient.exceptions import ClientException, Conflict from osm_ro_plugin import vimconn from osm_ro_plugin.vimconn import ( VimConnConnectionException, @@ -79,6 +80,36 @@ created_items_all_true = { } +# Variables used in TestNewFlavor Class +name1 = "sample-flavor" +extended = ( + { + "cpu-quota": {"limit": 3}, + "mem-quota": {"limit": 1}, + "mempage-size": "LARGE", + "cpu-pinning-policy": "DEDICATED", + "mem-policy": "STRICT", + }, +) +flavor_data = { + "name": name1, + "ram": 3, + "vcpus": 8, + "disk": 50, + "extended": extended, +} + +flavor_data2 = { + "name": name1, + "ram": 3, + "vcpus": 8, + "disk": 50, +} + + +@unittest.skip( + "Test is incomplete as it did not mock reload_connection and SFC methods are not in use." +) class TestSfcOperations(unittest.TestCase): @mock.patch("logging.getLogger", autospec=True) def setUp(self, mock_logger): @@ -1099,6 +1130,11 @@ class TestSfcOperations(unittest.TestCase): self.assertEqual(result, "638f957c-82df-11e7-b7c8-132706021464") +def check_if_assert_not_called(mocks: list): + for mocking in mocks: + mocking.assert_not_called() + + class Status: def __init__(self, s): self.status = s @@ -2242,7 +2278,10 @@ class TestNewVmInstance(unittest.TestCase): self.assertEqual(existing_vim_volumes, expected_existing_vim_volumes) self.vimconn.cinder.volumes.create.assert_not_called() - def test_prepare_persistent_non_root_volumes_vim_using_volume_id(self): + @patch.object(vimconnector, "update_block_device_mapping") + def test_prepare_persistent_non_root_volumes_vim_using_volume_id( + self, mock_update_block_device_mapping + ): """Existing persistent non root volume with vim_volume_id.""" vm_av_zone = ["nova"] base_disk_index = ord("b") @@ -2264,8 +2303,12 @@ class TestNewVmInstance(unittest.TestCase): self.assertDictEqual(block_device_mapping, expected_block_device_mapping) self.assertEqual(existing_vim_volumes, expected_existing_vim_volumes) self.vimconn.cinder.volumes.create.assert_not_called() + mock_update_block_device_mapping.assert_not_called() - def test_prepare_persistent_root_volumes_using_vim_id(self): + @patch.object(vimconnector, "update_block_device_mapping") + def test_prepare_persistent_root_volumes_using_vim_id( + self, mock_update_block_device_mapping + ): """Existing persistent root volume with vim_id.""" vm_av_zone = ["nova"] base_disk_index = ord("a") @@ -2289,8 +2332,12 @@ class TestNewVmInstance(unittest.TestCase): self.assertDictEqual(block_device_mapping, expected_block_device_mapping) self.assertEqual(existing_vim_volumes, expected_existing_vim_volumes) self.vimconn.cinder.volumes.create.assert_not_called() + mock_update_block_device_mapping.assert_not_called() - def test_prepare_persistent_non_root_volumes_using_vim_id(self): + @patch.object(vimconnector, "update_block_device_mapping") + def test_prepare_persistent_non_root_volumes_using_vim_id( + self, mock_update_block_device_mapping + ): """Existing persistent root volume with vim_id.""" vm_av_zone = ["nova"] base_disk_index = ord("b") @@ -2314,8 +2361,12 @@ class TestNewVmInstance(unittest.TestCase): self.assertDictEqual(block_device_mapping, expected_block_device_mapping) self.assertEqual(existing_vim_volumes, expected_existing_vim_volumes) self.vimconn.cinder.volumes.create.assert_not_called() + mock_update_block_device_mapping.assert_not_called() - def test_prepare_persistent_root_volumes_create(self): + @patch.object(vimconnector, "update_block_device_mapping") + def test_prepare_persistent_root_volumes_create( + self, mock_update_block_device_mapping + ): """Create persistent root volume.""" self.vimconn.cinder.volumes.create.return_value.id = volume_id2 vm_av_zone = ["nova"] @@ -2325,7 +2376,51 @@ class TestNewVmInstance(unittest.TestCase): existing_vim_volumes = [] created_items = {} expected_boot_vol_id = volume_id2 - expected_block_device_mapping = {"vda": volume_id2} + boot_volume_id = self.vimconn._prepare_persistent_root_volumes( + name, + vm_av_zone, + disk, + base_disk_index, + block_device_mapping, + existing_vim_volumes, + created_items, + ) + self.assertEqual(boot_volume_id, expected_boot_vol_id) + self.vimconn.cinder.volumes.create.assert_called_once_with( + size=10, + name="basicvmvda", + imageRef=image_id, + availability_zone=["nova"], + ) + mock_update_block_device_mapping.assert_called_once() + _call_mock_update_block_device_mapping = ( + mock_update_block_device_mapping.call_args_list + ) + self.assertEqual( + _call_mock_update_block_device_mapping[0].kwargs["block_device_mapping"], + block_device_mapping, + ) + self.assertEqual( + _call_mock_update_block_device_mapping[0].kwargs["base_disk_index"], 97 + ) + self.assertEqual(_call_mock_update_block_device_mapping[0].kwargs["disk"], disk) + self.assertEqual( + _call_mock_update_block_device_mapping[0].kwargs["created_items"], {} + ) + + @patch.object(vimconnector, "update_block_device_mapping") + def test_prepare_persistent_root_volumes_create_with_keep( + self, mock_update_block_device_mapping + ): + """Create persistent root volume, disk has keep parameter.""" + self.vimconn.cinder.volumes.create.return_value.id = volume_id2 + vm_av_zone = ["nova"] + base_disk_index = ord("a") + disk = {"size": 10, "image_id": image_id, "keep": True} + block_device_mapping = {} + existing_vim_volumes = [] + created_items = {} + expected_boot_vol_id = volume_id2 expected_existing_vim_volumes = [] boot_volume_id = self.vimconn._prepare_persistent_root_volumes( name, @@ -2337,7 +2432,6 @@ class TestNewVmInstance(unittest.TestCase): created_items, ) self.assertEqual(boot_volume_id, expected_boot_vol_id) - self.assertDictEqual(block_device_mapping, expected_block_device_mapping) self.assertEqual(existing_vim_volumes, expected_existing_vim_volumes) self.vimconn.cinder.volumes.create.assert_called_once_with( size=10, @@ -2345,9 +2439,26 @@ class TestNewVmInstance(unittest.TestCase): imageRef=image_id, availability_zone=["nova"], ) - self.assertEqual(created_items, {f"volume:{volume_id2}": True}) + mock_update_block_device_mapping.assert_called_once() + _call_mock_update_block_device_mapping = ( + mock_update_block_device_mapping.call_args_list + ) + self.assertEqual( + _call_mock_update_block_device_mapping[0].kwargs["block_device_mapping"], + block_device_mapping, + ) + self.assertEqual( + _call_mock_update_block_device_mapping[0].kwargs["base_disk_index"], 97 + ) + self.assertEqual(_call_mock_update_block_device_mapping[0].kwargs["disk"], disk) + self.assertEqual( + _call_mock_update_block_device_mapping[0].kwargs["created_items"], {} + ) - def test_prepare_persistent_non_root_volumes_create(self): + @patch.object(vimconnector, "update_block_device_mapping") + def test_prepare_persistent_non_root_volumes_create( + self, mock_update_block_device_mapping + ): """Create persistent non-root volume.""" self.vimconn.cinder = CopyingMock() self.vimconn.cinder.volumes.create.return_value.id = volume_id2 @@ -2357,7 +2468,6 @@ class TestNewVmInstance(unittest.TestCase): block_device_mapping = {} existing_vim_volumes = [] created_items = {} - expected_block_device_mapping = {"vda": volume_id2} expected_existing_vim_volumes = [] self.vimconn._prepare_non_root_persistent_volumes( name, @@ -2369,14 +2479,74 @@ class TestNewVmInstance(unittest.TestCase): created_items, ) - self.assertDictEqual(block_device_mapping, expected_block_device_mapping) self.assertEqual(existing_vim_volumes, expected_existing_vim_volumes) self.vimconn.cinder.volumes.create.assert_called_once_with( size=10, name="basicvmvda", availability_zone=["nova"] ) - self.assertEqual(created_items, {f"volume:{volume_id2}": True}) + mock_update_block_device_mapping.assert_called_once() + _call_mock_update_block_device_mapping = ( + mock_update_block_device_mapping.call_args_list + ) + self.assertEqual( + _call_mock_update_block_device_mapping[0].kwargs["block_device_mapping"], + block_device_mapping, + ) + self.assertEqual( + _call_mock_update_block_device_mapping[0].kwargs["base_disk_index"], 97 + ) + self.assertEqual(_call_mock_update_block_device_mapping[0].kwargs["disk"], disk) + self.assertEqual( + _call_mock_update_block_device_mapping[0].kwargs["created_items"], {} + ) + + @patch.object(vimconnector, "update_block_device_mapping") + def test_prepare_persistent_non_root_volumes_create_with_keep( + self, mock_update_block_device_mapping + ): + """Create persistent non-root volume.""" + self.vimconn.cinder = CopyingMock() + self.vimconn.cinder.volumes.create.return_value.id = volume_id2 + vm_av_zone = ["nova"] + base_disk_index = ord("a") + disk = {"size": 10, "keep": True} + block_device_mapping = {} + existing_vim_volumes = [] + created_items = {} + expected_existing_vim_volumes = [] + self.vimconn._prepare_non_root_persistent_volumes( + name, + disk, + vm_av_zone, + block_device_mapping, + base_disk_index, + existing_vim_volumes, + created_items, + ) + + self.assertEqual(existing_vim_volumes, expected_existing_vim_volumes) + self.vimconn.cinder.volumes.create.assert_called_once_with( + size=10, name="basicvmvda", availability_zone=["nova"] + ) + mock_update_block_device_mapping.assert_called_once() + _call_mock_update_block_device_mapping = ( + mock_update_block_device_mapping.call_args_list + ) + self.assertEqual( + _call_mock_update_block_device_mapping[0].kwargs["block_device_mapping"], + block_device_mapping, + ) + self.assertEqual( + _call_mock_update_block_device_mapping[0].kwargs["base_disk_index"], 97 + ) + self.assertEqual(_call_mock_update_block_device_mapping[0].kwargs["disk"], disk) + self.assertEqual( + _call_mock_update_block_device_mapping[0].kwargs["created_items"], {} + ) - def test_prepare_persistent_root_volumes_create_raise_exception(self): + @patch.object(vimconnector, "update_block_device_mapping") + def test_prepare_persistent_root_volumes_create_raise_exception( + self, mock_update_block_device_mapping + ): """Create persistent root volume raise exception.""" self.vimconn.cinder.volumes.create.side_effect = Exception vm_av_zone = ["nova"] @@ -2408,8 +2578,12 @@ class TestNewVmInstance(unittest.TestCase): self.assertEqual(existing_vim_volumes, []) self.assertEqual(block_device_mapping, {}) self.assertEqual(created_items, {}) + mock_update_block_device_mapping.assert_not_called() - def test_prepare_persistent_non_root_volumes_create_raise_exception(self): + @patch.object(vimconnector, "update_block_device_mapping") + def test_prepare_persistent_non_root_volumes_create_raise_exception( + self, mock_update_block_device_mapping + ): """Create persistent non-root volume raise exception.""" self.vimconn.cinder.volumes.create.side_effect = Exception vm_av_zone = ["nova"] @@ -2436,6 +2610,7 @@ class TestNewVmInstance(unittest.TestCase): self.assertEqual(existing_vim_volumes, []) self.assertEqual(block_device_mapping, {}) self.assertEqual(created_items, {}) + mock_update_block_device_mapping.assert_not_called() @patch("time.sleep") def test_wait_for_created_volumes_availability_volume_status_available( @@ -2650,7 +2825,6 @@ class TestNewVmInstance(unittest.TestCase): mock_created_vol_availability.return_value = 10 mock_existing_vol_availability.return_value = 15 self.vimconn.cinder = CopyingMock() - self.vimconn._prepare_disk_for_vminstance( name, existing_vim_volumes, @@ -2933,7 +3107,7 @@ class TestNewVmInstance(unittest.TestCase): self.vimconn._neutron_create_float_ip(param, created_items) self.assertEqual(created_items, expected_created_items) - def test_neutron_create_float_ip_exception_occured(self): + def test_neutron_create_float_ip_exception_occurred(self): """Floating ip could not be created.""" param = { "floatingip": { @@ -2944,14 +3118,14 @@ class TestNewVmInstance(unittest.TestCase): created_items = {} self.vimconn.neutron = CopyingMock() self.vimconn.neutron.create_floatingip.side_effect = Exception( - "Neutron floating ip create exception occured." + "Neutron floating ip create exception occurred." ) with self.assertRaises(VimConnException) as err: self.vimconn._neutron_create_float_ip(param, created_items) self.assertEqual(created_items, {}) self.assertEqual( str(err.exception), - "Exception: Cannot create new floating_ip Neutron floating ip create exception occured.", + "Exception: Cannot create new floating_ip Neutron floating ip create exception occurred.", ) @patch.object(vimconnector, "_neutron_create_float_ip") @@ -3166,7 +3340,6 @@ class TestNewVmInstance(unittest.TestCase): def test_get_free_floating_ip(self, mock_find_floating_ip, mock_shuffle): """Get free floating ip successfully.""" floating_network = {"floating_ip": "308b73-t9cc-1a6a-a270-12cc4811bd4a"} - created_items = {} floating_ips = [ { "port_id": "608b73-r9cc-5a6a-a270-82cc4811bd4a", @@ -3187,13 +3360,11 @@ class TestNewVmInstance(unittest.TestCase): mock_find_floating_ip.return_value = "508b73-o9cc-5a6a-a270-72cc4811bd8" expected_result = "508b73-o9cc-5a6a-a270-72cc4811bd8" - result = self.vimconn._get_free_floating_ip( - self.server, floating_network, created_items - ) + result = self.vimconn._get_free_floating_ip(self.server, floating_network) self.assertEqual(result, expected_result) mock_shuffle.assert_called_once_with(floating_ips) mock_find_floating_ip.assert_called_once_with( - self.server, floating_ips, floating_network, created_items + self.server, floating_ips, floating_network ) @patch("random.shuffle") @@ -3203,15 +3374,12 @@ class TestNewVmInstance(unittest.TestCase): ): """Neutron list floating IPs raises exception.""" floating_network = {"floating_ip": "308b73-t9cc-1a6a-a270-12cc4811bd4a"} - created_items = {} self.vimconn.neutron = CopyingMock() self.vimconn.neutron.list_floatingips.side_effect = Exception( "Floating ips could not be listed." ) with self.assertRaises(Exception) as err: - result = self.vimconn._get_free_floating_ip( - self.server, floating_network, created_items - ) + result = self.vimconn._get_free_floating_ip(self.server, floating_network) self.assertEqual(result, None) self.assertEqual(str(err.exception), "Floating ips could not be listed.") mock_shuffle.assert_not_called() @@ -3224,7 +3392,6 @@ class TestNewVmInstance(unittest.TestCase): ): """_find_floating_ip method raises exception.""" floating_network = {"floating_ip": "308b73-t9cc-1a6a-a270-12cc4811bd4a"} - created_items = {} floating_ips = [ { "port_id": "608b73-r9cc-5a6a-a270-82cc4811bd4a", @@ -3248,14 +3415,12 @@ class TestNewVmInstance(unittest.TestCase): ) with self.assertRaises(Exception) as err: - result = self.vimconn._get_free_floating_ip( - self.server, floating_network, created_items - ) + result = self.vimconn._get_free_floating_ip(self.server, floating_network) self.assertEqual(result, None) self.assertEqual(str(err.exception), "Free floating ip could not be found.") mock_shuffle.assert_called_once_with(floating_ips) mock_find_floating_ip.assert_called_once_with( - self.server, floating_ips, floating_network, created_items + self.server, floating_ips, floating_network ) @patch.object(vimconnector, "_create_floating_ip") @@ -3297,7 +3462,6 @@ class TestNewVmInstance(unittest.TestCase): "floating_ip": "y08b73-o9cc-1a6a-a270-12cc4811bd4u", "vim_id": "608b73-r9cc-5a6a-a270-82cc4811bd4a", }, - created_items, ) self.vimconn.neutron.show_floatingip.assert_called_once_with( "y08b73-o9cc-1a6a-a270-12cc4811bd4u" @@ -3351,7 +3515,6 @@ class TestNewVmInstance(unittest.TestCase): "floating_ip": "y08b73-o9cc-1a6a-a270-12cc4811bd4u", "vim_id": "608b73-r9cc-5a6a-a270-82cc4811bd4a", }, - created_items, ) self.vimconn.neutron.show_floatingip.assert_called_with(None) mock_sleep.assert_not_called() @@ -3407,7 +3570,6 @@ class TestNewVmInstance(unittest.TestCase): "vim_id": "608b73-r9cc-5a6a-a270-82cc4811bd4a", "exit_on_floating_ip_error": False, }, - created_items, ) self.vimconn.neutron.show_floatingip.assert_not_called() mock_sleep.assert_not_called() @@ -3462,7 +3624,6 @@ class TestNewVmInstance(unittest.TestCase): "vim_id": "608b73-r9cc-5a6a-a270-82cc4811bd4a", "exit_on_floating_ip_error": True, }, - created_items, ) self.vimconn.neutron.show_floatingip.assert_not_called() mock_sleep.assert_not_called() @@ -3518,7 +3679,6 @@ class TestNewVmInstance(unittest.TestCase): ( self.server, floating_network, - created_items, ), ) self.assertEqual( @@ -3526,7 +3686,6 @@ class TestNewVmInstance(unittest.TestCase): ( self.server, floating_network, - created_items, ), ) self.assertEqual( @@ -3534,7 +3693,6 @@ class TestNewVmInstance(unittest.TestCase): ( self.server, floating_network, - created_items, ), ) self.assertEqual(self.vimconn.neutron.show_floatingip.call_count, 3) @@ -3597,7 +3755,6 @@ class TestNewVmInstance(unittest.TestCase): ( self.server, floating_network, - created_items, ), ) self.assertEqual( @@ -3605,7 +3762,6 @@ class TestNewVmInstance(unittest.TestCase): ( self.server, floating_network, - created_items, ), ) self.assertEqual( @@ -3613,7 +3769,6 @@ class TestNewVmInstance(unittest.TestCase): ( self.server, floating_network, - created_items, ), ) self.assertEqual( @@ -3621,7 +3776,6 @@ class TestNewVmInstance(unittest.TestCase): ( self.server, floating_network, - created_items, ), ) @@ -3675,7 +3829,6 @@ class TestNewVmInstance(unittest.TestCase): ( self.server, floating_network, - created_items, ), ) self.assertEqual( @@ -3683,7 +3836,6 @@ class TestNewVmInstance(unittest.TestCase): ( self.server, floating_network, - created_items, ), ) self.assertEqual( @@ -3691,7 +3843,6 @@ class TestNewVmInstance(unittest.TestCase): ( self.server, floating_network, - created_items, ), ) self.assertEqual( @@ -3699,7 +3850,6 @@ class TestNewVmInstance(unittest.TestCase): ( self.server, floating_network, - created_items, ), ) @@ -3756,7 +3906,6 @@ class TestNewVmInstance(unittest.TestCase): ( self.server, floating_network, - created_items, ), ) self.assertEqual( @@ -3764,7 +3913,6 @@ class TestNewVmInstance(unittest.TestCase): ( self.server, floating_network, - created_items, ), ) self.assertEqual( @@ -3772,7 +3920,6 @@ class TestNewVmInstance(unittest.TestCase): ( self.server, floating_network, - created_items, ), ) @@ -3838,7 +3985,6 @@ class TestNewVmInstance(unittest.TestCase): ( self.server, floating_network, - created_items, ), ) self.assertEqual( @@ -3846,7 +3992,6 @@ class TestNewVmInstance(unittest.TestCase): ( self.server, floating_network, - created_items, ), ) self.assertEqual( @@ -3854,7 +3999,6 @@ class TestNewVmInstance(unittest.TestCase): ( self.server, floating_network, - created_items, ), ) @@ -3986,6 +4130,7 @@ class TestNewVmInstance(unittest.TestCase): self.vimconn.neutron.update_port.assert_not_called() @patch("time.time") + @patch.object(vimconnector, "remove_keep_tag_from_persistent_volumes") @patch.object(vimconnector, "_reload_connection") @patch.object(vimconnector, "_prepare_network_for_vminstance") @patch.object(vimconnector, "_create_user_data") @@ -4006,6 +4151,7 @@ class TestNewVmInstance(unittest.TestCase): mock_create_user_data, mock_prepare_network_for_vm_instance, mock_reload_connection, + mock_remove_keep_flag_from_persistent_volumes, mock_time, ): """New VM instance creation is successful.""" @@ -4077,10 +4223,12 @@ class TestNewVmInstance(unittest.TestCase): created_items={}, vm_start_time=time_return_value, ) + mock_remove_keep_flag_from_persistent_volumes.assert_not_called() mock_delete_vm_instance.assert_not_called() mock_format_exception.assert_not_called() @patch("time.time") + @patch.object(vimconnector, "remove_keep_tag_from_persistent_volumes") @patch.object(vimconnector, "_reload_connection") @patch.object(vimconnector, "_prepare_network_for_vminstance") @patch.object(vimconnector, "_create_user_data") @@ -4101,6 +4249,7 @@ class TestNewVmInstance(unittest.TestCase): mock_create_user_data, mock_prepare_network_for_vm_instance, mock_reload_connection, + mock_remove_keep_flag_from_persistent_volumes, mock_time, ): """New VM instance creation failed because of user data creation failure.""" @@ -4111,6 +4260,8 @@ class TestNewVmInstance(unittest.TestCase): mock_get_vm_availability_zone.return_value = "nova" + mock_remove_keep_flag_from_persistent_volumes.return_value = {} + self.vimconn.nova.servers.create.return_value = self.server mock_time.return_value = time_return_value @@ -4145,12 +4296,14 @@ class TestNewVmInstance(unittest.TestCase): mock_time.assert_not_called() mock_update_port_security.assert_not_called() mock_prepare_external_network.assert_not_called() + mock_remove_keep_flag_from_persistent_volumes.assert_called_once_with({}) mock_delete_vm_instance.assert_called_once_with(None, {}) mock_format_exception.assert_called_once() arg = mock_format_exception.call_args[0][0] self.assertEqual(str(arg), "User data could not be retrieved.") @patch("time.time") + @patch.object(vimconnector, "remove_keep_tag_from_persistent_volumes") @patch.object(vimconnector, "_reload_connection") @patch.object(vimconnector, "_prepare_network_for_vminstance") @patch.object(vimconnector, "_create_user_data") @@ -4171,6 +4324,7 @@ class TestNewVmInstance(unittest.TestCase): mock_create_user_data, mock_prepare_network_for_vm_instance, mock_reload_connection, + mock_remove_keep_flag_from_persistent_volumes, mock_time, ): """New VM instance creation, external network connection has failed as floating @@ -4184,6 +4338,8 @@ class TestNewVmInstance(unittest.TestCase): mock_time.return_value = time_return_value + mock_remove_keep_flag_from_persistent_volumes.return_value = {} + mock_prepare_external_network.side_effect = VimConnException( "Can not create floating ip." ) @@ -4244,12 +4400,14 @@ class TestNewVmInstance(unittest.TestCase): created_items={}, vm_start_time=time_return_value, ) + mock_remove_keep_flag_from_persistent_volumes.assert_called_once_with({}) mock_delete_vm_instance.assert_called_once_with(self.server.id, {}) mock_format_exception.assert_called_once() arg = mock_format_exception.call_args[0][0] self.assertEqual(str(arg), "Can not create floating ip.") @patch("time.time") + @patch.object(vimconnector, "remove_keep_tag_from_persistent_volumes") @patch.object(vimconnector, "_reload_connection") @patch.object(vimconnector, "_prepare_network_for_vminstance") @patch.object(vimconnector, "_create_user_data") @@ -4270,6 +4428,7 @@ class TestNewVmInstance(unittest.TestCase): mock_create_user_data, mock_prepare_network_for_vm_instance, mock_reload_connection, + mock_remove_keep_flag_from_persistent_volumes, mock_time, ): """New VM creation with affinity group.""" @@ -4339,10 +4498,12 @@ class TestNewVmInstance(unittest.TestCase): created_items={}, vm_start_time=time_return_value, ) + mock_remove_keep_flag_from_persistent_volumes.assert_not_called() mock_delete_vm_instance.assert_not_called() mock_format_exception.assert_not_called() @patch("time.time") + @patch.object(vimconnector, "remove_keep_tag_from_persistent_volumes") @patch.object(vimconnector, "_reload_connection") @patch.object(vimconnector, "_prepare_network_for_vminstance") @patch.object(vimconnector, "_create_user_data") @@ -4363,6 +4524,7 @@ class TestNewVmInstance(unittest.TestCase): mock_create_user_data, mock_prepare_network_for_vm_instance, mock_reload_connection, + mock_remove_keep_flag_from_persistent_volumes, mock_time, ): """New VM(server) creation failed.""" @@ -4377,6 +4539,8 @@ class TestNewVmInstance(unittest.TestCase): mock_time.return_value = time_return_value + mock_remove_keep_flag_from_persistent_volumes.return_value = {} + self.vimconn.new_vminstance( name, description, @@ -4429,12 +4593,14 @@ class TestNewVmInstance(unittest.TestCase): mock_time.assert_not_called() mock_update_port_security.assert_not_called() mock_prepare_external_network.assert_not_called() + mock_remove_keep_flag_from_persistent_volumes.assert_called_once_with({}) mock_delete_vm_instance.assert_called_once_with(None, {}) mock_format_exception.assert_called_once() arg = mock_format_exception.call_args[0][0] self.assertEqual(str(arg), "Server could not be created.") @patch("time.time") + @patch.object(vimconnector, "remove_keep_tag_from_persistent_volumes") @patch.object(vimconnector, "_reload_connection") @patch.object(vimconnector, "_prepare_network_for_vminstance") @patch.object(vimconnector, "_create_user_data") @@ -4455,6 +4621,7 @@ class TestNewVmInstance(unittest.TestCase): mock_create_user_data, mock_prepare_network_for_vm_instance, mock_reload_connection, + mock_remove_keep_flag_from_persistent_volumes, mock_time, ): """Connection to Cloud API has failed.""" @@ -4463,6 +4630,7 @@ class TestNewVmInstance(unittest.TestCase): mock_get_vm_availability_zone.return_value = "nova" self.vimconn.nova.servers.create.return_value = self.server mock_time.return_value = time_return_value + mock_remove_keep_flag_from_persistent_volumes.return_value = {} self.vimconn.new_vminstance( name, @@ -4489,6 +4657,7 @@ class TestNewVmInstance(unittest.TestCase): mock_time.assert_not_called() mock_update_port_security.assert_not_called() mock_prepare_external_network.assert_not_called() + mock_remove_keep_flag_from_persistent_volumes.assert_called_once_with({}) mock_delete_vm_instance.assert_called_once_with(None, {}) @patch.object(vimconnector, "_delete_ports_by_id_wth_neutron") @@ -4637,7 +4806,7 @@ class TestNewVmInstance(unittest.TestCase): k_id = floating_network_vim_id k = f"floating_ip:{floating_network_vim_id}" self.vimconn.neutron.delete_floatingip.side_effect = ( - nvExceptions.ClientException("Client exception occured.") + nvExceptions.ClientException("Client exception occurred.") ) self.vimconn._delete_floating_ip_by_id(k, k_id, created_items) self.vimconn.neutron.delete_floatingip.assert_called_once_with(k_id) @@ -4649,7 +4818,7 @@ class TestNewVmInstance(unittest.TestCase): }, ) self.vimconn.logger.error.assert_called_once_with( - "Error deleting floating ip: ClientException: Unknown Error (HTTP Client exception occured.)" + "Error deleting floating ip: ClientException: Unknown Error (HTTP Client exception occurred.)" ) def test_delete_floating_ip_by_id_floating_ip_raises_vimconnexception(self): @@ -5260,6 +5429,7 @@ class TestNewVmInstance(unittest.TestCase): self.vimconn.logger.error.assert_not_called() @patch("time.sleep") + @patch.object(vimconnector, "_extract_items_wth_keep_flag_from_created_items") @patch.object(vimconnector, "_format_exception") @patch.object(vimconnector, "_reload_connection") @patch.object(vimconnector, "_delete_vm_ports_attached_to_network") @@ -5270,10 +5440,12 @@ class TestNewVmInstance(unittest.TestCase): mock_delete_vm_ports_attached_to_network, mock_reload_connection, mock_format_exception, + mock_extract_items_wth_keep_flag_from_created_items, mock_sleep, ): vm_id = f"{virtual_mac_id}" created_items = deepcopy(created_items_all_true) + mock_extract_items_wth_keep_flag_from_created_items.return_value = created_items volumes_to_hold = [f"{volume_id}", f"{volume_id2}"] mock_delete_created_items.return_value = False self.vimconn.delete_vminstance(vm_id, created_items, volumes_to_hold) @@ -5285,8 +5457,96 @@ class TestNewVmInstance(unittest.TestCase): ) mock_sleep.assert_not_called() mock_format_exception.assert_not_called() + mock_extract_items_wth_keep_flag_from_created_items.assert_called_once_with( + created_items + ) + + @patch("time.sleep") + @patch.object(vimconnector, "_extract_items_wth_keep_flag_from_created_items") + @patch.object(vimconnector, "_format_exception") + @patch.object(vimconnector, "_reload_connection") + @patch.object(vimconnector, "_delete_vm_ports_attached_to_network") + @patch.object(vimconnector, "_delete_created_items") + def test_delete_vminstance_created_items_has_keep_flag( + self, + mock_delete_created_items, + mock_delete_vm_ports_attached_to_network, + mock_reload_connection, + mock_format_exception, + mock_extract_items_wth_keep_flag_from_created_items, + mock_sleep, + ): + """Created_items includes items which has keep flag.""" + vm_id = f"{virtual_mac_id}" + initial_created_items = { + f"port{port_id}": True, + f"floating_ip{floating_network_vim_id}": None, + f"volume{volume_id}keep": True, + f"volume{volume_id2}keep": True, + } + created_items = { + f"port{port_id}": True, + f"floating_ip{floating_network_vim_id}": None, + } + mock_extract_items_wth_keep_flag_from_created_items.return_value = created_items + volumes_to_hold = [] + mock_delete_created_items.return_value = False + self.vimconn.delete_vminstance(vm_id, initial_created_items, volumes_to_hold) + mock_reload_connection.assert_called_once() + mock_delete_vm_ports_attached_to_network.assert_called_once_with(created_items) + self.vimconn.nova.servers.delete.assert_called_once_with(vm_id) + mock_delete_created_items.assert_called_once_with( + created_items, volumes_to_hold, False + ) + mock_sleep.assert_not_called() + mock_format_exception.assert_not_called() + mock_extract_items_wth_keep_flag_from_created_items.assert_called_once_with( + initial_created_items + ) + + @patch("time.sleep") + @patch.object(vimconnector, "_extract_items_wth_keep_flag_from_created_items") + @patch.object(vimconnector, "_format_exception") + @patch.object(vimconnector, "_reload_connection") + @patch.object(vimconnector, "_delete_vm_ports_attached_to_network") + @patch.object(vimconnector, "_delete_created_items") + def test_delete_vminstance_extract_items_wth_keep_raises( + self, + mock_delete_created_items, + mock_delete_vm_ports_attached_to_network, + mock_reload_connection, + mock_format_exception, + mock_extract_items_wth_keep_flag_from_created_items, + mock_sleep, + ): + """extract_items_wth_keep_flag_from_created_items raises AttributeError.""" + vm_id = f"{virtual_mac_id}" + initial_created_items = { + f"port{port_id}": True, + f"floating_ip{floating_network_vim_id}": None, + f"volume{volume_id}keep": True, + f"volume{volume_id2}keep": True, + } + + mock_extract_items_wth_keep_flag_from_created_items.side_effect = AttributeError + volumes_to_hold = [] + mock_delete_created_items.return_value = False + with self.assertRaises(AttributeError): + self.vimconn.delete_vminstance( + vm_id, initial_created_items, volumes_to_hold + ) + mock_reload_connection.assert_not_called() + mock_delete_vm_ports_attached_to_network.assert_not_called() + self.vimconn.nova.servers.delete.assert_not_called() + mock_delete_created_items.assert_not_called() + mock_sleep.assert_not_called() + mock_format_exception.assert_not_called() + mock_extract_items_wth_keep_flag_from_created_items.assert_called_once_with( + initial_created_items + ) @patch("time.sleep") + @patch.object(vimconnector, "_extract_items_wth_keep_flag_from_created_items") @patch.object(vimconnector, "_format_exception") @patch.object(vimconnector, "_reload_connection") @patch.object(vimconnector, "_delete_vm_ports_attached_to_network") @@ -5297,25 +5557,31 @@ class TestNewVmInstance(unittest.TestCase): mock_delete_vm_ports_attached_to_network, mock_reload_connection, mock_format_exception, + mock_extract_items_wth_keep_flag_from_created_items, mock_sleep, ): """Delete creted items raises exception.""" vm_id = f"{virtual_mac_id}" created_items = deepcopy(created_items_all_true) + mock_extract_items_wth_keep_flag_from_created_items.return_value = created_items mock_sleep = MagicMock() volumes_to_hold = [] - err = ConnectionError("ClientException occured.") + err = ConnectionError("ClientException occurred.") mock_delete_created_items.side_effect = err with self.assertRaises(ConnectionError) as err: self.vimconn.delete_vminstance(vm_id, created_items, volumes_to_hold) - self.assertEqual(str(err), "ClientException occured.") + self.assertEqual(str(err), "ClientException occurred.") mock_reload_connection.assert_called_once() mock_delete_vm_ports_attached_to_network.assert_called_once_with(created_items) self.vimconn.nova.servers.delete.assert_called_once_with(vm_id) mock_delete_created_items.assert_called_once() mock_sleep.assert_not_called() + mock_extract_items_wth_keep_flag_from_created_items.assert_called_once_with( + created_items + ) @patch("time.sleep") + @patch.object(vimconnector, "_extract_items_wth_keep_flag_from_created_items") @patch.object(vimconnector, "_format_exception") @patch.object(vimconnector, "_reload_connection") @patch.object(vimconnector, "_delete_vm_ports_attached_to_network") @@ -5326,25 +5592,31 @@ class TestNewVmInstance(unittest.TestCase): mock_delete_vm_ports_attached_to_network, mock_reload_connection, mock_format_exception, + mock_extract_items_wth_keep_flag_from_created_items, mock_sleep, ): """Delete vm ports raises exception.""" vm_id = f"{virtual_mac_id}" created_items = deepcopy(created_items_all_true) + mock_extract_items_wth_keep_flag_from_created_items.return_value = created_items volumes_to_hold = [f"{volume_id}", f"{volume_id2}"] - err = ConnectionError("ClientException occured.") + err = ConnectionError("ClientException occurred.") mock_delete_vm_ports_attached_to_network.side_effect = err mock_delete_created_items.side_effect = err with self.assertRaises(ConnectionError) as err: self.vimconn.delete_vminstance(vm_id, created_items, volumes_to_hold) - self.assertEqual(str(err), "ClientException occured.") + self.assertEqual(str(err), "ClientException occurred.") mock_reload_connection.assert_called_once() mock_delete_vm_ports_attached_to_network.assert_called_once_with(created_items) self.vimconn.nova.servers.delete.assert_not_called() mock_delete_created_items.assert_not_called() mock_sleep.assert_not_called() + mock_extract_items_wth_keep_flag_from_created_items.assert_called_once_with( + created_items + ) @patch("time.sleep") + @patch.object(vimconnector, "_extract_items_wth_keep_flag_from_created_items") @patch.object(vimconnector, "_format_exception") @patch.object(vimconnector, "_reload_connection") @patch.object(vimconnector, "_delete_vm_ports_attached_to_network") @@ -5355,25 +5627,31 @@ class TestNewVmInstance(unittest.TestCase): mock_delete_vm_ports_attached_to_network, mock_reload_connection, mock_format_exception, + mock_extract_items_wth_keep_flag_from_created_items, mock_sleep, ): """Nova server delete raises exception.""" vm_id = f"{virtual_mac_id}" created_items = deepcopy(created_items_all_true) + mock_extract_items_wth_keep_flag_from_created_items.return_value = created_items volumes_to_hold = [f"{volume_id}", f"{volume_id2}"] - err = VimConnConnectionException("ClientException occured.") + err = VimConnConnectionException("ClientException occurred.") self.vimconn.nova.servers.delete.side_effect = err mock_delete_created_items.side_effect = err with self.assertRaises(VimConnConnectionException) as err: self.vimconn.delete_vminstance(vm_id, created_items, volumes_to_hold) - self.assertEqual(str(err), "ClientException occured.") + self.assertEqual(str(err), "ClientException occurred.") mock_reload_connection.assert_called_once() mock_delete_vm_ports_attached_to_network.assert_called_once_with(created_items) self.vimconn.nova.servers.delete.assert_called_once_with(vm_id) mock_delete_created_items.assert_not_called() mock_sleep.assert_not_called() + mock_extract_items_wth_keep_flag_from_created_items.assert_called_once_with( + created_items + ) @patch("time.sleep") + @patch.object(vimconnector, "_extract_items_wth_keep_flag_from_created_items") @patch.object(vimconnector, "_format_exception") @patch.object(vimconnector, "_reload_connection") @patch.object(vimconnector, "_delete_vm_ports_attached_to_network") @@ -5384,26 +5662,32 @@ class TestNewVmInstance(unittest.TestCase): mock_delete_vm_ports_attached_to_network, mock_reload_connection, mock_format_exception, + mock_extract_items_wth_keep_flag_from_created_items, mock_sleep, ): """Reload connection raises exception.""" vm_id = f"{virtual_mac_id}" created_items = deepcopy(created_items_all_true) + mock_extract_items_wth_keep_flag_from_created_items.return_value = created_items mock_sleep = MagicMock() volumes_to_hold = [f"{volume_id}", f"{volume_id2}"] - err = ConnectionError("ClientException occured.") + err = ConnectionError("ClientException occurred.") mock_delete_created_items.return_value = False mock_reload_connection.side_effect = err with self.assertRaises(ConnectionError) as err: self.vimconn.delete_vminstance(vm_id, created_items, volumes_to_hold) - self.assertEqual(str(err), "ClientException occured.") + self.assertEqual(str(err), "ClientException occurred.") mock_reload_connection.assert_called_once() mock_delete_vm_ports_attached_to_network.assert_not_called() self.vimconn.nova.servers.delete.assert_not_called() mock_delete_created_items.assert_not_called() mock_sleep.assert_not_called() + mock_extract_items_wth_keep_flag_from_created_items.assert_called_once_with( + created_items + ) @patch("time.sleep") + @patch.object(vimconnector, "_extract_items_wth_keep_flag_from_created_items") @patch.object(vimconnector, "_format_exception") @patch.object(vimconnector, "_reload_connection") @patch.object(vimconnector, "_delete_vm_ports_attached_to_network") @@ -5414,12 +5698,14 @@ class TestNewVmInstance(unittest.TestCase): mock_delete_vm_ports_attached_to_network, mock_reload_connection, mock_format_exception, + mock_extract_items_wth_keep_flag_from_created_items, mock_sleep, ): """created_items and volumes_to_hold are None.""" vm_id = f"{virtual_mac_id}" created_items = None volumes_to_hold = None + mock_extract_items_wth_keep_flag_from_created_items.return_value = {} mock_delete_created_items.return_value = False self.vimconn.delete_vminstance(vm_id, created_items, volumes_to_hold) mock_reload_connection.assert_called_once() @@ -5428,8 +5714,10 @@ class TestNewVmInstance(unittest.TestCase): mock_delete_created_items.assert_called_once_with({}, [], False) mock_sleep.assert_not_called() mock_format_exception.assert_not_called() + mock_extract_items_wth_keep_flag_from_created_items.assert_called_once_with({}) @patch("time.sleep") + @patch.object(vimconnector, "_extract_items_wth_keep_flag_from_created_items") @patch.object(vimconnector, "_format_exception") @patch.object(vimconnector, "_reload_connection") @patch.object(vimconnector, "_delete_vm_ports_attached_to_network") @@ -5440,11 +5728,13 @@ class TestNewVmInstance(unittest.TestCase): mock_delete_vm_ports_attached_to_network, mock_reload_connection, mock_format_exception, + mock_extract_items_wth_keep_flag_from_created_items, mock_sleep, ): """vm_id is None.""" vm_id = None created_items = deepcopy(created_items_all_true) + mock_extract_items_wth_keep_flag_from_created_items.return_value = created_items volumes_to_hold = [f"{volume_id}", f"{volume_id2}"] mock_delete_created_items.side_effect = [True, True, False] self.vimconn.delete_vminstance(vm_id, created_items, volumes_to_hold) @@ -5454,8 +5744,12 @@ class TestNewVmInstance(unittest.TestCase): self.assertEqual(mock_delete_created_items.call_count, 3) self.assertEqual(mock_sleep.call_count, 2) mock_format_exception.assert_not_called() + mock_extract_items_wth_keep_flag_from_created_items.assert_called_once_with( + created_items + ) @patch("time.sleep") + @patch.object(vimconnector, "_extract_items_wth_keep_flag_from_created_items") @patch.object(vimconnector, "_format_exception") @patch.object(vimconnector, "_reload_connection") @patch.object(vimconnector, "_delete_vm_ports_attached_to_network") @@ -5466,11 +5760,13 @@ class TestNewVmInstance(unittest.TestCase): mock_delete_vm_ports_attached_to_network, mock_reload_connection, mock_format_exception, + mock_extract_items_wth_keep_flag_from_created_items, mock_sleep, ): """Delete created items always return True.""" vm_id = None created_items = deepcopy(created_items_all_true) + mock_extract_items_wth_keep_flag_from_created_items.return_value = created_items volumes_to_hold = [f"{volume_id}", f"{volume_id2}"] mock_delete_created_items.side_effect = [True] * 1800 self.vimconn.delete_vminstance(vm_id, created_items, volumes_to_hold) @@ -5480,6 +5776,2085 @@ class TestNewVmInstance(unittest.TestCase): self.assertEqual(mock_delete_created_items.call_count, 1800) self.assertEqual(mock_sleep.call_count, 1800) mock_format_exception.assert_not_called() + mock_extract_items_wth_keep_flag_from_created_items.assert_called_once_with( + created_items + ) + + def test_remove_keep_tag_from_persistent_volumes_keep_flag_exists(self): + """Keep flag exists in created items.""" + created_items = { + f"port:{port_id}": True, + f"floating_ip:{floating_network_vim_id}": True, + f"volume:{volume_id}:keep": True, + f"volume:{volume_id2}:keep": True, + } + expected_result = { + f"port:{port_id}": True, + f"floating_ip:{floating_network_vim_id}": True, + f"volume:{volume_id}": True, + f"volume:{volume_id2}": True, + } + result = self.vimconn.remove_keep_tag_from_persistent_volumes(created_items) + self.assertDictEqual(result, expected_result) + + def test_remove_keep_tag_from_persistent_volumes_without_keep_flag(self): + """Keep flag does not exist in created items.""" + created_items = { + f"port:{port_id}": True, + f"floating_ip:{floating_network_vim_id}": True, + f"volume:{volume_id}": True, + f"volume:{volume_id2}": True, + } + result = self.vimconn.remove_keep_tag_from_persistent_volumes(created_items) + self.assertDictEqual(result, created_items) + + def test_update_block_device_mapping_empty_volume(self): + volume = "" + block_device_mapping = {} + base_disk_index = 100 + disk = {} + created_items = {} + with self.assertRaises(VimConnException) as err: + self.vimconn.update_block_device_mapping( + volume, block_device_mapping, base_disk_index, disk, created_items + ) + self.assertEqual(str(err), "Volume is empty.") + self.assertEqual(block_device_mapping, {}) + self.assertEqual(created_items, {}) + + def test_update_block_device_mapping_invalid_volume(self): + volume = "Volume-A" + block_device_mapping = {} + base_disk_index = 100 + disk = {} + created_items = {} + with self.assertRaises(VimConnException) as err: + self.vimconn.update_block_device_mapping( + volume, block_device_mapping, base_disk_index, disk, created_items + ) + self.assertEqual( + str(err), "Created volume is not valid, does not have id attribute." + ) + self.assertEqual(block_device_mapping, {}) + self.assertEqual(created_items, {}) + + def test_update_block_device_mapping(self): + volume = MagicMock(autospec=True) + volume.id = volume_id + block_device_mapping = {} + base_disk_index = 100 + disk = {} + created_items = {} + self.vimconn.update_block_device_mapping( + volume, block_device_mapping, base_disk_index, disk, created_items + ) + self.assertEqual( + block_device_mapping, {"vdd": "ac408b73-b9cc-4a6a-a270-82cc4811bd4a"} + ) + self.assertEqual( + created_items, {"volume:ac408b73-b9cc-4a6a-a270-82cc4811bd4a": True} + ) + + def test_update_block_device_mapping_with_keep_flag(self): + volume = MagicMock(autospec=True) + volume.id = volume_id + block_device_mapping = {} + base_disk_index = 100 + disk = {"size": 10, "keep": True} + created_items = {} + self.vimconn.update_block_device_mapping( + volume, block_device_mapping, base_disk_index, disk, created_items + ) + self.assertEqual( + block_device_mapping, {"vdd": "ac408b73-b9cc-4a6a-a270-82cc4811bd4a"} + ) + self.assertEqual( + created_items, {"volume:ac408b73-b9cc-4a6a-a270-82cc4811bd4a:keep": True} + ) + + def test_extract_items_with_keep_flag_item_has_keep_flag(self): + created_items = deepcopy(created_items_all_true) + created_items[f"volume:{volume_id2}:keep"] = True + result = self.vimconn._extract_items_wth_keep_flag_from_created_items( + created_items + ) + self.assertEqual(result, deepcopy(created_items_all_true)) + + def test_extract_items_with_keep_flag_no_item_wth_keep_flag(self): + created_items = deepcopy(created_items_all_true) + result = self.vimconn._extract_items_wth_keep_flag_from_created_items( + created_items + ) + self.assertEqual(result, deepcopy(created_items_all_true)) + + def test_extract_items_with_keep_flag_all_items_are_already_deleted(self): + created_items = { + f"port:{port_id}": None, + f"floating_ip:{floating_network_vim_id}": None, + f"volume:{volume_id}:keep": None, + f"volume:{volume_id2}:keep": None, + } + expected_result = { + f"port:{port_id}": None, + f"floating_ip:{floating_network_vim_id}": None, + } + result = self.vimconn._extract_items_wth_keep_flag_from_created_items( + created_items + ) + self.assertEqual(result, expected_result) + + def test_extract_items_with_keep_flag_without_semicolon(self): + created_items = { + f"port{port_id}": True, + f"floating_ip{floating_network_vim_id}": None, + f"volume{volume_id}keep": True, + f"volume{volume_id2}keep": True, + } + result = self.vimconn._extract_items_wth_keep_flag_from_created_items( + created_items + ) + self.assertEqual(result, {}) + + def test_extract_items_with_keep_flag_invalid_type_created_items(self): + created_items = [{f"port{port_id}": True}, {f"volume{volume_id2}keep": True}] + with self.assertRaises(AttributeError): + self.vimconn._extract_items_wth_keep_flag_from_created_items(created_items) + + @patch.object(vimconnector, "_reload_connection", new_callable=CopyingMock()) + def test_get_monitoring_data(self, mock_reload_conection): + servers = ["server1", "server2"] + ports = {"ports": ["port1", "port2"]} + self.vimconn.nova.servers.list.return_value = servers + self.vimconn.neutron.list_ports.return_value = ports + result = self.vimconn.get_monitoring_data() + self.assertTupleEqual(result, (servers, ports)) + mock_reload_conection.assert_called_once() + self.vimconn.nova.servers.list.assert_called_once_with(detailed=True) + self.vimconn.neutron.list_ports.assert_called_once() + + @patch.object(vimconnector, "_reload_connection", new_callable=CopyingMock()) + def test_get_monitoring_data_reload_connection_raises(self, mock_reload_conection): + mock_reload_conection.side_effect = VimConnNotFoundException( + "Connection object not found." + ) + with self.assertRaises(VimConnException) as err: + result = self.vimconn.get_monitoring_data() + self.assertTupleEqual(result, None) + self.assertEqual( + str(err.exception.args[0]), + "Exception in monitoring while getting VMs and ports status: Connection object not found.", + ) + mock_reload_conection.assert_called_once() + check_if_assert_not_called( + [self.vimconn.nova.servers.list, self.vimconn.neutron.list_ports] + ) + + @patch.object(vimconnector, "_reload_connection", new_callable=CopyingMock()) + def test_get_monitoring_data_server_list_raises(self, mock_reload_conection): + self.vimconn.nova.servers.list.side_effect = VimConnConnectionException( + "Can not connect to Cloud API." + ) + with self.assertRaises(VimConnException) as err: + result = self.vimconn.get_monitoring_data() + self.assertTupleEqual(result, None) + self.assertEqual( + str(err.exception.args[0]), + "Exception in monitoring while getting VMs and ports status: Can not connect to Cloud API.", + ) + mock_reload_conection.assert_called_once() + self.vimconn.nova.servers.list.assert_called_once_with(detailed=True) + self.vimconn.neutron.list_ports.assert_not_called() + + @patch.object(vimconnector, "_reload_connection", new_callable=CopyingMock()) + def test_get_monitoring_data_list_ports_raises(self, mock_reload_conection): + self.vimconn.neutron.list_ports.side_effect = VimConnConnectionException( + "Can not connect to Cloud API." + ) + with self.assertRaises(VimConnException) as err: + result = self.vimconn.get_monitoring_data() + self.assertTupleEqual(result, None) + self.assertEqual( + str(err.exception.args[0]), + "Exception in monitoring while getting VMs and ports status: Can not connect to Cloud API.", + ) + mock_reload_conection.assert_called_once() + self.vimconn.nova.servers.list.assert_called_once_with(detailed=True) + self.vimconn.neutron.list_ports.assert_called_once() + + +class TestNewFlavor(unittest.TestCase): + @patch("logging.getLogger", autospec=True) + def setUp(self, mock_logger): + # We are disabling the logging of exception not to print them to console. + mock_logger = logging.getLogger() + mock_logger.disabled = True + self.vimconn = vimconnector( + "123", + "openstackvim", + "456", + "789", + "http://dummy.url", + None, + "user", + "pass", + ) + self.vimconn.nova = CopyingMock(autospec=True) + self.flavor1 = CopyingMock(autospec=True, name="sample-flavor") + self.flavor2 = CopyingMock(autospec=True, name="other-flavor") + self.new_flavor = CopyingMock(autospec=True, name="new_flavor") + self.new_flavor.id = "075d2482-5edb-43e3-91b3-234e65b6268a" + self.vimconn.nova.flavors.create.return_value = self.new_flavor + + @patch.object(vimconnector, "process_vio_numa_nodes", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_memory", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_vcpu", new_callable=CopyingMock()) + @patch.object( + vimconnector, + "process_numa_paired_threads", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "process_numa_cores", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_threads", new_callable=CopyingMock()) + def test_process_numa_parameters_of_flavor_id_memory_vcpu_in_numa_type_vio( + self, + mock_process_numa_threads, + mock_process_numa_cores, + mock_process_numa_paired_threads, + mock_process_numa_vcpu, + mock_process_numa_memory, + mock_process_vio_numa_nodes, + ): + """Process numa parameters, id, memory, vcpu exist, vim type is VIO, + paired-threads, cores, threads do not exist in numa. + """ + numas = [ + {"id": 0, "memory": 1, "vcpu": [1, 3]}, + {"id": 1, "memory": 2, "vcpu": [2]}, + ] + extra_specs = {} + expected_extra_specs = { + "hw:numa_nodes": "2", + "hw:cpu_sockets": "2", + } + self.vimconn.vim_type = "VIO" + self.vimconn._process_numa_parameters_of_flavor(numas, extra_specs) + + self.assertEqual(mock_process_numa_memory.call_count, 2) + self.assertEqual(mock_process_numa_vcpu.call_count, 2) + mock_process_vio_numa_nodes.assert_called_once_with(2, {"hw:numa_nodes": "2"}) + _call_mock_process_numa_memory = mock_process_numa_memory.call_args_list + self.assertEqual( + _call_mock_process_numa_memory[0].args, + ( + {"id": 0, "memory": 1, "vcpu": [1, 3]}, + 0, + { + "hw:numa_nodes": "2", + }, + ), + ) + self.assertEqual( + _call_mock_process_numa_memory[1].args, + ( + {"id": 1, "memory": 2, "vcpu": [2]}, + 1, + { + "hw:cpu_sockets": "2", + "hw:numa_nodes": "2", + }, + ), + ) + _call_mock_process_numa_vcpu = mock_process_numa_vcpu.call_args_list + self.assertEqual( + _call_mock_process_numa_vcpu[0].args, + ( + {"id": 0, "memory": 1, "vcpu": [1, 3]}, + 0, + { + "hw:numa_nodes": "2", + }, + ), + ) + self.assertEqual( + _call_mock_process_numa_vcpu[1].args, + ( + {"id": 1, "memory": 2, "vcpu": [2]}, + 1, + { + "hw:cpu_sockets": "2", + "hw:numa_nodes": "2", + }, + ), + ) + self.assertDictEqual(extra_specs, expected_extra_specs) + check_if_assert_not_called( + [ + mock_process_numa_threads, + mock_process_numa_cores, + mock_process_numa_paired_threads, + ] + ) + + @patch.object(vimconnector, "process_vio_numa_nodes", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_memory", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_vcpu", new_callable=CopyingMock()) + @patch.object( + vimconnector, + "process_numa_paired_threads", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "process_numa_cores", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_threads", new_callable=CopyingMock()) + def test_process_numa_parameters_of_flavor_id_memory_vcpu_in_numa_type_openstack( + self, + mock_process_numa_threads, + mock_process_numa_cores, + mock_process_numa_paired_threads, + mock_process_numa_vcpu, + mock_process_numa_memory, + mock_process_vio_numa_nodes, + ): + """Process numa parameters, id, memory, vcpu exist, vim type is openstack, + paired-threads, cores, threads do not exist in numa. + """ + numas = [ + {"id": 0, "memory": 1, "vcpu": [1, 3]}, + {"id": 1, "memory": 2, "vcpu": [2]}, + ] + extra_specs = {} + expected_extra_specs = { + "hw:numa_nodes": "2", + "hw:cpu_sockets": "2", + } + self.vimconn.vim_type = "openstack" + self.vimconn._process_numa_parameters_of_flavor(numas, extra_specs) + + self.assertEqual(mock_process_numa_memory.call_count, 2) + self.assertEqual(mock_process_numa_vcpu.call_count, 2) + _call_mock_process_numa_memory = mock_process_numa_memory.call_args_list + self.assertEqual( + _call_mock_process_numa_memory[0].args, + ( + {"id": 0, "memory": 1, "vcpu": [1, 3]}, + 0, + {"hw:numa_nodes": "2"}, + ), + ) + self.assertEqual( + _call_mock_process_numa_memory[1].args, + ( + {"id": 1, "memory": 2, "vcpu": [2]}, + 1, + {"hw:cpu_sockets": "2", "hw:numa_nodes": "2"}, + ), + ) + _call_mock_process_numa_vcpu = mock_process_numa_vcpu.call_args_list + self.assertEqual( + _call_mock_process_numa_vcpu[0].args, + ( + {"id": 0, "memory": 1, "vcpu": [1, 3]}, + 0, + {"hw:numa_nodes": "2"}, + ), + ) + self.assertEqual( + _call_mock_process_numa_vcpu[1].args, + ( + {"id": 1, "memory": 2, "vcpu": [2]}, + 1, + {"hw:cpu_sockets": "2", "hw:numa_nodes": "2"}, + ), + ) + self.assertDictEqual(extra_specs, expected_extra_specs) + check_if_assert_not_called( + [ + mock_process_numa_threads, + mock_process_numa_cores, + mock_process_numa_paired_threads, + ] + ) + + @patch.object(vimconnector, "process_vio_numa_nodes", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_memory", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_vcpu", new_callable=CopyingMock()) + @patch.object( + vimconnector, + "process_numa_paired_threads", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "process_numa_cores", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_threads", new_callable=CopyingMock()) + def test_process_numa_parameters_of_flavor_id_paired_threads_in_numa_type_openstack_extra_spec_not_empty( + self, + mock_process_numa_threads, + mock_process_numa_cores, + mock_process_numa_paired_threads, + mock_process_numa_vcpu, + mock_process_numa_memory, + mock_process_vio_numa_nodes, + ): + """Process numa parameters, id, paired-threads exist, vim type is openstack. + vcpus calculation according to paired-threads in numa, there is extra_spec. + .""" + numas = [{"id": 0, "paired-threads": 3}, {"id": 1, "paired-threads": 3}] + extra_specs = {"some-key": "some-value"} + expected_extra_specs = { + "hw:cpu_sockets": "2", + "hw:cpu_threads": "12", + "hw:numa_nodes": "2", + "some-key": "some-value", + } + self.vimconn.vim_type = "openstack" + mock_process_numa_paired_threads.side_effect = [6, 6] + self.vimconn._process_numa_parameters_of_flavor(numas, extra_specs) + + check_if_assert_not_called([mock_process_numa_threads, mock_process_numa_cores]) + self.assertEqual(mock_process_numa_memory.call_count, 2) + self.assertEqual(mock_process_numa_vcpu.call_count, 2) + self.assertEqual(mock_process_numa_paired_threads.call_count, 2) + _call_mock_process_numa_paired_threads = ( + mock_process_numa_paired_threads.call_args_list + ) + self.assertEqual( + _call_mock_process_numa_paired_threads[0].args, + ( + {"id": 0, "paired-threads": 3}, + {"hw:cpu_sockets": "2", "hw:numa_nodes": "2", "some-key": "some-value"}, + ), + ) + self.assertEqual( + _call_mock_process_numa_paired_threads[1].args, + ( + {"id": 1, "paired-threads": 3}, + {"hw:cpu_sockets": "2", "hw:numa_nodes": "2", "some-key": "some-value"}, + ), + ) + self.assertDictEqual(extra_specs, expected_extra_specs) + + @patch.object(vimconnector, "process_vio_numa_nodes", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_memory", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_vcpu", new_callable=CopyingMock()) + @patch.object( + vimconnector, + "process_numa_paired_threads", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "process_numa_cores", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_threads", new_callable=CopyingMock()) + def test_process_numa_parameters_of_flavor_id_paired_threads_in_numa_type_vio_extra_spec_not_empty( + self, + mock_process_numa_threads, + mock_process_numa_cores, + mock_process_numa_paired_threads, + mock_process_numa_vcpu, + mock_process_numa_memory, + mock_process_vio_numa_nodes, + ): + """Process numa parameters, id, paired-threads exist, vim type is VIO. + vcpus calculation according to paired-threads in numa, there is extra_spec. + """ + numas = [{"id": 0, "paired-threads": 2}, {"id": 1, "paired-threads": 2}] + extra_specs = {"some-key": "some-value"} + expected_extra_specs = { + "hw:numa_nodes": "2", + "hw:cpu_sockets": "2", + "hw:cpu_threads": "8", + "some-key": "some-value", + } + self.vimconn.vim_type = "VIO" + mock_process_numa_paired_threads.side_effect = [4, 4] + self.vimconn._process_numa_parameters_of_flavor(numas, extra_specs) + check_if_assert_not_called([mock_process_numa_threads, mock_process_numa_cores]) + self.assertEqual(mock_process_numa_paired_threads.call_count, 2) + self.assertEqual(mock_process_numa_memory.call_count, 2) + self.assertEqual(mock_process_numa_vcpu.call_count, 2) + _call_mock_process_numa_paired_threads = ( + mock_process_numa_paired_threads.call_args_list + ) + mock_process_vio_numa_nodes.assert_called_once_with( + 2, {"some-key": "some-value", "hw:numa_nodes": "2"} + ) + self.assertEqual( + _call_mock_process_numa_paired_threads[0].args, + ( + {"id": 0, "paired-threads": 2}, + { + "hw:cpu_sockets": "2", + "hw:numa_nodes": "2", + "some-key": "some-value", + }, + ), + ) + self.assertEqual( + _call_mock_process_numa_paired_threads[1].args, + ( + {"id": 1, "paired-threads": 2}, + { + "hw:cpu_sockets": "2", + "hw:numa_nodes": "2", + "some-key": "some-value", + }, + ), + ) + self.assertDictEqual(extra_specs, expected_extra_specs) + + @patch.object(vimconnector, "process_vio_numa_nodes", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_memory", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_vcpu", new_callable=CopyingMock()) + @patch.object( + vimconnector, + "process_numa_paired_threads", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "process_numa_cores", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_threads", new_callable=CopyingMock()) + def test_process_numa_parameters_of_flavor_id_cores_in_numa_type_openstack( + self, + mock_process_numa_threads, + mock_process_numa_cores, + mock_process_numa_paired_threads, + mock_process_numa_vcpu, + mock_process_numa_memory, + mock_process_vio_numa_nodes, + ): + """Process numa parameters, id, cores exist, vim type is openstack. + vcpus calculation according to cores in numa. + """ + numas = [{"id": 0, "cores": 1}, {"id": 1, "cores": 2}] + extra_specs = {} + updated_extra_specs = {"hw:numa_nodes": "2", "hw:cpu_sockets": "2"} + expected_extra_specs = { + "hw:numa_nodes": "2", + "hw:cpu_sockets": "2", + "hw:cpu_cores": "3", + } + self.vimconn.vim_type = "openstack" + mock_process_numa_cores.side_effect = [1, 2] + self.vimconn._process_numa_parameters_of_flavor(numas, extra_specs) + + check_if_assert_not_called( + [mock_process_numa_threads, mock_process_numa_paired_threads] + ) + self.assertEqual(mock_process_numa_cores.call_count, 2) + self.assertEqual(mock_process_numa_memory.call_count, 2) + self.assertEqual(mock_process_numa_vcpu.call_count, 2) + _call_mock_process_numa_cores = mock_process_numa_cores.call_args_list + self.assertEqual( + _call_mock_process_numa_cores[0].args, + ({"id": 0, "cores": 1}, updated_extra_specs), + ) + self.assertEqual( + _call_mock_process_numa_cores[1].args, + ({"id": 1, "cores": 2}, updated_extra_specs), + ) + self.assertDictEqual(extra_specs, expected_extra_specs) + + @patch.object(vimconnector, "process_vio_numa_nodes", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_memory", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_vcpu", new_callable=CopyingMock()) + @patch.object( + vimconnector, + "process_numa_paired_threads", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "process_numa_cores", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_threads", new_callable=CopyingMock()) + def test_process_numa_parameters_of_flavor_id_cores_in_numa_type_vio( + self, + mock_process_numa_threads, + mock_process_numa_cores, + mock_process_numa_paired_threads, + mock_process_numa_vcpu, + mock_process_numa_memory, + mock_process_vio_numa_nodes, + ): + """Process numa parameters, id, cores exist, vim type is VIO. + vcpus calculation according to cores in numa. + """ + numas = [{"id": 0, "cores": 1}, {"id": 1, "cores": 2}] + extra_specs = {} + expected_extra_specs = { + "hw:cpu_cores": "3", + "hw:cpu_sockets": "2", + "hw:numa_nodes": "2", + } + self.vimconn.vim_type = "VIO" + mock_process_numa_cores.side_effect = [1, 2] + self.vimconn._process_numa_parameters_of_flavor(numas, extra_specs) + check_if_assert_not_called( + [mock_process_numa_threads, mock_process_numa_paired_threads] + ) + self.assertEqual(mock_process_numa_memory.call_count, 2) + self.assertEqual(mock_process_numa_vcpu.call_count, 2) + self.assertEqual(mock_process_numa_cores.call_count, 2) + mock_process_vio_numa_nodes.assert_called_once_with(2, {"hw:numa_nodes": "2"}) + _call_mock_process_numa_cores = mock_process_numa_cores.call_args_list + self.assertEqual( + _call_mock_process_numa_cores[0].args, + ( + {"id": 0, "cores": 1}, + { + "hw:cpu_sockets": "2", + "hw:numa_nodes": "2", + }, + ), + ) + self.assertEqual( + _call_mock_process_numa_cores[1].args, + ( + {"id": 1, "cores": 2}, + { + "hw:cpu_sockets": "2", + "hw:numa_nodes": "2", + }, + ), + ) + self.assertDictEqual(extra_specs, expected_extra_specs) + + @patch.object(vimconnector, "process_vio_numa_nodes", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_memory", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_vcpu", new_callable=CopyingMock()) + @patch.object( + vimconnector, + "process_numa_paired_threads", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "process_numa_cores", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_threads", new_callable=CopyingMock()) + def test_process_numa_parameters_of_flavor_without_numa_id_with_threads_type_vio( + self, + mock_process_numa_threads, + mock_process_numa_cores, + mock_process_numa_paired_threads, + mock_process_numa_vcpu, + mock_process_numa_memory, + mock_process_vio_numa_nodes, + ): + """Process numa parameters, memory, vcpu, thread exist, vim type is VIO, + vcpus calculation according threads in numa, there are not numa ids. + """ + numas = [ + {"memory": 1, "vcpu": [1, 3], "threads": 3}, + {"memory": 2, "vcpu": [2]}, + ] + extra_specs = {} + expected_extra_specs = { + "hw:numa_nodes": "2", + "hw:cpu_sockets": "2", + "hw:cpu_threads": "3", + } + self.vimconn.vim_type = "VIO" + mock_process_numa_threads.return_value = 3 + self.vimconn._process_numa_parameters_of_flavor(numas, extra_specs) + check_if_assert_not_called( + [ + mock_process_numa_memory, + mock_process_numa_vcpu, + mock_process_numa_cores, + mock_process_numa_paired_threads, + ] + ) + mock_process_vio_numa_nodes.assert_called_once_with(2, {"hw:numa_nodes": "2"}) + self.assertEqual(mock_process_numa_threads.call_count, 1) + _call_mock_process_numa_threads = mock_process_numa_threads.call_args_list + self.assertEqual( + _call_mock_process_numa_threads[0].args, + ( + {"memory": 1, "vcpu": [1, 3], "threads": 3}, + { + "hw:cpu_sockets": "2", + "hw:numa_nodes": "2", + }, + ), + ) + self.assertDictEqual(extra_specs, expected_extra_specs) + + @patch.object(vimconnector, "process_vio_numa_nodes", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_memory", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_vcpu", new_callable=CopyingMock()) + @patch.object( + vimconnector, + "process_numa_paired_threads", + new_callable=CopyingMock(autospec=True), + ) + @patch.object(vimconnector, "process_numa_cores", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_threads", new_callable=CopyingMock()) + def test_process_numa_parameters_of_flavor_without_numa_id_with_threads_type_openstack( + self, + mock_process_numa_threads, + mock_process_numa_cores, + mock_process_numa_paired_threads, + mock_process_numa_vcpu, + mock_process_numa_memory, + mock_process_vio_numa_nodes, + ): + """Process numa parameters, memory, vcpu, thread exist, vim type is openstack, + vcpus calculation according threads in numa, there are not numa ids. + """ + numas = [ + {"memory": 1, "vcpu": [1, 3], "threads": 3}, + {"memory": 2, "vcpu": [2]}, + ] + extra_specs = {} + expected_extra_specs = { + "hw:numa_nodes": "2", + "hw:cpu_sockets": "2", + "hw:cpu_threads": "3", + } + self.vimconn.vim_type = "openstack" + mock_process_numa_threads.return_value = 3 + self.vimconn._process_numa_parameters_of_flavor(numas, extra_specs) + + check_if_assert_not_called( + [ + mock_process_numa_memory, + mock_process_numa_vcpu, + mock_process_numa_cores, + mock_process_numa_paired_threads, + mock_process_vio_numa_nodes, + ] + ) + self.assertEqual(mock_process_numa_threads.call_count, 1) + _call_mock_process_numa_threads = mock_process_numa_threads.call_args_list + self.assertEqual( + _call_mock_process_numa_threads[0].args, + ( + {"memory": 1, "vcpu": [1, 3], "threads": 3}, + {"hw:cpu_sockets": "2", "hw:numa_nodes": "2"}, + ), + ) + self.assertDictEqual(extra_specs, expected_extra_specs) + + @patch.object(vimconnector, "process_vio_numa_nodes", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_memory", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_vcpu", new_callable=CopyingMock()) + @patch.object( + vimconnector, + "process_numa_paired_threads", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "process_numa_cores", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_threads", new_callable=CopyingMock()) + def test_process_numa_parameters_of_flavor_empty_numas_list_type_vio( + self, + mock_process_numa_threads, + mock_process_numa_cores, + mock_process_numa_paired_threads, + mock_process_numa_vcpu, + mock_process_numa_memory, + mock_process_vio_numa_nodes, + ): + """Numa list is empty, vim type is VIO.""" + numas = [] + extra_specs = {} + expected_extra_specs = {"hw:numa_nodes": "0"} + self.vimconn.vim_type = "VIO" + self.vimconn._process_numa_parameters_of_flavor(numas, extra_specs) + check_if_assert_not_called( + [ + mock_process_numa_memory, + mock_process_numa_vcpu, + mock_process_numa_cores, + mock_process_numa_paired_threads, + mock_process_numa_threads, + ] + ) + mock_process_vio_numa_nodes.assert_called_once_with(0, {"hw:numa_nodes": "0"}) + self.assertDictEqual(extra_specs, expected_extra_specs) + + @patch.object(vimconnector, "process_vio_numa_nodes", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_memory", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_vcpu", new_callable=CopyingMock()) + @patch.object( + vimconnector, + "process_numa_paired_threads", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "process_numa_cores", new_callable=CopyingMock()) + @patch.object(vimconnector, "process_numa_threads", new_callable=CopyingMock()) + def test_process_numa_parameters_of_flavor_empty_numas_list_type_openstack( + self, + mock_process_numa_threads, + mock_process_numa_cores, + mock_process_numa_paired_threads, + mock_process_numa_vcpu, + mock_process_numa_memory, + mock_process_vio_numa_nodes, + ): + """Numa list is empty, vim type is openstack.""" + numas = [] + extra_specs = {} + expected_extra_specs = {"hw:numa_nodes": "0"} + self.vimconn.vim_type = "openstack" + mock_process_numa_threads.return_value = None + self.vimconn._process_numa_parameters_of_flavor(numas, extra_specs) + + check_if_assert_not_called( + [ + mock_process_numa_memory, + mock_process_numa_vcpu, + mock_process_numa_cores, + mock_process_numa_paired_threads, + mock_process_numa_threads, + mock_process_vio_numa_nodes, + ] + ) + self.assertDictEqual(extra_specs, expected_extra_specs) + + def test_process_numa_memory_empty_extra_spec(self): + numa = {"memory": 2, "vcpu": [2]} + node_id = 2 + extra_specs = {} + expected_extra_spec = {"hw:numa_mem.2": 2048} + self.vimconn.process_numa_memory(numa, node_id, extra_specs) + self.assertDictEqual(extra_specs, expected_extra_spec) + + def test_process_numa_memory_not_exist(self): + numa = {"vcpu": [2]} + node_id = 2 + extra_specs = {"vmware:latency_sensitivity_level": "high"} + self.vimconn.process_numa_memory(numa, node_id, extra_specs) + self.assertDictEqual(extra_specs, {"vmware:latency_sensitivity_level": "high"}) + + def test_process_numa_memory_node_id_is_none(self): + numa = {"memory": 2, "vcpu": [2]} + node_id = None + extra_specs = {} + expected_extra_spec = {"hw:numa_mem.None": 2048} + self.vimconn.process_numa_memory(numa, node_id, extra_specs) + self.assertDictEqual(extra_specs, expected_extra_spec) + + def test_process_numa_vcpu_empty_extra_spec(self): + numa = {"vcpu": [2]} + node_id = 0 + extra_specs = {} + expected_extra_spec = {"hw:numa_cpus.0": "2"} + self.vimconn.process_numa_vcpu(numa, node_id, extra_specs) + self.assertDictEqual(extra_specs, expected_extra_spec) + + def test_process_numa_vcpu_not_exist(self): + numa = {"memory": 2} + node_id = 0 + extra_specs = {"vmware:latency_sensitivity_level": "high"} + expected_extra_spec = {"vmware:latency_sensitivity_level": "high"} + self.vimconn.process_numa_vcpu(numa, node_id, extra_specs) + self.assertDictEqual(extra_specs, expected_extra_spec) + + def test_process_numa_vcpu_empty_node_id(self): + numa = {"vcpu": [2]} + node_id = "" + extra_specs = {} + expected_extra_spec = {"hw:numa_cpus.": "2"} + self.vimconn.process_numa_vcpu(numa, node_id, extra_specs) + self.assertDictEqual(extra_specs, expected_extra_spec) + + def test_process_numa_vcpu_empty_numa_dict(self): + numa = {} + node_id = 4 + extra_specs = {} + self.vimconn.process_numa_vcpu(numa, node_id, extra_specs) + self.assertDictEqual(extra_specs, {}) + + def test_process_numa_vcpu_str_node_id(self): + numa = {"vcpu": [2]} + node_id = "12" + extra_specs = {} + expected_extra_spec = {"hw:numa_cpus.12": "2"} + self.vimconn.process_numa_vcpu(numa, node_id, extra_specs) + self.assertDictEqual(extra_specs, expected_extra_spec) + + def test_process_numa_paired_threads_empty_extra_spec(self): + numa = {"id": 0, "paired-threads": 3} + extra_specs = {} + expected_extra_spec = { + "hw:cpu_thread_policy": "require", + "hw:cpu_policy": "dedicated", + } + result = self.vimconn.process_numa_paired_threads(numa, extra_specs) + self.assertDictEqual(extra_specs, expected_extra_spec) + self.assertEqual(result, 6) + + def test_process_numa_paired_threads_empty_numa(self): + numa = {} + extra_specs = {} + result = self.vimconn.process_numa_paired_threads(numa, extra_specs) + self.assertDictEqual(extra_specs, {}) + self.assertEqual(result, None) + + def test_process_numa_paired_threads_not_exist(self): + numa = {"vcpu": [2]} + extra_specs = {} + result = self.vimconn.process_numa_paired_threads(numa, extra_specs) + self.assertDictEqual(extra_specs, {}) + self.assertEqual(result, None) + + def test_process_numa_paired_threads_str_thread_num(self): + numa = {"id": 0, "paired-threads": "3"} + extra_specs = {} + expected_extra_spec = { + "hw:cpu_thread_policy": "require", + "hw:cpu_policy": "dedicated", + } + result = self.vimconn.process_numa_paired_threads(numa, extra_specs) + self.assertDictEqual(extra_specs, expected_extra_spec) + self.assertEqual(result, "33") + + def test_process_numa_paired_threads_none_thread_num(self): + numa = {"id": 0, "paired-threads": None} + extra_specs = {} + result = self.vimconn.process_numa_paired_threads(numa, extra_specs) + self.assertDictEqual(extra_specs, {}) + self.assertEqual(result, None) + + def test_process_numa_cores_empty_extra_spec(self): + numa = {"id": 0, "cores": 1} + extra_specs = {} + expected_extra_spec = { + "hw:cpu_policy": "dedicated", + "hw:cpu_thread_policy": "isolate", + } + result = self.vimconn.process_numa_cores(numa, extra_specs) + self.assertDictEqual(extra_specs, expected_extra_spec) + self.assertEqual(result, 1) + + def test_process_numa_cores_not_exist(self): + numa = {"id": 0, "paired-threads": 3} + extra_specs = {} + result = self.vimconn.process_numa_cores(numa, extra_specs) + self.assertDictEqual(extra_specs, {}) + self.assertEqual(result, None) + + def test_process_numa_cores_empty_numa(self): + numa = {} + extra_specs = expected_extra_spec = {"some-key": "some-val"} + result = self.vimconn.process_numa_cores(numa, extra_specs) + self.assertDictEqual(extra_specs, expected_extra_spec) + self.assertEqual(result, None) + + def test_process_numa_cores_none_core_num(self): + numa = {"memory": 1, "cores": None} + extra_specs = {} + result = self.vimconn.process_numa_cores(numa, extra_specs) + self.assertDictEqual(extra_specs, {}) + self.assertEqual(result, None) + + def test_process_numa_cores_string_core_num(self): + numa = {"id": 0, "cores": "1"} + extra_specs = {"some-key": "some-val"} + expected_extra_spec = { + "hw:cpu_policy": "dedicated", + "hw:cpu_thread_policy": "isolate", + "some-key": "some-val", + } + result = self.vimconn.process_numa_cores(numa, extra_specs) + self.assertDictEqual(extra_specs, expected_extra_spec) + self.assertEqual(result, "1") + + def test_process_numa_cores_float_core_num(self): + numa = {"memory": 2, "cores": 10.03} + extra_specs = {"some-key": "some-val"} + expected_extra_spec = { + "hw:cpu_policy": "dedicated", + "hw:cpu_thread_policy": "isolate", + "some-key": "some-val", + } + result = self.vimconn.process_numa_cores(numa, extra_specs) + self.assertDictEqual(extra_specs, expected_extra_spec) + self.assertEqual(result, 10.03) + + def test_process_numa_threads_empty_extra_spec_int_thread_num(self): + numa = {"memory": 1, "vcpu": [1, 3], "threads": 3} + extra_specs = {} + expected_extra_spec = { + "hw:cpu_policy": "dedicated", + "hw:cpu_thread_policy": "prefer", + } + result = self.vimconn.process_numa_threads(numa, extra_specs) + self.assertDictEqual(extra_specs, expected_extra_spec) + self.assertEqual(result, 3) + + def test_process_numa_threads_empty_numa(self): + numa = {} + extra_specs = {"some-key": "some-val"} + expected_extra_spec = {"some-key": "some-val"} + result = self.vimconn.process_numa_threads(numa, extra_specs) + self.assertDictEqual(extra_specs, expected_extra_spec) + self.assertEqual(result, None) + + def test_process_numa_threads_not_exist(self): + numa = {"memory": 1} + extra_specs = expected_extra_spec = {"some-key": "some-val"} + result = self.vimconn.process_numa_threads(numa, extra_specs) + self.assertDictEqual(extra_specs, expected_extra_spec) + self.assertEqual(result, None) + + def test_process_numa_threads_str_thread_num(self): + numa = {"vcpu": [1, 3], "threads": "3"} + extra_specs = {} + expected_extra_spec = { + "hw:cpu_policy": "dedicated", + "hw:cpu_thread_policy": "prefer", + } + result = self.vimconn.process_numa_threads(numa, extra_specs) + self.assertDictEqual(extra_specs, expected_extra_spec) + self.assertEqual(result, "3") + + def test_process_numa_threads_none_thread_num(self): + numa = {"vcpu": [1, 3], "threads": None} + extra_specs = {} + result = self.vimconn.process_numa_threads(numa, extra_specs) + self.assertDictEqual(extra_specs, {}) + self.assertEqual(result, None) + + def test_process_numa_threads_float_thread_num(self): + numa = {"memory": 1, "vcpu": [1, 3], "threads": 3.3} + extra_specs = {"some-key": "some-val"} + expected_extra_spec = { + "hw:cpu_policy": "dedicated", + "hw:cpu_thread_policy": "prefer", + "some-key": "some-val", + } + result = self.vimconn.process_numa_threads(numa, extra_specs) + self.assertDictEqual(extra_specs, expected_extra_spec) + self.assertEqual(result, 3.3) + + def test_change_the_flavor_name_not_existing_name(self): + """Flavor name does not exist in Openstack flavor list.""" + self.flavor1.name = "sample-flavor-3" + self.flavor2.name = "other-flavor-4" + self.vimconn.nova.flavors.list.return_value = [self.flavor1, self.flavor2] + name = "other-flavor-3" + name_suffix = 3 + flavor_data = {"name": "other-flavor"} + result = self.vimconn._change_flavor_name(name, name_suffix, flavor_data) + self.assertEqual(result, name) + self.vimconn.nova.flavors.list.assert_called_once() + # Checking whether name_suffix changed or not. + self.assertEqual(name_suffix, 3) + + def test_change_the_flavor_name_existing_name(self): + """Flavor name exists in Openstack flavor list.""" + self.flavor1.name = "other-flavor-6" + self.flavor2.name = "other-flavor-3" + self.vimconn.nova.flavors.list.return_value = [self.flavor1, self.flavor2] + name = "other-flavor-3" + name_suffix = 5 + flavor_data = {"name": "other-flavor"} + expected_result = "other-flavor-7" + result = self.vimconn._change_flavor_name(name, name_suffix, flavor_data) + self.assertEqual(result, expected_result) + # Checking whether name_suffix changed or not. + self.assertEqual(name_suffix, 5) + self.vimconn.nova.flavors.list.assert_called_once() + + def test_change_the_flavor_name_flavor_data_does_not_have_name(self): + """Flavor data does not have name.""" + self.flavor1.name = "other-flavor-6" + self.flavor2.name = "other-flavor-3" + self.vimconn.nova.flavors.list.return_value = [self.flavor1, self.flavor2] + name = "other-flavor-3" + name_suffix = 5 + flavor_data = {} + with self.assertRaises(KeyError): + self.vimconn._change_flavor_name(name, name_suffix, flavor_data) + self.vimconn.nova.flavors.list.assert_called_once() + # Checking whether name_suffix changed or not. + self.assertEqual(name_suffix, 5) + + def test_change_the_flavor_name_invalid_name_suffix(self): + """Name suffix is invalid.""" + self.flavor1.name = "other-flavor-6" + self.flavor2.name = "other-flavor-3" + self.vimconn.nova.flavors.list.return_value = [self.flavor1, self.flavor2] + name = "other-flavor-3" + name_suffix = "a" + flavor_data = {"name": "other-flavor"} + with self.assertRaises(TypeError): + self.vimconn._change_flavor_name(name, name_suffix, flavor_data) + self.vimconn.nova.flavors.list.assert_called_once() + # Checking whether name_suffix changed or not. + self.assertEqual(name_suffix, "a") + + def test_change_the_flavor_name_given_name_is_empty(self): + """Given name is empty string.""" + self.flavor1.name = "other-flavor-6" + self.flavor2.name = "other-flavor-3" + self.vimconn.nova.flavors.list.return_value = [self.flavor1, self.flavor2] + name = "" + name_suffix = 3 + flavor_data = {"name": "other-flavor"} + result = self.vimconn._change_flavor_name(name, name_suffix, flavor_data) + self.assertEqual(result, "") + self.vimconn.nova.flavors.list.assert_called_once() + # Checking whether name_suffix increased or not. + self.assertEqual(name_suffix, 3) + + def test_change_the_flavor_name_given_name_is_none(self): + """Given name is None.""" + self.flavor1.name = "other-flavor-6" + self.flavor2.name = "other-flavor-3" + self.vimconn.nova.flavors.list.return_value = [self.flavor1, self.flavor2] + name = None + name_suffix = 6 + flavor_data = {"name": "other-flavor"} + result = self.vimconn._change_flavor_name(name, name_suffix, flavor_data) + self.assertEqual(result, None) + self.vimconn.nova.flavors.list.assert_called_once() + # Checking whether name_suffix increased or not. + self.assertEqual(name_suffix, 6) + + def test_change_the_flavor_name_empty_nova_flavor_list(self): + """Nova flavor list is empty.""" + self.vimconn.nova.flavors.list.return_value = [] + name = "other-flavor-3" + name_suffix = 5 + flavor_data = {"name": "other-flavor"} + result = self.vimconn._change_flavor_name(name, name_suffix, flavor_data) + self.vimconn.nova.flavors.list.assert_called_once() + self.assertEqual(result, name) + # Checking whether name_suffix increased or not. + self.assertEqual(name_suffix, 5) + + @patch.object( + vimconnector, + "_process_numa_parameters_of_flavor", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "process_resource_quota", new_callable=CopyingMock()) + def test_process_extended_config_of_flavor_with_numa_cpu_mem_vif_disk_quota( + self, mock_process_resource_quota, mock_process_numa_parameters_of_flavor + ): + """Process extended config, extended has numas, cpu, mem, vif and disk-io quota.""" + numas = [ + {"memory": 1, "vcpu": [1, 3], "threads": 3}, + {"memory": 2, "vcpu": [2]}, + ] + extended = { + "numas": numas, + "cpu-quota": {"limit": 3}, + "mem-quota": {"limit": 1}, + "vif-quota": {"limit": 10}, + "disk-io-quota": {"limit": 50}, + "mempage-size": "LARGE", + } + extra_specs = {} + expected_extra_specs = { + "hw:mem_page_size": "large", + } + self.vimconn._process_extended_config_of_flavor(extended, extra_specs) + + self.assertEqual(mock_process_resource_quota.call_count, 4) + mock_process_numa_parameters_of_flavor.assert_called_once_with(numas, {}) + self.assertEqual(extra_specs, expected_extra_specs) + + @patch.object( + vimconnector, + "_process_numa_parameters_of_flavor", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "process_resource_quota", new_callable=CopyingMock()) + def test_process_extended_config_of_flavor_with_numa_wrong_disk_quota( + self, mock_process_resource_quota, mock_process_numa_parameters_of_flavor + ): + """Process extended config, extended has wrong disk quota key.""" + numas = [ + {"memory": 1, "threads": 3}, + {"memory": 2, "vcpu": [2]}, + ] + extended = { + "numas": numas, + "disk-quota": {"limit": 50}, + "mempage-size": "PREFER_LARGE", + } + extra_specs = {} + expected_extra_specs = { + "hw:mem_page_size": "any", + } + self.vimconn._process_extended_config_of_flavor(extended, extra_specs) + mock_process_resource_quota.assert_not_called() + mock_process_numa_parameters_of_flavor.assert_called_once_with(numas, {}) + self.assertEqual(extra_specs, expected_extra_specs) + + @patch.object( + vimconnector, + "_process_numa_parameters_of_flavor", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "process_resource_quota", new_callable=CopyingMock()) + def test_process_extended_config_of_flavor_without_numa_cpu_mem_vif_disk_quota( + self, mock_process_resource_quota, mock_process_numa_parameters_of_flavor + ): + """Process extended config, extended has cpu, mem, vif and disk-io quota but not numas.""" + extended = { + "cpu-quota": {"limit": 3}, + "mem-quota": {"limit": 1}, + "vif-quota": {"limit": 10}, + "disk-io-quota": {"limit": 50}, + "mempage-size": "SMALL", + } + extra_specs = {} + expected_extra_specs = { + "hw:mem_page_size": "small", + } + self.vimconn._process_extended_config_of_flavor(extended, extra_specs) + self.assertEqual(mock_process_resource_quota.call_count, 4) + mock_process_numa_parameters_of_flavor.assert_not_called() + self.assertEqual(extra_specs, expected_extra_specs) + + @patch.object( + vimconnector, + "_process_numa_parameters_of_flavor", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "process_resource_quota", new_callable=CopyingMock()) + def test_process_extended_config_of_flavor_with_numa_with_cpu_pinning_mem_policy( + self, mock_process_resource_quota, mock_process_numa_parameters_of_flavor + ): + """Process extended config, extended has cpu, mem quota, cpu-pinning and mem-policy.""" + numas = [ + {"memory": 1}, + {"memory": 2, "vcpu": [2]}, + ] + extended = { + "numas": numas, + "cpu-quota": {"limit": 3}, + "mem-quota": {"limit": 1}, + "mempage-size": "LARGE", + "cpu-pinning-policy": "DEDICATED", + "mem-policy": "STRICT", + } + extra_specs = {} + expected_extra_specs = { + "hw:mem_page_size": "large", + "hw:cpu_policy": "dedicated", + "hw:numa_mempolicy": "strict", + } + self.vimconn._process_extended_config_of_flavor(extended, extra_specs) + self.assertEqual(mock_process_resource_quota.call_count, 2) + mock_process_numa_parameters_of_flavor.assert_called_once_with(numas, {}) + self.assertEqual(extra_specs, expected_extra_specs) + + @patch.object( + vimconnector, + "_process_numa_parameters_of_flavor", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "process_resource_quota", new_callable=CopyingMock()) + def test_process_extended_config_of_flavor_without_numa_with_cpu_pinning_mem_policy( + self, mock_process_resource_quota, mock_process_numa_parameters_of_flavor + ): + """Process extended config, extended has cpu, mem quota, cpu-pinning and mem-policy but not numas.""" + extended = { + "cpu-quota": {"limit": 3}, + "mem-quota": {"limit": 1}, + "mempage-size": "LARGE", + "cpu-pinning-policy": "DEDICATED", + "mem-policy": "STRICT", + } + extra_specs = {} + expected_extra_specs = { + "hw:mem_page_size": "large", + "hw:cpu_policy": "dedicated", + "hw:numa_mempolicy": "strict", + } + self.vimconn._process_extended_config_of_flavor(extended, extra_specs) + self.assertEqual(mock_process_resource_quota.call_count, 2) + mock_process_numa_parameters_of_flavor.assert_not_called() + self.assertEqual(extra_specs, expected_extra_specs) + + @patch.object( + vimconnector, + "_process_numa_parameters_of_flavor", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "process_resource_quota", new_callable=CopyingMock()) + def test_process_extended_config_of_flavor_without_numa_with_wrong_mempage_size( + self, mock_process_resource_quota, mock_process_numa_parameters_of_flavor + ): + """Process extended config, extended has wrong mempage-size without numas.""" + extended = { + "cpu-quota": {"limit": 3}, + "mem-quota": {"limit": 1}, + "mempage-size": "SIZE_2GB", + "cpu-pinning-policy": "DEDICATED", + "mem-policy": "STRICT", + } + extra_specs = {} + + expected_extra_specs = { + "hw:cpu_policy": "dedicated", + "hw:numa_mempolicy": "strict", + } + self.vimconn._process_extended_config_of_flavor(extended, extra_specs) + self.assertEqual(mock_process_resource_quota.call_count, 2) + mock_process_numa_parameters_of_flavor.assert_not_called() + self.assertEqual(extra_specs, expected_extra_specs) + + @patch.object( + vimconnector, + "_process_numa_parameters_of_flavor", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "process_resource_quota", new_callable=CopyingMock()) + def test_process_extended_config_of_flavor_with_numa_with_wrong_mempage_size( + self, mock_process_resource_quota, mock_process_numa_parameters_of_flavor + ): + """Process extended config, extended has wrong mempage-size with numas.""" + numas = [ + {"memory": 1}, + {"memory": 2, "vcpu": [2]}, + ] + extended = { + "numas": numas, + "cpu-quota": {"limit": 3}, + "mem-quota": {"limit": 1}, + "mempage-size": "SIZE_2GB", + "cpu-pinning-policy": "DEDICATED", + "mem-policy": "STRICT", + } + extra_specs = {} + expected_extra_specs = { + "hw:cpu_policy": "dedicated", + "hw:numa_mempolicy": "strict", + } + self.vimconn._process_extended_config_of_flavor(extended, extra_specs) + self.assertEqual(mock_process_resource_quota.call_count, 2) + mock_process_numa_parameters_of_flavor.assert_called_once_with(numas, {}) + self.assertEqual(extra_specs, expected_extra_specs) + + @patch.object( + vimconnector, + "_process_numa_parameters_of_flavor", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "process_resource_quota", new_callable=CopyingMock()) + def test_process_extended_config_of_flavor_none_vcpus( + self, mock_process_resource_quota, mock_process_numa_parameters_of_flavor + ): + """Process extended config, extended has cpu, mem quota, cpu-pinning and mem-policy, vcpus is None.""" + numas = [ + {"memory": 1}, + {"memory": 2, "vcpu": [2]}, + ] + extended = { + "numas": numas, + "cpu-quota": {"limit": 3}, + "mem-quota": {"limit": 1}, + "mempage-size": "SIZE_2GB", + "cpu-pinning-policy": "DEDICATED", + "mem-policy": "STRICT", + } + extra_specs = {} + expected_extra_specs = { + "hw:cpu_policy": "dedicated", + "hw:numa_mempolicy": "strict", + } + self.vimconn._process_extended_config_of_flavor(extended, extra_specs) + self.assertEqual(mock_process_resource_quota.call_count, 2) + mock_process_numa_parameters_of_flavor.assert_called_once_with(numas, {}) + self.assertEqual(extra_specs, expected_extra_specs) + + @patch.object( + vimconnector, + "_process_numa_parameters_of_flavor", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "process_resource_quota", new_callable=CopyingMock()) + def test_process_extended_config_of_flavor_none_vcpus_without_numas( + self, mock_process_resource_quota, mock_process_numa_parameters_of_flavor + ): + """Process extended config, extended has cpu, mem quota, cpu-pinning and mem-policy, vcpus is None.""" + extended = { + "cpu-quota": {"limit": 3}, + "mem-quota": {"limit": 1}, + "mempage-size": "SIZE_2GB", + "cpu-pinning-policy": "DEDICATED", + "mem-policy": "STRICT", + } + extra_specs = {"some-key": "some-val"} + expected_extra_specs = { + "hw:cpu_policy": "dedicated", + "hw:numa_mempolicy": "strict", + "some-key": "some-val", + } + self.vimconn._process_extended_config_of_flavor(extended, extra_specs) + self.assertEqual(mock_process_resource_quota.call_count, 2) + mock_process_numa_parameters_of_flavor.assert_not_called() + self.assertEqual(extra_specs, expected_extra_specs) + + @patch.object( + vimconnector, + "_process_numa_parameters_of_flavor", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "process_resource_quota", new_callable=CopyingMock()) + def test_process_extended_config_of_flavor_wrong_cpu_pinning_mem_policy_empty_vcpus( + self, mock_process_resource_quota, mock_process_numa_parameters_of_flavor + ): + """Process extended config, extended has wrong cpu-pinning and mem-policy keys.""" + numas = [ + {"memory": 1}, + {"memory": 2, "vcpu": [2]}, + ] + extended = { + "numas": numas, + "cpu-quota": {"limit": 3}, + "mem-quota": {"limit": 1}, + "mempage-size": "SIZE_2GB", + "cpu-pinning-pol": "DEDICATED", + "mem-pol": "STRICT", + } + extra_specs = {} + expected_extra_specs = {} + self.vimconn._process_extended_config_of_flavor(extended, extra_specs) + self.assertEqual(mock_process_resource_quota.call_count, 2) + mock_process_numa_parameters_of_flavor.assert_called_once_with( + numas, extra_specs + ) + self.assertEqual(extra_specs, expected_extra_specs) + + @patch.object( + vimconnector, + "_process_numa_parameters_of_flavor", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "process_resource_quota", new_callable=CopyingMock()) + def test_process_extended_config_of_flavor_empty_extended( + self, mock_process_resource_quota, mock_process_numa_parameters_of_flavor + ): + """Process extended config, extended is empty.""" + extended = {} + extra_specs = {} + self.vimconn._process_extended_config_of_flavor(extended, extra_specs) + check_if_assert_not_called( + [mock_process_resource_quota, mock_process_numa_parameters_of_flavor] + ) + self.assertEqual(extra_specs, {}) + + def test_get_flavor_details_empty_flavor_data(self): + flavor_data = {} + expected_result = (64, 1, {}, None) + result = self.vimconn._get_flavor_details(flavor_data) + self.assertEqual(result, expected_result) + + def test_get_flavor_details_flavor_data_has_ram_vcpus_extended(self): + flavor_data = { + "ram": 32, + "vcpus": 3, + "extended": { + "some-key": "some-val", + }, + } + expected_result = (32, 3, {}, {"some-key": "some-val"}) + result = self.vimconn._get_flavor_details(flavor_data) + self.assertEqual(result, expected_result) + + def test_get_flavor_details_flavor_data_is_none(self): + flavor_data = None + with self.assertRaises(AttributeError): + self.vimconn._get_flavor_details(flavor_data) + + def test_get_flavor_details_flavor_data_has_only_extended(self): + flavor_data = { + "extended": { + "some-key": "some-val", + } + } + expected_result = (64, 1, {}, {"some-key": "some-val"}) + result = self.vimconn._get_flavor_details(flavor_data) + self.assertEqual(result, expected_result) + + @patch.object(vimconnector, "_get_flavor_details", new_callable=CopyingMock()) + @patch.object( + vimconnector, + "_process_extended_config_of_flavor", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "_change_flavor_name", new_callable=CopyingMock()) + @patch.object(vimconnector, "_reload_connection", new_callable=CopyingMock()) + @patch.object(vimconnector, "_format_exception", new_callable=CopyingMock()) + def test_new_flavor_with_extended_with_extra_specs( + self, + mock_format_exception, + mock_reload_connection, + mock_change_flavor_name, + mock_extended_config_of_flavor, + mock_get_flavor_details, + ): + """Create new flavor with using extended parameters and extra specs.""" + name_suffix = 0 + vcpus = 8 + mock_change_flavor_name.return_value = name1 + mock_get_flavor_details.return_value = ( + 3, + vcpus, + {"some-key": "some-value"}, + extended, + ) + expected_result = self.new_flavor.id + result = self.vimconn.new_flavor(flavor_data) + self.assertEqual(result, expected_result) + mock_reload_connection.assert_called_once() + self.new_flavor.set_keys.assert_called_once() + mock_get_flavor_details.assert_called_once_with(flavor_data) + mock_change_flavor_name.assert_called_once_with(name1, name_suffix, flavor_data) + mock_extended_config_of_flavor.assert_called_once_with( + extended, {"some-key": "some-value"} + ) + self.vimconn.nova.flavors.create.assert_called_once_with( + name=name1, ram=3, vcpus=8, disk=50, ephemeral=0, swap=0, is_public=True + ) + mock_format_exception.assert_not_called() + + @patch.object(vimconnector, "_get_flavor_details", new_callable=CopyingMock()) + @patch.object( + vimconnector, + "_process_extended_config_of_flavor", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "_change_flavor_name", new_callable=CopyingMock()) + @patch.object(vimconnector, "_reload_connection", new_callable=CopyingMock()) + @patch.object(vimconnector, "_format_exception", new_callable=CopyingMock()) + def test_new_flavor_with_extended_without_extra_specs( + self, + mock_format_exception, + mock_reload_connection, + mock_change_flavor_name, + mock_extended_config_of_flavor, + mock_get_flavor_details, + ): + """Create new flavor with using extended parameters without extra specs.""" + name_suffix = 0 + vcpus = 8 + mock_change_flavor_name.return_value = name1 + mock_get_flavor_details.return_value = (3, vcpus, {}, extended) + expected_result = self.new_flavor.id + result = self.vimconn.new_flavor(flavor_data) + self.assertEqual(result, expected_result) + mock_reload_connection.assert_called_once() + mock_get_flavor_details.assert_called_once_with(flavor_data) + mock_change_flavor_name.assert_called_once_with(name1, name_suffix, flavor_data) + mock_extended_config_of_flavor.assert_called_once_with(extended, {}) + self.vimconn.nova.flavors.create.assert_called_once_with( + name=name1, ram=3, vcpus=vcpus, disk=50, ephemeral=0, swap=0, is_public=True + ) + check_if_assert_not_called([self.new_flavor.set_keys, mock_format_exception]) + + @patch.object(vimconnector, "_get_flavor_details", new_callable=CopyingMock()) + @patch.object( + vimconnector, + "_process_extended_config_of_flavor", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "_change_flavor_name", new_callable=CopyingMock()) + @patch.object(vimconnector, "_reload_connection", new_callable=CopyingMock()) + @patch.object(vimconnector, "_format_exception", new_callable=CopyingMock()) + def test_new_flavor_change_name_if_used_false_with_extended( + self, + mock_format_exception, + mock_reload_connection, + mock_change_flavor_name, + mock_extended_config_of_flavor, + mock_get_flavor_details, + ): + """Create new flavor, change_name_if_used_false, there is extended.""" + vcpus = 8 + mock_get_flavor_details.return_value = (3, vcpus, {}, extended) + expected_result = self.new_flavor.id + result = self.vimconn.new_flavor(flavor_data, False) + self.assertEqual(result, expected_result) + mock_reload_connection.assert_called_once() + self.assertEqual(mock_get_flavor_details.call_count, 1) + mock_extended_config_of_flavor.assert_called_once_with(extended, {}) + self.vimconn.nova.flavors.create.assert_called_once_with( + name=name1, ram=3, vcpus=8, disk=50, ephemeral=0, swap=0, is_public=True + ) + check_if_assert_not_called( + [mock_change_flavor_name, mock_format_exception, self.new_flavor.set_keys] + ) + + @patch.object(vimconnector, "_get_flavor_details", new_callable=CopyingMock()) + @patch.object( + vimconnector, + "_process_extended_config_of_flavor", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "_change_flavor_name", new_callable=CopyingMock()) + @patch.object(vimconnector, "_reload_connection", new_callable=CopyingMock()) + @patch.object(vimconnector, "_format_exception", new_callable=CopyingMock()) + def test_new_flavor_change_name_if_used_true_without_extended( + self, + mock_format_exception, + mock_reload_connection, + mock_change_flavor_name, + mock_extended_config_of_flavor, + mock_get_flavor_details, + ): + """Create new flavor without extended parameters.""" + name_suffix = 0 + mock_change_flavor_name.return_value = name1 + expected_result = self.new_flavor.id + mock_get_flavor_details.return_value = (3, 8, {}, None) + result = self.vimconn.new_flavor(flavor_data2) + self.assertEqual(result, expected_result) + mock_reload_connection.assert_called_once() + mock_change_flavor_name.assert_called_once_with( + name1, name_suffix, flavor_data2 + ) + self.assertEqual(mock_get_flavor_details.call_count, 1) + self.vimconn.nova.flavors.create.assert_called_once_with( + name=name1, ram=3, vcpus=8, disk=50, ephemeral=0, swap=0, is_public=True + ) + check_if_assert_not_called( + [ + self.new_flavor.set_keys, + mock_extended_config_of_flavor, + mock_format_exception, + ] + ) + + @patch.object(vimconnector, "_get_flavor_details", new_callable=CopyingMock()) + @patch.object( + vimconnector, + "_process_extended_config_of_flavor", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "_change_flavor_name", new_callable=CopyingMock()) + @patch.object(vimconnector, "_reload_connection", new_callable=CopyingMock()) + @patch.object(vimconnector, "_format_exception", new_callable=CopyingMock()) + def test_new_flavor_reload_connection_exception( + self, + mock_format_exception, + mock_reload_connection, + mock_change_flavor_name, + mock_extended_config_of_flavor, + mock_get_flavor_details, + ): + """Create new flavor, reload connection exception occurred.""" + error_msg = "Can not connect to client APIs." + error = nvExceptions.ClientException(error_msg) + mock_change_flavor_name.return_value = name1 + mock_reload_connection.side_effect = error + with self.assertRaises(Exception) as err: + self.vimconn.new_flavor(flavor_data2) + self.assertEqual(str(err.exception), "Can not connect to client APIs.") + self.assertEqual(mock_reload_connection.call_count, 1) + call_mock_format_exception = mock_format_exception.call_args + self.assertEqual( + str(call_mock_format_exception[0][0]), str(ClientException(error_msg)) + ) + check_if_assert_not_called( + [ + mock_change_flavor_name, + mock_get_flavor_details, + mock_extended_config_of_flavor, + self.vimconn.nova.flavors.create, + ] + ) + + @patch.object(vimconnector, "_get_flavor_details", new_callable=CopyingMock()) + @patch.object( + vimconnector, + "_process_extended_config_of_flavor", + new_callable=CopyingMock(autospec=True), + ) + @patch.object(vimconnector, "_change_flavor_name", new_callable=CopyingMock()) + @patch.object(vimconnector, "_reload_connection", new_callable=CopyingMock()) + @patch.object(vimconnector, "_format_exception", new_callable=CopyingMock()) + def test_new_flavor_flavor_data_without_name( + self, + mock_format_exception, + mock_reload_connection, + mock_change_flavor_name, + mock_extended_config_of_flavor, + mock_get_flavor_details, + ): + """Create new flavor, flavor data does not have name.""" + flavor_data3 = { + "ram": 3, + "vcpus": 8, + "disk": 50, + } + error_msg = "name" + self.vimconn.new_flavor(flavor_data3) + mock_format_exception.assert_called_once() + call_mock_format_exception = mock_format_exception.call_args + self.assertEqual( + str(call_mock_format_exception[0][0]), str(KeyError(error_msg)) + ) + check_if_assert_not_called( + [ + mock_reload_connection, + mock_change_flavor_name, + mock_get_flavor_details, + mock_extended_config_of_flavor, + self.vimconn.nova.flavors.create, + ] + ) + + @patch.object(vimconnector, "_get_flavor_details", new_callable=CopyingMock()) + @patch.object( + vimconnector, + "_process_extended_config_of_flavor", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "_change_flavor_name", new_callable=CopyingMock()) + @patch.object(vimconnector, "_reload_connection", new_callable=CopyingMock()) + @patch.object(vimconnector, "_format_exception", new_callable=CopyingMock()) + def test_new_flavor_change_flavor_name_has_extended_conflict_exception_recovered_in_retry( + self, + mock_format_exception, + mock_reload_connection, + mock_change_flavor_name, + mock_extended_config_of_flavor, + mock_get_flavor_details, + ): + """Create new flavor, nvExceptions.Conflict occurred and recovered, there is extended config.""" + name_suffix = 0 + error_msg = "Conflict has occurred while creating flavor name." + error2 = nvExceptions.Conflict(error_msg) + mock_change_flavor_name.side_effect = [error2, "sample-flavor-3"] + expected_result = self.new_flavor.id + mock_get_flavor_details.return_value = (3, 8, {}, extended) + result = self.vimconn.new_flavor(flavor_data2) + self.assertEqual(result, expected_result) + self.assertEqual(mock_reload_connection.call_count, 2) + mock_change_flavor_name.assert_called_with(name1, name_suffix, flavor_data2) + self.assertEqual(mock_change_flavor_name.call_count, 2) + self.assertEqual(mock_get_flavor_details.call_count, 1) + self.assertEqual(mock_extended_config_of_flavor.call_count, 1) + self.vimconn.nova.flavors.create.assert_called_once_with( + name="sample-flavor-3", + ram=3, + vcpus=8, + disk=50, + ephemeral=0, + swap=0, + is_public=True, + ) + check_if_assert_not_called([self.new_flavor.set_keys, mock_format_exception]) + + @patch.object(vimconnector, "_get_flavor_details", new_callable=CopyingMock()) + @patch.object( + vimconnector, + "_process_extended_config_of_flavor", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "_change_flavor_name", new_callable=CopyingMock()) + @patch.object(vimconnector, "_reload_connection", new_callable=CopyingMock()) + @patch.object(vimconnector, "_format_exception", new_callable=CopyingMock()) + def test_new_flavor_change_flavor_name_without_extended_conflict_exception_recovered_in_retry( + self, + mock_format_exception, + mock_reload_connection, + mock_change_flavor_name, + mock_extended_config_of_flavor, + mock_get_flavor_details, + ): + """Create new flavor, nvExceptions.Conflict occurred and recovered, there is not extended config.""" + name_suffix = 0 + error2 = nvExceptions.Conflict( + "Conflict has occurred while creating flavor name." + ) + mock_change_flavor_name.side_effect = [error2, "sample-flavor-3"] + expected_result = self.new_flavor.id + mock_get_flavor_details.return_value = (3, 8, {}, None) + result = self.vimconn.new_flavor(flavor_data2) + self.assertEqual(result, expected_result) + self.assertEqual(mock_reload_connection.call_count, 2) + mock_change_flavor_name.assert_called_with(name1, name_suffix, flavor_data2) + self.assertEqual(mock_change_flavor_name.call_count, 2) + self.assertEqual(mock_get_flavor_details.call_count, 1) + self.vimconn.nova.flavors.create.assert_called_once_with( + name="sample-flavor-3", + ram=3, + vcpus=8, + disk=50, + ephemeral=0, + swap=0, + is_public=True, + ) + check_if_assert_not_called( + [ + self.new_flavor.set_keys, + mock_extended_config_of_flavor, + mock_format_exception, + ] + ) + + @patch.object(vimconnector, "_get_flavor_details", new_callable=CopyingMock()) + @patch.object( + vimconnector, + "_process_extended_config_of_flavor", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "_change_flavor_name", new_callable=CopyingMock()) + @patch.object(vimconnector, "_reload_connection", new_callable=CopyingMock()) + @patch.object(vimconnector, "_format_exception", new_callable=CopyingMock()) + def test_new_flavor_change_flavor_name_conflict_exception_change_name_if_used_false( + self, + mock_format_exception, + mock_reload_connection, + mock_change_flavor_name, + mock_extended_config_of_flavor, + mock_get_flavor_details, + ): + """Create new flavor, nvExceptions.Conflict occurred, + change_name_if_used is false.""" + change_name_if_used = False + error_msg = "Conflict has occurred while creating flavor name." + error2 = nvExceptions.Conflict(error_msg) + mock_get_flavor_details.return_value = (4, 8, {}, None) + self.vimconn.nova.flavors.create.side_effect = error2 + with self.assertRaises(Exception) as err: + self.vimconn.new_flavor(flavor_data2, change_name_if_used) + self.assertEqual(str(err.exception), error_msg) + self.assertEqual(type(err.exception), nvExceptions.Conflict) + self.vimconn.nova.flavors.create.assert_called_with( + name="sample-flavor", + ram=4, + vcpus=8, + disk=50, + ephemeral=0, + swap=0, + is_public=True, + ) + self.assertEqual(mock_get_flavor_details.call_count, 3) + self.assertEqual(self.vimconn.nova.flavors.create.call_count, 3) + self.assertEqual(mock_reload_connection.call_count, 3) + check_if_assert_not_called( + [mock_change_flavor_name, mock_extended_config_of_flavor] + ) + _call_mock_format_exception = mock_format_exception.call_args + self.assertEqual( + str(_call_mock_format_exception[0][0]), str(Conflict(error_msg)) + ) + self.assertEqual(mock_format_exception.call_count, 3) + + @patch.object(vimconnector, "_get_flavor_details", new_callable=CopyingMock()) + @patch.object( + vimconnector, + "_process_extended_config_of_flavor", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "_change_flavor_name", new_callable=CopyingMock()) + @patch.object(vimconnector, "_reload_connection", new_callable=CopyingMock()) + @patch.object(vimconnector, "_format_exception", new_callable=CopyingMock()) + def test_new_flavor_client_exception_occurred_change_name_if_used_true( + self, + mock_format_exception, + mock_reload_connection, + mock_change_flavor_name, + mock_extended_config_of_flavor, + mock_get_flavor_details, + ): + """Create new flavor, nvExceptions.ClientException occurred, + change_name_if_used is true.""" + error_msg = "Connection failed." + error2 = nvExceptions.ClientException(error_msg) + mock_change_flavor_name.side_effect = [ + "sample-flavor-3", + "sample-flavor-4", + "sample-flavor-5", + ] + mock_get_flavor_details.return_value = (3, 8, {}, None) + self.vimconn.nova.flavors.create.side_effect = error2 + with self.assertRaises(Exception) as err: + self.vimconn.new_flavor(flavor_data2) + self.assertEqual( + str(err.exception), "Conflict has occurred while creating flavor name." + ) + self.assertEqual(type(err.exception), nvExceptions.Conflict) + self.assertEqual(self.vimconn.nova.flavors.create.call_count, 1) + _call_mock_nova_create_flavor = self.vimconn.nova.flavors.create.call_args_list + self.assertEqual( + _call_mock_nova_create_flavor[0][1], + ( + { + "name": "sample-flavor-3", + "ram": 3, + "vcpus": 8, + "disk": 50, + "ephemeral": 0, + "swap": 0, + "is_public": True, + } + ), + ) + + self.assertEqual(mock_reload_connection.call_count, 1) + self.assertEqual(mock_get_flavor_details.call_count, 1) + _call_mock_change_flavor = mock_change_flavor_name.call_args_list + self.assertEqual( + _call_mock_change_flavor[0][0], + ( + "sample-flavor", + 0, + {"name": "sample-flavor", "ram": 3, "vcpus": 8, "disk": 50}, + ), + ) + self.assertEqual(mock_change_flavor_name.call_count, 1) + mock_extended_config_of_flavor.assert_not_called() + call_mock_format_exception = mock_format_exception.call_args + self.assertEqual( + str(call_mock_format_exception[0][0]), str(ClientException(error_msg)) + ) + self.assertEqual(mock_format_exception.call_count, 1) + + @patch.object(vimconnector, "_get_flavor_details", new_callable=CopyingMock()) + @patch.object( + vimconnector, + "_process_extended_config_of_flavor", + new_callable=CopyingMock(), + ) + @patch.object(vimconnector, "_change_flavor_name", new_callable=CopyingMock()) + @patch.object(vimconnector, "_reload_connection", new_callable=CopyingMock()) + @patch.object(vimconnector, "_format_exception", new_callable=CopyingMock()) + def test_new_flavor_change_flavor_name_conflict_exception_occurred_change_name_if_used_true( + self, + mock_format_exception, + mock_reload_connection, + mock_change_flavor_name, + mock_extended_config_of_flavor, + mock_get_flavor_details, + ): + """Create new flavor, nvExceptions.Conflict occurred, + change_name_if_used is true.""" + error_msg = "Conflict has occurred while creating flavor name." + error2 = nvExceptions.Conflict(error_msg) + mock_change_flavor_name.side_effect = [ + "sample-flavor-3", + "sample-flavor-4", + "sample-flavor-5", + ] + mock_get_flavor_details.return_value = (3, 8, {}, None) + self.vimconn.nova.flavors.create.side_effect = error2 + with self.assertRaises(Exception) as err: + self.vimconn.new_flavor(flavor_data2) + self.assertEqual(str(err.exception), error_msg) + self.assertEqual(type(err.exception), nvExceptions.Conflict) + self.assertEqual(self.vimconn.nova.flavors.create.call_count, 3) + _call_mock_nova_create_flavor = self.vimconn.nova.flavors.create.call_args_list + self.assertEqual( + _call_mock_nova_create_flavor[0][1], + ( + { + "name": "sample-flavor-3", + "ram": 3, + "vcpus": 8, + "disk": 50, + "ephemeral": 0, + "swap": 0, + "is_public": True, + } + ), + ) + self.assertEqual( + _call_mock_nova_create_flavor[1][1], + ( + { + "name": "sample-flavor-4", + "ram": 3, + "vcpus": 8, + "disk": 50, + "ephemeral": 0, + "swap": 0, + "is_public": True, + } + ), + ) + self.assertEqual( + _call_mock_nova_create_flavor[2][1], + ( + { + "name": "sample-flavor-5", + "ram": 3, + "vcpus": 8, + "disk": 50, + "ephemeral": 0, + "swap": 0, + "is_public": True, + } + ), + ) + self.assertEqual(mock_reload_connection.call_count, 3) + _call_mock_change_flavor = mock_change_flavor_name.call_args_list + self.assertEqual( + _call_mock_change_flavor[0][0], + ( + "sample-flavor", + 0, + {"name": "sample-flavor", "ram": 3, "vcpus": 8, "disk": 50}, + ), + ) + self.assertEqual( + _call_mock_change_flavor[1][0], + ( + "sample-flavor-3", + 0, + {"name": "sample-flavor", "ram": 3, "vcpus": 8, "disk": 50}, + ), + ) + self.assertEqual( + _call_mock_change_flavor[2][0], + ( + "sample-flavor-4", + 0, + {"name": "sample-flavor", "ram": 3, "vcpus": 8, "disk": 50}, + ), + ) + self.assertEqual(mock_change_flavor_name.call_count, 3) + mock_extended_config_of_flavor.assert_not_called() + call_mock_format_exception = mock_format_exception.call_args + self.assertEqual( + str(call_mock_format_exception[0][0]), str(Conflict(error_msg)) + ) + self.assertEqual(mock_format_exception.call_count, 1) + + def test_process_process_vio_numa_nodes_without_numa_with_extra_spec(self): + numa_nodes = 0 + extra_specs = {"hw:numa_nodes": "0"} + expected_extra_spec = { + "vmware:latency_sensitivity_level": "high", + "hw:numa_nodes": "0", + } + self.vimconn.process_vio_numa_nodes(numa_nodes, extra_specs) + self.assertDictEqual(extra_specs, expected_extra_spec) + + def test_process_process_vio_numa_nodes_list_type_numa_nodes_empty_extra_spec(self): + numa_nodes = [7, 9, 4] + extra_specs = {} + expected_extra_spec = { + "vmware:latency_sensitivity_level": "high", + } + self.vimconn.process_vio_numa_nodes(numa_nodes, extra_specs) + self.assertDictEqual(extra_specs, expected_extra_spec) + + def test_process_process_vio_numa_nodes_with_numa_with_extra_spec(self): + numa_nodes = 5 + extra_specs = {"hw:numa_nodes": "5"} + expected_extra_spec = { + "vmware:latency_sensitivity_level": "high", + "hw:numa_nodes": "5", + } + self.vimconn.process_vio_numa_nodes(numa_nodes, extra_specs) + self.assertDictEqual(extra_specs, expected_extra_spec) + + def test_process_process_vio_numa_nodes_none_numa_nodes(self): + numa_nodes = None + extra_specs = {"hw:numa_nodes": "None"} + expected_extra_spec = { + "vmware:latency_sensitivity_level": "high", + "hw:numa_nodes": "None", + } + self.vimconn.process_vio_numa_nodes(numa_nodes, extra_specs) + self.assertDictEqual(extra_specs, expected_extra_spec) + + def test_process_process_vio_numa_nodes_invalid_type_extra_specs(self): + numa_nodes = 5 + extra_specs = [] + with self.assertRaises(TypeError): + self.vimconn.process_vio_numa_nodes(numa_nodes, extra_specs) if __name__ == "__main__":