Refactoring new_flavor method in Openstack VIM connector 49/12849/11
authorGulsum Atici <gulsum.atici@canonical.com>
Thu, 19 Jan 2023 09:44:06 +0000 (12:44 +0300)
committerGulsum Atici <gulsum.atici@canonical.com>
Mon, 23 Jan 2023 18:59:44 +0000 (21:59 +0300)
Change-Id: If852a4c20f41cba2609d9d0d30865649a748e067
Signed-off-by: Gulsum Atici <gulsum.atici@canonical.com>
RO-VIM-openstack/osm_rovim_openstack/tests/test_vimconn_openstack.py
RO-VIM-openstack/osm_rovim_openstack/vimconn_openstack.py
releasenotes/notes/refactor_new_flavor-9717ff4c02776dda.yaml [new file with mode: 0644]

index f4382ad..acf6be4 100644 (file)
@@ -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,34 @@ created_items_all_true = {
 }
 
 
+# Variables used in TestNewFlavor Class
+flavor_id = "075d2482-5edb-43e3-91b3-234e65b6268a"
+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,
+}
+
+
 class TestSfcOperations(unittest.TestCase):
     @mock.patch("logging.getLogger", autospec=True)
     def setUp(self, mock_logger):
@@ -3071,7 +3100,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": {
@@ -3082,14 +3111,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")
@@ -4770,7 +4799,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)
@@ -4782,7 +4811,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):
@@ -5530,11 +5559,11 @@ class TestNewVmInstance(unittest.TestCase):
         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)
@@ -5564,12 +5593,12 @@ class TestNewVmInstance(unittest.TestCase):
         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()
@@ -5599,12 +5628,12 @@ class TestNewVmInstance(unittest.TestCase):
         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)
@@ -5635,12 +5664,12 @@ class TestNewVmInstance(unittest.TestCase):
         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()
@@ -5889,5 +5918,1921 @@ class TestNewVmInstance(unittest.TestCase):
             self.vimconn._extract_items_wth_keep_flag_from_created_items(created_items)
 
 
+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
+
+    @staticmethod
+    def check_if_assert_not_called(mocks: list):
+        for mocking in mocks:
+            mocking.assert_not_called()
+
+    @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,
+    ):
+        """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]},
+        ]
+        vcpus = 3
+        extra_specs = {}
+        expected_extra_specs = {
+            "hw:numa_nodes": "2",
+            "vmware:extra_config": '{"numa.nodeAffinity":"0"}',
+            "vmware:latency_sensitivity_level": "high",
+            "hw:cpu_sockets": "2",
+        }
+        self.vimconn.vim_type = "VIO"
+        result = self.vimconn._process_numa_parameters_of_flavor(
+            numas, extra_specs, vcpus
+        )
+        self.assertEqual(result, vcpus)
+        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",
+                    "vmware:extra_config": '{"numa.nodeAffinity":"0"}',
+                    "vmware:latency_sensitivity_level": "high",
+                },
+            ),
+        )
+        self.assertEqual(
+            _call_mock_process_numa_memory[1].args,
+            (
+                {"id": 1, "memory": 2, "vcpu": [2]},
+                1,
+                {
+                    "hw:cpu_sockets": "2",
+                    "hw:numa_nodes": "2",
+                    "vmware:extra_config": '{"numa.nodeAffinity":"0"}',
+                    "vmware:latency_sensitivity_level": "high",
+                },
+            ),
+        )
+        _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",
+                    "vmware:extra_config": '{"numa.nodeAffinity":"0"}',
+                    "vmware:latency_sensitivity_level": "high",
+                },
+            ),
+        )
+        self.assertEqual(
+            _call_mock_process_numa_vcpu[1].args,
+            (
+                {"id": 1, "memory": 2, "vcpu": [2]},
+                1,
+                {
+                    "hw:cpu_sockets": "2",
+                    "hw:numa_nodes": "2",
+                    "vmware:extra_config": '{"numa.nodeAffinity":"0"}',
+                    "vmware:latency_sensitivity_level": "high",
+                },
+            ),
+        )
+        self.assertDictEqual(extra_specs, expected_extra_specs)
+        self.check_if_assert_not_called(
+            [
+                mock_process_numa_threads,
+                mock_process_numa_cores,
+                mock_process_numa_paired_threads,
+            ]
+        )
+
+    @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,
+    ):
+        """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]},
+        ]
+        vcpus = 3
+        extra_specs = {}
+        expected_extra_specs = {
+            "hw:numa_nodes": "2",
+            "hw:cpu_sockets": "2",
+        }
+        self.vimconn.vim_type = "openstack"
+        result = self.vimconn._process_numa_parameters_of_flavor(
+            numas, extra_specs, vcpus
+        )
+        self.assertEqual(result, vcpus)
+        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)
+        self.check_if_assert_not_called(
+            [
+                mock_process_numa_threads,
+                mock_process_numa_cores,
+                mock_process_numa_paired_threads,
+            ]
+        )
+
+    @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,
+    ):
+        """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:numa_nodes": "2",
+            "hw:cpu_sockets": "2",
+            "some-key": "some-value",
+        }
+        self.vimconn.vim_type = "openstack"
+        vcpus = 6
+        mock_process_numa_paired_threads.side_effect = [6, 6]
+        result = self.vimconn._process_numa_parameters_of_flavor(
+            numas, extra_specs, vcpus
+        )
+        self.assertEqual(result, vcpus)
+        self.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_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,
+    ):
+        """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": 3}, {"id": 1, "paired-threads": 3}]
+        extra_specs = {"some-key": "some-value"}
+        expected_extra_specs = {
+            "hw:numa_nodes": "2",
+            "vmware:extra_config": '{"numa.nodeAffinity":"0"}',
+            "vmware:latency_sensitivity_level": "high",
+            "hw:cpu_sockets": "2",
+            "some-key": "some-value",
+        }
+        self.vimconn.vim_type = "VIO"
+        vcpus = 6
+        mock_process_numa_paired_threads.side_effect = [6, 6]
+        result = self.vimconn._process_numa_parameters_of_flavor(
+            numas, extra_specs, vcpus
+        )
+        self.assertEqual(result, vcpus)
+        self.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
+        )
+        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",
+                    "vmware:extra_config": '{"numa.nodeAffinity":"0"}',
+                    "vmware:latency_sensitivity_level": "high",
+                },
+            ),
+        )
+        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",
+                    "vmware:extra_config": '{"numa.nodeAffinity":"0"}',
+                    "vmware:latency_sensitivity_level": "high",
+                },
+            ),
+        )
+        self.assertDictEqual(extra_specs, expected_extra_specs)
+
+    @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,
+    ):
+        """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 = {}
+        expected_extra_specs = {"hw:numa_nodes": "2", "hw:cpu_sockets": "2"}
+        self.vimconn.vim_type = "openstack"
+        vcpus = 2
+        mock_process_numa_cores.side_effect = [1, 2]
+        result = self.vimconn._process_numa_parameters_of_flavor(
+            numas, extra_specs, vcpus
+        )
+        self.assertEqual(result, vcpus)
+        self.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}, {"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_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,
+    ):
+        """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:numa_nodes": "2",
+            "hw:cpu_sockets": "2",
+            "vmware:extra_config": '{"numa.nodeAffinity":"0"}',
+            "vmware:latency_sensitivity_level": "high",
+        }
+        self.vimconn.vim_type = "VIO"
+        vcpus = 2
+        mock_process_numa_cores.side_effect = [1, 2]
+        result = self.vimconn._process_numa_parameters_of_flavor(
+            numas, extra_specs, vcpus
+        )
+        self.assertEqual(result, vcpus)
+        self.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)
+        _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}, expected_extra_specs),
+        )
+        self.assertEqual(
+            _call_mock_process_numa_cores[1].args,
+            ({"id": 1, "cores": 2}, expected_extra_specs),
+        )
+        self.assertDictEqual(extra_specs, expected_extra_specs)
+
+    @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,
+    ):
+        """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",
+            "vmware:extra_config": '{"numa.nodeAffinity":"0"}',
+            "vmware:latency_sensitivity_level": "high",
+            "hw:cpu_sockets": "2",
+        }
+        self.vimconn.vim_type = "VIO"
+        vcpus = 3
+        mock_process_numa_threads.return_value = vcpus
+        result = self.vimconn._process_numa_parameters_of_flavor(
+            numas, extra_specs, vcpus
+        )
+        self.assertEqual(result, vcpus)
+        self.check_if_assert_not_called(
+            [
+                mock_process_numa_memory,
+                mock_process_numa_vcpu,
+                mock_process_numa_cores,
+                mock_process_numa_paired_threads,
+            ]
+        )
+        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},
+                expected_extra_specs,
+            ),
+        )
+        self.assertDictEqual(extra_specs, expected_extra_specs)
+
+    @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,
+    ):
+        """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",
+        }
+        self.vimconn.vim_type = "openstack"
+        vcpus = 3
+        mock_process_numa_threads.return_value = vcpus
+        result = self.vimconn._process_numa_parameters_of_flavor(
+            numas, extra_specs, vcpus
+        )
+        self.assertEqual(result, vcpus)
+        self.check_if_assert_not_called(
+            [
+                mock_process_numa_memory,
+                mock_process_numa_vcpu,
+                mock_process_numa_cores,
+                mock_process_numa_paired_threads,
+            ]
+        )
+        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},
+                expected_extra_specs,
+            ),
+        )
+        self.assertDictEqual(extra_specs, expected_extra_specs)
+
+    @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,
+    ):
+        """Numa list is empty, vim type is VIO."""
+        numas = []
+        extra_specs = {}
+        expected_extra_specs = {
+            "hw:numa_nodes": "0",
+            "vmware:extra_config": '{"numa.nodeAffinity":"0"}',
+            "vmware:latency_sensitivity_level": "high",
+        }
+        self.vimconn.vim_type = "VIO"
+        vcpus = 4
+        mock_process_numa_threads.return_value = None
+        result = self.vimconn._process_numa_parameters_of_flavor(
+            numas, extra_specs, vcpus
+        )
+        self.assertEqual(result, vcpus)
+        self.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,
+            ]
+        )
+        self.assertDictEqual(extra_specs, expected_extra_specs)
+
+    @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,
+    ):
+        """Numa list is empty, vim type is openstack."""
+        numas = []
+        extra_specs = {}
+        expected_extra_specs = {"hw:numa_nodes": "0"}
+        self.vimconn.vim_type = "openstack"
+        vcpus = 5
+        mock_process_numa_threads.return_value = None
+        result = self.vimconn._process_numa_parameters_of_flavor(
+            numas, extra_specs, vcpus
+        )
+        self.assertEqual(result, vcpus)
+        self.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,
+            ]
+        )
+        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_memory_node_id_is_int(self):
+        numa = {"memory": 2, "vcpu": [2]}
+        node_id = 0
+        extra_specs = {}
+        expected_extra_spec = {"hw:numa_mem.0": 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]},
+        ]
+        vcpus = 3
+        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",
+        }
+        mock_process_numa_parameters_of_flavor.return_value = vcpus
+        result = self.vimconn._process_extended_config_of_flavor(
+            extended, extra_specs, vcpus
+        )
+        self.assertEqual(result, vcpus)
+        self.assertEqual(mock_process_resource_quota.call_count, 4)
+        mock_process_numa_parameters_of_flavor.assert_called_once_with(numas, {}, vcpus)
+        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]},
+        ]
+        vcpus = 3
+        extended = {
+            "numas": numas,
+            "disk-quota": {"limit": 50},
+            "mempage-size": "PREFER_LARGE",
+        }
+        extra_specs = {}
+        expected_extra_specs = {
+            "hw:mem_page_size": "any",
+        }
+        mock_process_numa_parameters_of_flavor.return_value = vcpus
+        result = self.vimconn._process_extended_config_of_flavor(
+            extended, extra_specs, vcpus
+        )
+        self.assertEqual(result, vcpus)
+        mock_process_resource_quota.assert_not_called()
+        mock_process_numa_parameters_of_flavor.assert_called_once_with(numas, {}, vcpus)
+        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."""
+        vcpus = 3
+        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",
+        }
+        mock_process_numa_parameters_of_flavor.return_value = vcpus
+        result = self.vimconn._process_extended_config_of_flavor(
+            extended, extra_specs, vcpus
+        )
+        self.assertEqual(result, vcpus)
+        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 = {}
+        vcpus = 3
+        expected_extra_specs = {
+            "hw:mem_page_size": "large",
+            "hw:cpu_policy": "dedicated",
+            "hw:numa_mempolicy": "strict",
+        }
+        mock_process_numa_parameters_of_flavor.return_value = 4
+        result = self.vimconn._process_extended_config_of_flavor(
+            extended, extra_specs, vcpus
+        )
+        self.assertEqual(result, 4)
+        self.assertEqual(mock_process_resource_quota.call_count, 2)
+        mock_process_numa_parameters_of_flavor.assert_called_once_with(numas, {}, vcpus)
+        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 = {}
+        vcpus = 3
+        expected_extra_specs = {
+            "hw:mem_page_size": "large",
+            "hw:cpu_policy": "dedicated",
+            "hw:numa_mempolicy": "strict",
+        }
+        result = self.vimconn._process_extended_config_of_flavor(
+            extended, extra_specs, vcpus
+        )
+        self.assertEqual(result, 3)
+        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 = {}
+        vcpus = 6
+        expected_extra_specs = {
+            "hw:cpu_policy": "dedicated",
+            "hw:numa_mempolicy": "strict",
+        }
+        result = self.vimconn._process_extended_config_of_flavor(
+            extended, extra_specs, vcpus
+        )
+        self.assertEqual(result, 6)
+        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 = {}
+        mock_process_numa_parameters_of_flavor.return_value = 4
+        vcpus = 1
+        expected_extra_specs = {
+            "hw:cpu_policy": "dedicated",
+            "hw:numa_mempolicy": "strict",
+        }
+        result = self.vimconn._process_extended_config_of_flavor(
+            extended, extra_specs, vcpus
+        )
+        self.assertEqual(result, 4)
+        self.assertEqual(mock_process_resource_quota.call_count, 2)
+        mock_process_numa_parameters_of_flavor.assert_called_once_with(numas, {}, vcpus)
+        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",
+        }
+        mock_process_numa_parameters_of_flavor.return_value = 1
+        extra_specs = {}
+        vcpus = None
+        expected_extra_specs = {
+            "hw:cpu_policy": "dedicated",
+            "hw:numa_mempolicy": "strict",
+        }
+        result = self.vimconn._process_extended_config_of_flavor(
+            extended, extra_specs, vcpus
+        )
+        self.assertEqual(result, 1)
+        self.assertEqual(mock_process_resource_quota.call_count, 2)
+        mock_process_numa_parameters_of_flavor.assert_called_once_with(numas, {}, vcpus)
+        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"}
+        vcpus = None
+        expected_extra_specs = {
+            "hw:cpu_policy": "dedicated",
+            "hw:numa_mempolicy": "strict",
+            "some-key": "some-val",
+        }
+        result = self.vimconn._process_extended_config_of_flavor(
+            extended, extra_specs, vcpus
+        )
+        self.assertEqual(result, None)
+        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",
+        }
+        mock_process_numa_parameters_of_flavor.return_value = 1
+        extra_specs = {}
+        vcpus = ""
+        expected_extra_specs = {}
+        result = self.vimconn._process_extended_config_of_flavor(
+            extended, extra_specs, vcpus
+        )
+        self.assertEqual(result, 1)
+        self.assertEqual(mock_process_resource_quota.call_count, 2)
+        mock_process_numa_parameters_of_flavor.assert_called_once_with(
+            numas, extra_specs, vcpus
+        )
+        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 = {}
+        vcpus = 2
+        result = self.vimconn._process_extended_config_of_flavor(
+            extended, extra_specs, vcpus
+        )
+        self.assertEqual(result, 2)
+        self.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_extended_config_of_flavor.return_value = vcpus
+        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"}, vcpus
+        )
+        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_extended_config_of_flavor.return_value = vcpus
+        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, {}, vcpus)
+        self.vimconn.nova.flavors.create.assert_called_once_with(
+            name=name1, ram=3, vcpus=vcpus, disk=50, ephemeral=0, swap=0, is_public=True
+        )
+        self.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)
+        mock_extended_config_of_flavor.return_value = 16
+        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, {}, vcpus)
+        self.vimconn.nova.flavors.create.assert_called_once_with(
+            name=name1, ram=3, vcpus=16, disk=50, ephemeral=0, swap=0, is_public=True
+        )
+        self.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
+        )
+        self.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))
+        )
+        self.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))
+        )
+        self.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)
+        mock_extended_config_of_flavor.return_value = 10
+        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=10,
+            disk=50,
+            ephemeral=0,
+            swap=0,
+            is_public=True,
+        )
+        self.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,
+        )
+        self.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)
+        self.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)
+
+
 if __name__ == "__main__":
     unittest.main()
index 2f7a5ef..7c57817 100644 (file)
@@ -38,7 +38,7 @@ from pprint import pformat
 import random
 import re
 import time
-from typing import Dict, Optional, Tuple
+from typing import Dict, List, Optional, Tuple
 
 from cinderclient import client as cClient
 from glanceclient import client as glClient
@@ -1227,11 +1227,14 @@ class vimconnector(vimconn.VimConnector):
         ) as e:
             self._format_exception(e)
 
-    def process_resource_quota(self, quota, prefix, extra_specs):
-        """
-        :param prefix:
-        :param extra_specs:
-        :return:
+    @staticmethod
+    def process_resource_quota(quota: dict, prefix: str, extra_specs: dict) -> None:
+        """Process resource quota and fill up extra_specs.
+        Args:
+            quota       (dict):         Keeping the quota of resurces
+            prefix      (str)           Prefix
+            extra_specs (dict)          Dict to be filled to be used during flavor creation
+
         """
         if "limit" in quota:
             extra_specs["quota:" + prefix + "_limit"] = quota["limit"]
@@ -1243,11 +1246,253 @@ class vimconnector(vimconn.VimConnector):
             extra_specs["quota:" + prefix + "_shares_level"] = "custom"
             extra_specs["quota:" + prefix + "_shares_share"] = quota["shares"]
 
-    def new_flavor(self, flavor_data, change_name_if_used=True):
-        """Adds a tenant flavor to openstack VIM
-        if change_name_if_used is True, it will change name in case of conflict, because it is not supported name
-         repetition
-        Returns the flavor identifier
+    @staticmethod
+    def process_numa_memory(
+        numa: dict, node_id: Optional[int], extra_specs: dict
+    ) -> None:
+        """Set the memory in extra_specs.
+        Args:
+            numa        (dict):         A dictionary which includes numa information
+            node_id     (int):          ID of numa node
+            extra_specs (dict):         To be filled.
+
+        """
+        if not numa.get("memory"):
+            return
+        memory_mb = numa["memory"] * 1024
+        memory = "hw:numa_mem.{}".format(node_id)
+        extra_specs[memory] = int(memory_mb)
+
+    @staticmethod
+    def process_numa_vcpu(numa: dict, node_id: int, extra_specs: dict) -> None:
+        """Set the cpu in extra_specs.
+        Args:
+            numa        (dict):         A dictionary which includes numa information
+            node_id     (int):          ID of numa node
+            extra_specs (dict):         To be filled.
+
+        """
+        if not numa.get("vcpu"):
+            return
+        vcpu = numa["vcpu"]
+        cpu = "hw:numa_cpus.{}".format(node_id)
+        vcpu = ",".join(map(str, vcpu))
+        extra_specs[cpu] = vcpu
+
+    @staticmethod
+    def process_numa_paired_threads(numa: dict, extra_specs: dict) -> Optional[int]:
+        """Fill up extra_specs if numa has paired-threads.
+        Args:
+            numa        (dict):         A dictionary which includes numa information
+            extra_specs (dict):         To be filled.
+
+        Returns:
+            vcpus       (int)           Number of virtual cpus
+
+        """
+        if not numa.get("paired-threads"):
+            return
+        # cpu_thread_policy "require" implies that compute node must have an STM architecture
+        vcpus = numa["paired-threads"] * 2
+        extra_specs["hw:cpu_thread_policy"] = "require"
+        extra_specs["hw:cpu_policy"] = "dedicated"
+        return vcpus
+
+    @staticmethod
+    def process_numa_cores(numa: dict, extra_specs: dict) -> Optional[int]:
+        """Fill up extra_specs if numa has cores.
+        Args:
+            numa        (dict):         A dictionary which includes numa information
+            extra_specs (dict):         To be filled.
+
+        Returns:
+            vcpus       (int)           Number of virtual cpus
+
+        """
+        # cpu_thread_policy "isolate" implies that the host must not have an SMT
+        # architecture, or a non-SMT architecture will be emulated
+        if not numa.get("cores"):
+            return
+        vcpus = numa["cores"]
+        extra_specs["hw:cpu_thread_policy"] = "isolate"
+        extra_specs["hw:cpu_policy"] = "dedicated"
+        return vcpus
+
+    @staticmethod
+    def process_numa_threads(numa: dict, extra_specs: dict) -> Optional[int]:
+        """Fill up extra_specs if numa has threads.
+        Args:
+            numa        (dict):         A dictionary which includes numa information
+            extra_specs (dict):         To be filled.
+
+        Returns:
+            vcpus       (int)           Number of virtual cpus
+
+        """
+        # cpu_thread_policy "prefer" implies that the host may or may not have an SMT architecture
+        if not numa.get("threads"):
+            return
+        vcpus = numa["threads"]
+        extra_specs["hw:cpu_thread_policy"] = "prefer"
+        extra_specs["hw:cpu_policy"] = "dedicated"
+        return vcpus
+
+    def _process_numa_parameters_of_flavor(
+        self, numas: List, extra_specs: Dict, vcpus: Optional[int]
+    ) -> int:
+        """Process numa parameters and fill up extra_specs.
+
+        Args:
+            numas   (list):             List of dictionary which includes numa information
+            extra_specs (dict):         To be filled.
+            vcpus       (int)      Number of virtual cpus
+
+        Returns:
+            vcpus       (int)           Number of virtual cpus
+
+        """
+        numa_nodes = len(numas)
+        extra_specs["hw:numa_nodes"] = str(numa_nodes)
+
+        if self.vim_type == "VIO":
+            extra_specs["vmware:extra_config"] = '{"numa.nodeAffinity":"0"}'
+            extra_specs["vmware:latency_sensitivity_level"] = "high"
+
+        for numa in numas:
+            if "id" in numa:
+                node_id = numa["id"]
+                # overwrite ram and vcpus
+                # check if key "memory" is present in numa else use ram value at flavor
+                self.process_numa_memory(numa, node_id, extra_specs)
+                self.process_numa_vcpu(numa, node_id, extra_specs)
+
+            # See for reference: https://specs.openstack.org/openstack/nova-specs/specs/mitaka/implemented/virt-driver-cpu-thread-pinning.html
+            extra_specs["hw:cpu_sockets"] = str(numa_nodes)
+
+            if "paired-threads" in numa:
+                vcpus = self.process_numa_paired_threads(numa, extra_specs)
+
+            elif "cores" in numa:
+                vcpus = self.process_numa_cores(numa, extra_specs)
+
+            elif "threads" in numa:
+                vcpus = self.process_numa_threads(numa, extra_specs)
+
+        return vcpus
+
+    def _change_flavor_name(
+        self, name: str, name_suffix: int, flavor_data: dict
+    ) -> str:
+        """Change the flavor name if the name already exists.
+
+        Args:
+            name    (str):          Flavor name to be checked
+            name_suffix (int):      Suffix to be appended to name
+            flavor_data (dict):     Flavor dict
+
+        Returns:
+            name    (str):          New flavor name to be used
+
+        """
+        # Get used names
+        fl = self.nova.flavors.list()
+        fl_names = [f.name for f in fl]
+
+        while name in fl_names:
+            name_suffix += 1
+            name = flavor_data["name"] + "-" + str(name_suffix)
+
+        return name
+
+    def _process_extended_config_of_flavor(
+        self, extended: dict, extra_specs: dict, vcpus: Optional[int]
+    ) -> int:
+        """Process the extended dict to fill up extra_specs.
+        Args:
+
+            extended    (dict):         Keeping the extra specification of flavor
+            extra_specs (dict)          Dict to be filled to be used during flavor creation
+            vcpus       (int)           Number of virtual cpus
+
+        Returns:
+            vcpus       (int)           Number of virtual cpus
+
+        """
+        quotas = {
+            "cpu-quota": "cpu",
+            "mem-quota": "memory",
+            "vif-quota": "vif",
+            "disk-io-quota": "disk_io",
+        }
+
+        page_sizes = {
+            "LARGE": "large",
+            "SMALL": "small",
+            "SIZE_2MB": "2MB",
+            "SIZE_1GB": "1GB",
+            "PREFER_LARGE": "any",
+        }
+
+        policies = {
+            "cpu-pinning-policy": "hw:cpu_policy",
+            "cpu-thread-pinning-policy": "hw:cpu_thread_policy",
+            "mem-policy": "hw:numa_mempolicy",
+        }
+
+        numas = extended.get("numas")
+        if numas:
+            vcpus = self._process_numa_parameters_of_flavor(numas, extra_specs, vcpus)
+
+        for quota, item in quotas.items():
+            if quota in extended.keys():
+                self.process_resource_quota(extended.get(quota), item, extra_specs)
+
+        # Set the mempage size as specified in the descriptor
+        if extended.get("mempage-size"):
+            if extended["mempage-size"] in page_sizes.keys():
+                extra_specs["hw:mem_page_size"] = page_sizes[extended["mempage-size"]]
+            else:
+                # Normally, validations in NBI should not allow to this condition.
+                self.logger.debug(
+                    "Invalid mempage-size %s. Will be ignored",
+                    extended.get("mempage-size"),
+                )
+
+        for policy, hw_policy in policies.items():
+            if extended.get(policy):
+                extra_specs[hw_policy] = extended[policy].lower()
+
+        return vcpus
+
+    @staticmethod
+    def _get_flavor_details(flavor_data: dict) -> Tuple:
+        """Returns the details of flavor
+        Args:
+            flavor_data     (dict):     Dictionary that includes required flavor details
+
+        Returns:
+            ram, vcpus, extra_specs, extended   (tuple):    Main items of required flavor
+
+        """
+        return (
+            flavor_data.get("ram", 64),
+            flavor_data.get("vcpus", 1),
+            {},
+            flavor_data.get("extended"),
+        )
+
+    def new_flavor(self, flavor_data: dict, change_name_if_used: bool = True) -> str:
+        """Adds a tenant flavor to openstack VIM.
+        if change_name_if_used is True, it will change name in case of conflict,
+        because it is not supported name repetition.
+
+        Args:
+            flavor_data (dict):             Flavor details to be processed
+            change_name_if_used (bool):     Change name in case of conflict
+
+        Returns:
+             flavor_id  (str):     flavor identifier
+
         """
         self.logger.debug("Adding flavor '%s'", str(flavor_data))
         retry = 0
@@ -1262,138 +1507,18 @@ class vimconnector(vimconn.VimConnector):
                     self._reload_connection()
 
                     if change_name_if_used:
-                        # get used names
-                        fl_names = []
-                        fl = self.nova.flavors.list()
-
-                        for f in fl:
-                            fl_names.append(f.name)
+                        name = self._change_flavor_name(name, name_suffix, flavor_data)
 
-                        while name in fl_names:
-                            name_suffix += 1
-                            name = flavor_data["name"] + "-" + str(name_suffix)
-
-                    ram = flavor_data.get("ram", 64)
-                    vcpus = flavor_data.get("vcpus", 1)
-                    extra_specs = {}
-
-                    extended = flavor_data.get("extended")
+                    ram, vcpus, extra_specs, extended = self._get_flavor_details(
+                        flavor_data
+                    )
                     if extended:
-                        numas = extended.get("numas")
-
-                        if numas:
-                            numa_nodes = len(numas)
-
-                            extra_specs["hw:numa_nodes"] = str(numa_nodes)
-
-                            if self.vim_type == "VIO":
-                                extra_specs[
-                                    "vmware:extra_config"
-                                ] = '{"numa.nodeAffinity":"0"}'
-                                extra_specs["vmware:latency_sensitivity_level"] = "high"
-
-                            for numa in numas:
-                                if "id" in numa:
-                                    node_id = numa["id"]
-
-                                    if "memory" in numa:
-                                        memory_mb = numa["memory"] * 1024
-                                        memory = "hw:numa_mem.{}".format(node_id)
-                                        extra_specs[memory] = int(memory_mb)
-
-                                    if "vcpu" in numa:
-                                        vcpu = numa["vcpu"]
-                                        cpu = "hw:numa_cpus.{}".format(node_id)
-                                        vcpu = ",".join(map(str, vcpu))
-                                        extra_specs[cpu] = vcpu
-
-                                # overwrite ram and vcpus
-                                # check if key "memory" is present in numa else use ram value at flavor
-                                # See for reference: https://specs.openstack.org/openstack/nova-specs/specs/mitaka/
-                                # implemented/virt-driver-cpu-thread-pinning.html
-                                extra_specs["hw:cpu_sockets"] = str(numa_nodes)
-
-                                if "paired-threads" in numa:
-                                    vcpus = numa["paired-threads"] * 2
-                                    # cpu_thread_policy "require" implies that the compute node must have an
-                                    # STM architecture
-                                    extra_specs["hw:cpu_thread_policy"] = "require"
-                                    extra_specs["hw:cpu_policy"] = "dedicated"
-                                elif "cores" in numa:
-                                    vcpus = numa["cores"]
-                                    # cpu_thread_policy "prefer" implies that the host must not have an SMT
-                                    # architecture, or a non-SMT architecture will be emulated
-                                    extra_specs["hw:cpu_thread_policy"] = "isolate"
-                                    extra_specs["hw:cpu_policy"] = "dedicated"
-                                elif "threads" in numa:
-                                    vcpus = numa["threads"]
-                                    # cpu_thread_policy "prefer" implies that the host may or may not have an SMT
-                                    # architecture
-                                    extra_specs["hw:cpu_thread_policy"] = "prefer"
-                                    extra_specs["hw:cpu_policy"] = "dedicated"
-                                # for interface in numa.get("interfaces",() ):
-                                #     if interface["dedicated"]=="yes":
-                                #         raise vimconn.VimConnException("Passthrough interfaces are not supported
-                                #         for the openstack connector", http_code=vimconn.HTTP_Service_Unavailable)
-                                #     #TODO, add the key 'pci_passthrough:alias"="<label at config>:<number ifaces>"'
-                                #      when a way to connect it is available
-                        elif extended.get("cpu-quota"):
-                            self.process_resource_quota(
-                                extended.get("cpu-quota"), "cpu", extra_specs
-                            )
-
-                        if extended.get("mem-quota"):
-                            self.process_resource_quota(
-                                extended.get("mem-quota"), "memory", extra_specs
-                            )
-
-                        if extended.get("vif-quota"):
-                            self.process_resource_quota(
-                                extended.get("vif-quota"), "vif", extra_specs
-                            )
+                        vcpus = self._process_extended_config_of_flavor(
+                            extended, extra_specs, vcpus
+                        )
 
-                        if extended.get("disk-io-quota"):
-                            self.process_resource_quota(
-                                extended.get("disk-io-quota"), "disk_io", extra_specs
-                            )
+                    # Create flavor
 
-                        # Set the mempage size as specified in the descriptor
-                        if extended.get("mempage-size"):
-                            if extended.get("mempage-size") == "LARGE":
-                                extra_specs["hw:mem_page_size"] = "large"
-                            elif extended.get("mempage-size") == "SMALL":
-                                extra_specs["hw:mem_page_size"] = "small"
-                            elif extended.get("mempage-size") == "SIZE_2MB":
-                                extra_specs["hw:mem_page_size"] = "2MB"
-                            elif extended.get("mempage-size") == "SIZE_1GB":
-                                extra_specs["hw:mem_page_size"] = "1GB"
-                            elif extended.get("mempage-size") == "PREFER_LARGE":
-                                extra_specs["hw:mem_page_size"] = "any"
-                            else:
-                                # The validations in NBI should make reaching here not possible.
-                                # If this message is shown, check validations
-                                self.logger.debug(
-                                    "Invalid mempage-size %s. Will be ignored",
-                                    extended.get("mempage-size"),
-                                )
-                        if extended.get("cpu-pinning-policy"):
-                            extra_specs["hw:cpu_policy"] = extended.get(
-                                "cpu-pinning-policy"
-                            ).lower()
-
-                        # Set the cpu thread pinning policy as specified in the descriptor
-                        if extended.get("cpu-thread-pinning-policy"):
-                            extra_specs["hw:cpu_thread_policy"] = extended.get(
-                                "cpu-thread-pinning-policy"
-                            ).lower()
-
-                        # Set the mem policy as specified in the descriptor
-                        if extended.get("mem-policy"):
-                            extra_specs["hw:numa_mempolicy"] = extended.get(
-                                "mem-policy"
-                            ).lower()
-
-                    # create flavor
                     new_flavor = self.nova.flavors.create(
                         name=name,
                         ram=ram,
@@ -1403,17 +1528,20 @@ class vimconnector(vimconn.VimConnector):
                         swap=flavor_data.get("swap", 0),
                         is_public=flavor_data.get("is_public", True),
                     )
-                    # add metadata
+
+                    # Add metadata
                     if extra_specs:
                         new_flavor.set_keys(extra_specs)
 
                     return new_flavor.id
+
                 except nvExceptions.Conflict as e:
+
                     if change_name_if_used and retry < max_retries:
                         continue
 
                     self._format_exception(e)
-        # except nvExceptions.BadRequest as e:
+
         except (
             ksExceptions.ClientException,
             nvExceptions.ClientException,
diff --git a/releasenotes/notes/refactor_new_flavor-9717ff4c02776dda.yaml b/releasenotes/notes/refactor_new_flavor-9717ff4c02776dda.yaml
new file mode 100644 (file)
index 0000000..66d9d74
--- /dev/null
@@ -0,0 +1,22 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+---
+other:
+  - |
+     Refactoring Openstack VIM Connector new_flavor method and adding unit tests
+
+