Pin black, flake and pylint versions in tox.ini
[osm/RO.git] / NG-RO / osm_ng_ro / tests / test_ns.py
index f4a1c87..0da5290 100644 (file)
@@ -71,6 +71,9 @@ vnfd_wth_persistent_storage = {
             "id": "persistent-root-volume",
             "type-of-storage": "persistent-storage:persistent-storage",
             "size-of-storage": "10",
+            "vdu-storage-requirements": [
+                {"key": "keep-volume", "value": "true"},
+            ],
         },
         {
             "id": "ephemeral-volume",
@@ -144,6 +147,9 @@ target_vdu_wth_persistent_storage = {
             "id": "persistent-root-volume",
             "size-of-storage": "10",
             "type-of-storage": "persistent-storage:persistent-storage",
+            "vdu-storage-requirements": [
+                {"key": "keep-volume", "value": "true"},
+            ],
         },
         {
             "id": "ephemeral-volume",
@@ -200,6 +206,7 @@ expected_extra_dict2 = {
         "start": True,
     },
 }
+
 tasks_by_target_record_id = {
     "nsrs:th47f48-9870-4169-b758-9732e1ff40f3": {
         "extra_dict": {
@@ -301,6 +308,80 @@ runcmd:
      - [ ls, -l, / ]
      - [ sh, -xc, "echo $(date) '& rm -rf /'" ]
 """
+vdu_id = "bb9c43f9-10a2-4569-a8a8-957c3528b6d1"
+vnf_id = "665b4165-ce24-4320-bf19-b9a45bade49f"
+target_vim = "vim:f9f370ac-0d44-41a7-9000-457f2332bc35"
+action_id = "bb937f49-3870-4169-b758-9732e1ff40f3"
+nsr_id_2 = "993166fe-723e-4680-ac4b-b1af2541ae31"
+target_record_1 = "vnfrs:665b4165-ce24-4320-bf19-b9a45bade49f:vdur.1.vim_info.vim:f9f370ac-0d44-41a7-9000-457f2332bc35"
+target_record_id = (
+    "vnfrs:665b4165-ce24-4320-bf19-b9a45bade49f:"
+    "vdur.bb9c43f9-10a2-4569-a8a8-957c3528b6d1"
+)
+expected_result_vertical_scale = {
+    "target_id": target_vim,
+    "action_id": "bb937f49-3870-4169-b758-9732e1ff40f3",
+    "nsr_id": "993166fe-723e-4680-ac4b-b1af2541ae31",
+    "task_id": "bb937f49-3870-4169-b758-9732e1ff40f3:1",
+    "status": "SCHEDULED",
+    "action": "EXEC",
+    "item": "verticalscale",
+    "target_record": target_record_1,
+    "target_record_id": target_record_id,
+    "params": {
+        "vim_vm_id": "f37b18ef-3caa-4dc9-ab91-15c669b16396",
+        "flavor_dict": "flavor_dict",
+        "flavor_id": "TASK-nsrs:993166fe-723e-4680-ac4b-b1af2541ae31:flavor.0",
+    },
+    "depends_on": ["nsrs:993166fe-723e-4680-ac4b-b1af2541ae31:flavor.0"],
+}
+vdu = {
+    "id": vdu_id,
+    "vim_info": {target_vim: {"interfaces": []}},
+    "ns-flavor-id": "0",
+}
+vnf = {"_id": vnf_id}
+extra_dict_vertical_scale = {
+    "params": {
+        "vim_vm_id": "f37b18ef-3caa-4dc9-ab91-15c669b16396",
+        "flavor_dict": "flavor_dict",
+    },
+}
+extra_dict_migrate = {
+    "params": {
+        "vim_vm_id": "f37b18ef-3caa-4dc9-ab91-15c669b16396",
+        "migrate_host": "migrateToHost",
+    },
+}
+expected_result_migrate = {
+    "target_id": target_vim,
+    "action_id": "bb937f49-3870-4169-b758-9732e1ff40f3",
+    "nsr_id": "993166fe-723e-4680-ac4b-b1af2541ae31",
+    "task_id": "bb937f49-3870-4169-b758-9732e1ff40f3:1",
+    "status": "SCHEDULED",
+    "action": "EXEC",
+    "item": "migrate",
+    "target_record": "vnfrs:665b4165-ce24-4320-bf19-b9a45bade49f:vdur.1.vim_info.vim:f9f370ac-0d44-41a7-9000-457f2332bc35",
+    "target_record_id": target_record_id,
+    "params": {
+        "vim_vm_id": "f37b18ef-3caa-4dc9-ab91-15c669b16396",
+        "migrate_host": "migrateToHost",
+    },
+}
+expected_result_rebuild_start_stop = {
+    "target_id": target_vim,
+    "action_id": "bb937f49-3870-4169-b758-9732e1ff40f3",
+    "nsr_id": "993166fe-723e-4680-ac4b-b1af2541ae31",
+    "task_id": "bb937f49-3870-4169-b758-9732e1ff40f3:0",
+    "status": "SCHEDULED",
+    "action": "EXEC",
+    "item": "update",
+    "target_record_id": "vnfrs:665b4165-ce24-4320-bf19-b9a45bade49f:vdur.bb9c43f9-10a2-4569-a8a8-957c3528b6d1",
+}
+
+
+class TestException(Exception):
+    pass
 
 
 class CopyingMock(MagicMock):
@@ -1488,7 +1569,7 @@ class TestNs(unittest.TestCase):
         self.assertDictEqual(expected_numa_result, numa_result)
         self.assertEqual(expected_epa_vcpu_set_result, epa_vcpu_set_result)
 
-    def test__process_guest_epa_cpu_pinning_params_with_threads(self):
+    def test__process_guest_epa_cpu_pinning_params_with_policy_prefer(self):
         expected_numa_result = {"threads": 3}
         expected_epa_vcpu_set_result = True
         guest_epa_quota = {
@@ -1507,9 +1588,47 @@ class TestNs(unittest.TestCase):
         self.assertDictEqual(expected_numa_result, numa_result)
         self.assertEqual(expected_epa_vcpu_set_result, epa_vcpu_set_result)
 
-    def test__process_guest_epa_cpu_pinning_params(self):
+    def test__process_guest_epa_cpu_pinning_params_with_policy_isolate(self):
         expected_numa_result = {"cores": 3}
         expected_epa_vcpu_set_result = True
+        guest_epa_quota = {
+            "cpu-pinning-policy": "DEDICATED",
+            "cpu-thread-pinning-policy": "ISOLATE",
+        }
+        vcpu_count = 3
+        epa_vcpu_set = False
+
+        numa_result, epa_vcpu_set_result = Ns._process_guest_epa_cpu_pinning_params(
+            guest_epa_quota=guest_epa_quota,
+            vcpu_count=vcpu_count,
+            epa_vcpu_set=epa_vcpu_set,
+        )
+
+        self.assertDictEqual(expected_numa_result, numa_result)
+        self.assertEqual(expected_epa_vcpu_set_result, epa_vcpu_set_result)
+
+    def test__process_guest_epa_cpu_pinning_params_with_policy_require(self):
+        expected_numa_result = {"threads": 3}
+        expected_epa_vcpu_set_result = True
+        guest_epa_quota = {
+            "cpu-pinning-policy": "DEDICATED",
+            "cpu-thread-pinning-policy": "REQUIRE",
+        }
+        vcpu_count = 3
+        epa_vcpu_set = False
+
+        numa_result, epa_vcpu_set_result = Ns._process_guest_epa_cpu_pinning_params(
+            guest_epa_quota=guest_epa_quota,
+            vcpu_count=vcpu_count,
+            epa_vcpu_set=epa_vcpu_set,
+        )
+
+        self.assertDictEqual(expected_numa_result, numa_result)
+        self.assertEqual(expected_epa_vcpu_set_result, epa_vcpu_set_result)
+
+    def test__process_guest_epa_cpu_pinning_params(self):
+        expected_numa_result = {"threads": 3}
+        expected_epa_vcpu_set_result = True
         guest_epa_quota = {
             "cpu-pinning-policy": "DEDICATED",
         }
@@ -1771,7 +1890,6 @@ class TestNs(unittest.TestCase):
         self,
         epa_params,
     ):
-
         target_flavor = {}
         indata = {
             "vnf": [
@@ -1798,7 +1916,6 @@ class TestNs(unittest.TestCase):
         self,
         epa_params,
     ):
-
         target_flavor = {
             "no-target-flavor": "here",
         }
@@ -1821,7 +1938,6 @@ class TestNs(unittest.TestCase):
         self,
         epa_params,
     ):
-
         expected_result = {
             "find_params": {
                 "flavor_data": {
@@ -1866,7 +1982,6 @@ class TestNs(unittest.TestCase):
         self,
         epa_params,
     ):
-
         expected_result = {
             "find_params": {
                 "flavor_data": {
@@ -2023,7 +2138,6 @@ class TestNs(unittest.TestCase):
         self,
         epa_params,
     ):
-
         expected_result = {
             "find_params": {
                 "flavor_data": {
@@ -2088,7 +2202,6 @@ class TestNs(unittest.TestCase):
         self,
         epa_params,
     ):
-
         kwargs = {
             "db": db,
         }
@@ -2199,7 +2312,6 @@ class TestNs(unittest.TestCase):
         self,
         epa_params,
     ):
-
         expected_result = {
             "find_params": {
                 "flavor_data": {
@@ -2260,11 +2372,57 @@ class TestNs(unittest.TestCase):
         self.assertDictEqual(result, expected_result)
 
     @patch("osm_ng_ro.ns.Ns._process_epa_params")
-    def test__process_flavor_params(
+    def test__process_flavor_params_with_vim_flavor_id(
         self,
         epa_params,
     ):
+        expected_result = {
+            "find_params": {
+                "vim_flavor_id": "test.flavor",
+            },
+        }
+        target_flavor = {
+            "id": "test_id",
+            "name": "test",
+            "storage-gb": "10",
+            "memory-mb": "1024",
+            "vcpu-count": "2",
+        }
+        indata = {
+            "vnf": [
+                {
+                    "vdur": [
+                        {
+                            "ns-flavor-id": "test_id",
+                            "additionalParams": {
+                                "OSM": {"vim_flavor_id": "test.flavor"}
+                            },
+                        },
+                    ],
+                    "vnfd-id": "ad6356e3-698c-43bf-9901-3aae9e9b9d18",
+                },
+            ],
+        }
+        vim_info = {}
+        target_record_id = ""
+
+        epa_params.return_value = {}
+
+        result = Ns._process_flavor_params(
+            target_flavor=target_flavor,
+            indata=indata,
+            vim_info=vim_info,
+            target_record_id=target_record_id,
+        )
 
+        self.assertFalse(epa_params.called)
+        self.assertDictEqual(result, expected_result)
+
+    @patch("osm_ng_ro.ns.Ns._process_epa_params")
+    def test__process_flavor_params(
+        self,
+        epa_params,
+    ):
         kwargs = {
             "db": db,
         }
@@ -2385,213 +2543,8 @@ class TestNs(unittest.TestCase):
         self.assertTrue(epa_params.called)
         self.assertDictEqual(result, expected_result)
 
-    def test__ip_profile_to_ro_with_none(self):
-        ip_profile = None
-
-        result = Ns._ip_profile_to_ro(
-            ip_profile=ip_profile,
-        )
-
-        self.assertIsNone(result)
-
-    def test__ip_profile_to_ro_with_empty_profile(self):
-        ip_profile = {}
-
-        result = Ns._ip_profile_to_ro(
-            ip_profile=ip_profile,
-        )
-
-        self.assertIsNone(result)
-
-    def test__ip_profile_to_ro_with_wrong_profile(self):
-        ip_profile = {
-            "no-profile": "here",
-        }
-        expected_result = {
-            "ip_version": "IPv4",
-            "subnet_address": None,
-            "gateway_address": None,
-            "dhcp_enabled": False,
-            "dhcp_start_address": None,
-            "dhcp_count": None,
-        }
-
-        result = Ns._ip_profile_to_ro(
-            ip_profile=ip_profile,
-        )
-
-        self.assertDictEqual(expected_result, result)
-
-    def test__ip_profile_to_ro_with_ipv4_profile(self):
-        ip_profile = {
-            "ip-version": "ipv4",
-            "subnet-address": "192.168.0.0/24",
-            "gateway-address": "192.168.0.254",
-            "dhcp-params": {
-                "enabled": True,
-                "start-address": "192.168.0.10",
-                "count": 25,
-            },
-        }
-        expected_result = {
-            "ip_version": "IPv4",
-            "subnet_address": "192.168.0.0/24",
-            "gateway_address": "192.168.0.254",
-            "dhcp_enabled": True,
-            "dhcp_start_address": "192.168.0.10",
-            "dhcp_count": 25,
-        }
-
-        result = Ns._ip_profile_to_ro(
-            ip_profile=ip_profile,
-        )
-
-        self.assertDictEqual(expected_result, result)
-
-    def test__ip_profile_to_ro_with_ipv6_profile(self):
-        ip_profile = {
-            "ip-version": "ipv6",
-            "subnet-address": "2001:0200:0001::/48",
-            "gateway-address": "2001:0200:0001:ffff:ffff:ffff:ffff:fffe",
-            "dhcp-params": {
-                "enabled": True,
-                "start-address": "2001:0200:0001::0010",
-                "count": 25,
-            },
-        }
-        expected_result = {
-            "ip_version": "IPv6",
-            "subnet_address": "2001:0200:0001::/48",
-            "gateway_address": "2001:0200:0001:ffff:ffff:ffff:ffff:fffe",
-            "dhcp_enabled": True,
-            "dhcp_start_address": "2001:0200:0001::0010",
-            "dhcp_count": 25,
-        }
-
-        result = Ns._ip_profile_to_ro(
-            ip_profile=ip_profile,
-        )
-
-        self.assertDictEqual(expected_result, result)
-
-    def test__ip_profile_to_ro_with_dns_server(self):
-        ip_profile = {
-            "ip-version": "ipv4",
-            "subnet-address": "192.168.0.0/24",
-            "gateway-address": "192.168.0.254",
-            "dhcp-params": {
-                "enabled": True,
-                "start-address": "192.168.0.10",
-                "count": 25,
-            },
-            "dns-server": [
-                {
-                    "address": "8.8.8.8",
-                },
-                {
-                    "address": "1.1.1.1",
-                },
-                {
-                    "address": "1.0.0.1",
-                },
-            ],
-        }
-        expected_result = {
-            "ip_version": "IPv4",
-            "subnet_address": "192.168.0.0/24",
-            "gateway_address": "192.168.0.254",
-            "dhcp_enabled": True,
-            "dhcp_start_address": "192.168.0.10",
-            "dhcp_count": 25,
-            "dns_address": "8.8.8.8;1.1.1.1;1.0.0.1",
-        }
-
-        result = Ns._ip_profile_to_ro(
-            ip_profile=ip_profile,
-        )
-
-        self.assertDictEqual(expected_result, result)
-
-    def test__ip_profile_to_ro_with_security_group(self):
-        ip_profile = {
-            "ip-version": "ipv4",
-            "subnet-address": "192.168.0.0/24",
-            "gateway-address": "192.168.0.254",
-            "dhcp-params": {
-                "enabled": True,
-                "start-address": "192.168.0.10",
-                "count": 25,
-            },
-            "security-group": {
-                "some-security-group": "here",
-            },
-        }
-        expected_result = {
-            "ip_version": "IPv4",
-            "subnet_address": "192.168.0.0/24",
-            "gateway_address": "192.168.0.254",
-            "dhcp_enabled": True,
-            "dhcp_start_address": "192.168.0.10",
-            "dhcp_count": 25,
-            "security_group": {
-                "some-security-group": "here",
-            },
-        }
-
-        result = Ns._ip_profile_to_ro(
-            ip_profile=ip_profile,
-        )
-
-        self.assertDictEqual(expected_result, result)
-
-    def test__ip_profile_to_ro(self):
-        ip_profile = {
-            "ip-version": "ipv4",
-            "subnet-address": "192.168.0.0/24",
-            "gateway-address": "192.168.0.254",
-            "dhcp-params": {
-                "enabled": True,
-                "start-address": "192.168.0.10",
-                "count": 25,
-            },
-            "dns-server": [
-                {
-                    "address": "8.8.8.8",
-                },
-                {
-                    "address": "1.1.1.1",
-                },
-                {
-                    "address": "1.0.0.1",
-                },
-            ],
-            "security-group": {
-                "some-security-group": "here",
-            },
-        }
-        expected_result = {
-            "ip_version": "IPv4",
-            "subnet_address": "192.168.0.0/24",
-            "gateway_address": "192.168.0.254",
-            "dhcp_enabled": True,
-            "dhcp_start_address": "192.168.0.10",
-            "dhcp_count": 25,
-            "dns_address": "8.8.8.8;1.1.1.1;1.0.0.1",
-            "security_group": {
-                "some-security-group": "here",
-            },
-        }
-
-        result = Ns._ip_profile_to_ro(
-            ip_profile=ip_profile,
-        )
-
-        self.assertDictEqual(expected_result, result)
-
-    @patch("osm_ng_ro.ns.Ns._ip_profile_to_ro")
     def test__process_net_params_with_empty_params(
         self,
-        ip_profile_to_ro,
     ):
         target_vld = {
             "name": "vld-name",
@@ -2601,6 +2554,9 @@ class TestNs(unittest.TestCase):
         }
         vim_info = {
             "provider_network": "some-profile-here",
+            "ip_profile": {
+                "some_ip_profile": "here",
+            },
         }
         target_record_id = ""
         expected_result = {
@@ -2614,10 +2570,6 @@ class TestNs(unittest.TestCase):
             }
         }
 
-        ip_profile_to_ro.return_value = {
-            "some_ip_profile": "here",
-        }
-
         result = Ns._process_net_params(
             target_vld=target_vld,
             indata=indata,
@@ -2626,12 +2578,9 @@ class TestNs(unittest.TestCase):
         )
 
         self.assertDictEqual(expected_result, result)
-        self.assertTrue(ip_profile_to_ro.called)
 
-    @patch("osm_ng_ro.ns.Ns._ip_profile_to_ro")
     def test__process_net_params_with_vim_info_sdn(
         self,
-        ip_profile_to_ro,
     ):
         target_vld = {
             "name": "vld-name",
@@ -2662,12 +2611,9 @@ class TestNs(unittest.TestCase):
         )
 
         self.assertDictEqual(expected_result, result)
-        self.assertFalse(ip_profile_to_ro.called)
 
-    @patch("osm_ng_ro.ns.Ns._ip_profile_to_ro")
     def test__process_net_params_with_vim_info_sdn_target_vim(
         self,
-        ip_profile_to_ro,
     ):
         target_vld = {
             "name": "vld-name",
@@ -2701,12 +2647,9 @@ class TestNs(unittest.TestCase):
         )
 
         self.assertDictEqual(expected_result, result)
-        self.assertFalse(ip_profile_to_ro.called)
 
-    @patch("osm_ng_ro.ns.Ns._ip_profile_to_ro")
     def test__process_net_params_with_vim_network_name(
         self,
-        ip_profile_to_ro,
     ):
         target_vld = {
             "name": "vld-name",
@@ -2734,12 +2677,9 @@ class TestNs(unittest.TestCase):
         )
 
         self.assertDictEqual(expected_result, result)
-        self.assertFalse(ip_profile_to_ro.called)
 
-    @patch("osm_ng_ro.ns.Ns._ip_profile_to_ro")
     def test__process_net_params_with_vim_network_id(
         self,
-        ip_profile_to_ro,
     ):
         target_vld = {
             "name": "vld-name",
@@ -2767,12 +2707,9 @@ class TestNs(unittest.TestCase):
         )
 
         self.assertDictEqual(expected_result, result)
-        self.assertFalse(ip_profile_to_ro.called)
 
-    @patch("osm_ng_ro.ns.Ns._ip_profile_to_ro")
     def test__process_net_params_with_mgmt_network(
         self,
-        ip_profile_to_ro,
     ):
         target_vld = {
             "id": "vld-id",
@@ -2799,12 +2736,9 @@ class TestNs(unittest.TestCase):
         )
 
         self.assertDictEqual(expected_result, result)
-        self.assertFalse(ip_profile_to_ro.called)
 
-    @patch("osm_ng_ro.ns.Ns._ip_profile_to_ro")
     def test__process_net_params_with_underlay_eline(
         self,
-        ip_profile_to_ro,
     ):
         target_vld = {
             "name": "vld-name",
@@ -2816,6 +2750,9 @@ class TestNs(unittest.TestCase):
         }
         vim_info = {
             "provider_network": "some-profile-here",
+            "ip_profile": {
+                "some_ip_profile": "here",
+            },
         }
         target_record_id = ""
         expected_result = {
@@ -2829,10 +2766,6 @@ class TestNs(unittest.TestCase):
             }
         }
 
-        ip_profile_to_ro.return_value = {
-            "some_ip_profile": "here",
-        }
-
         result = Ns._process_net_params(
             target_vld=target_vld,
             indata=indata,
@@ -2841,12 +2774,9 @@ class TestNs(unittest.TestCase):
         )
 
         self.assertDictEqual(expected_result, result)
-        self.assertTrue(ip_profile_to_ro.called)
 
-    @patch("osm_ng_ro.ns.Ns._ip_profile_to_ro")
     def test__process_net_params_with_underlay_elan(
         self,
-        ip_profile_to_ro,
     ):
         target_vld = {
             "name": "vld-name",
@@ -2858,6 +2788,9 @@ class TestNs(unittest.TestCase):
         }
         vim_info = {
             "provider_network": "some-profile-here",
+            "ip_profile": {
+                "some_ip_profile": "here",
+            },
         }
         target_record_id = ""
         expected_result = {
@@ -2871,10 +2804,6 @@ class TestNs(unittest.TestCase):
             }
         }
 
-        ip_profile_to_ro.return_value = {
-            "some_ip_profile": "here",
-        }
-
         result = Ns._process_net_params(
             target_vld=target_vld,
             indata=indata,
@@ -2883,7 +2812,6 @@ class TestNs(unittest.TestCase):
         )
 
         self.assertDictEqual(expected_result, result)
-        self.assertTrue(ip_profile_to_ro.called)
 
     def test__get_cloud_init_exception(self):
         db_mock = MagicMock(name="database mock")
@@ -3096,66 +3024,198 @@ class TestNs(unittest.TestCase):
             self.assertEqual(result, expected_result)
 
     @patch("osm_ng_ro.ns.Ns._assign_vim")
-    def test__rebuild_start_stop_task(self, assign_vim):
+    def test__rebuild_start_stop_task__successful(self, assign_vim):
         self.ns = Ns()
         extra_dict = {}
         actions = ["start", "stop", "rebuild"]
-        vdu_id = "bb9c43f9-10a2-4569-a8a8-957c3528b6d1"
-        vnf_id = "665b4165-ce24-4320-bf19-b9a45bade49f"
         vdu_index = "0"
-        action_id = "bb937f49-3870-4169-b758-9732e1ff40f3"
-        nsr_id = "993166fe-723e-4680-ac4b-b1af2541ae31"
         task_index = 0
-        target_vim = "vim:f9f370ac-0d44-41a7-9000-457f2332bc35"
-        t = "vnfrs:665b4165-ce24-4320-bf19-b9a45bade49f:vdur.bb9c43f9-10a2-4569-a8a8-957c3528b6d1"
         for action in actions:
-            expected_result = {
-                "target_id": "vim:f9f370ac-0d44-41a7-9000-457f2332bc35",
-                "action_id": "bb937f49-3870-4169-b758-9732e1ff40f3",
-                "nsr_id": "993166fe-723e-4680-ac4b-b1af2541ae31",
-                "task_id": "bb937f49-3870-4169-b758-9732e1ff40f3:0",
-                "status": "SCHEDULED",
-                "action": "EXEC",
-                "item": "update",
-                "target_record": "vnfrs:665b4165-ce24-4320-bf19-b9a45bade49f:vdur.0",
-                "target_record_id": t,
-                "params": {
-                    "vim_vm_id": "f37b18ef-3caa-4dc9-ab91-15c669b16396",
-                    "action": action,
-                },
+            params = {
+                "vim_vm_id": "f37b18ef-3caa-4dc9-ab91-15c669b16396",
+                "action": action,
             }
-            extra_dict["params"] = {
+            extra_dict["params"] = params
+            expected_result = deepcopy(expected_result_rebuild_start_stop)
+            expected_result["target_record"] = (
+                "vnfrs:665b4165-ce24-4320-bf19-b9a45bade49f:vdur.0.vim_info.vim:f9f370ac-0d44-41a7-9000-457f2332bc35"
+            )
+            expected_result["params"] = params
+            task = self.ns.rebuild_start_stop_task(
+                vdu_id,
+                vnf_id,
+                vdu_index,
+                action_id,
+                nsr_id_2,
+                task_index,
+                target_vim,
+                extra_dict,
+            )
+            self.assertDictEqual(task, expected_result)
+
+    @patch("osm_ng_ro.ns.Ns._assign_vim")
+    def test__rebuild_start_stop_task__empty_extra_dict__task_without_params(
+        self, assign_vim
+    ):
+        self.ns = Ns()
+        extra_dict = {}
+        actions = ["start", "stop", "rebuild"]
+        vdu_index = "0"
+        task_index = 0
+        expected_result = deepcopy(expected_result_rebuild_start_stop)
+        expected_result["target_record"] = (
+            "vnfrs:665b4165-ce24-4320-bf19-b9a45bade49f:vdur.0.vim_info.vim:f9f370ac-0d44-41a7-9000-457f2332bc35"
+        )
+        for _ in actions:
+            task = self.ns.rebuild_start_stop_task(
+                vdu_id,
+                vnf_id,
+                vdu_index,
+                action_id,
+                nsr_id_2,
+                task_index,
+                target_vim,
+                extra_dict,
+            )
+            self.assertDictEqual(task, expected_result)
+
+    @patch("osm_ng_ro.ns.Ns._assign_vim")
+    def test__rebuild_start_stop_task__different_vdu_index__target_record_changes(
+        self, assign_vim
+    ):
+        self.ns = Ns()
+        extra_dict = {}
+        actions = ["start", "stop", "rebuild"]
+        vdu_index = "4"
+        task_index = 0
+        for action in actions:
+            params = {
                 "vim_vm_id": "f37b18ef-3caa-4dc9-ab91-15c669b16396",
                 "action": action,
             }
+            extra_dict["params"] = params
+            expected_result = deepcopy(expected_result_rebuild_start_stop)
+            expected_result["target_record"] = (
+                "vnfrs:665b4165-ce24-4320-bf19-b9a45bade49f:vdur.4.vim_info.vim:f9f370ac-0d44-41a7-9000-457f2332bc35"
+            )
+            expected_result["params"] = params
             task = self.ns.rebuild_start_stop_task(
                 vdu_id,
                 vnf_id,
                 vdu_index,
                 action_id,
-                nsr_id,
+                nsr_id_2,
                 task_index,
                 target_vim,
                 extra_dict,
             )
-            self.assertEqual(task.get("action_id"), action_id)
-            self.assertEqual(task.get("nsr_id"), nsr_id)
-            self.assertEqual(task.get("target_id"), target_vim)
             self.assertDictEqual(task, expected_result)
 
     @patch("osm_ng_ro.ns.Ns._assign_vim")
-    def test_verticalscale_task(self, assign_vim):
+    def test__rebuild_start_stop_task__different_task_index__task_id_changes(
+        self, assign_vim
+    ):
         self.ns = Ns()
         extra_dict = {}
+        actions = ["start", "stop", "rebuild"]
+        vdu_index = "0"
+        task_index = 3
+        for action in actions:
+            params = {
+                "vim_vm_id": "f37b18ef-3caa-4dc9-ab91-15c669b16396",
+                "action": action,
+            }
+            extra_dict["params"] = params
+            expected_result = deepcopy(expected_result_rebuild_start_stop)
+            expected_result["target_record"] = (
+                "vnfrs:665b4165-ce24-4320-bf19-b9a45bade49f:vdur.0.vim_info.vim:f9f370ac-0d44-41a7-9000-457f2332bc35"
+            )
+            expected_result["params"] = params
+            expected_result["task_id"] = "bb937f49-3870-4169-b758-9732e1ff40f3:3"
+            task = self.ns.rebuild_start_stop_task(
+                vdu_id,
+                vnf_id,
+                vdu_index,
+                action_id,
+                nsr_id_2,
+                task_index,
+                target_vim,
+                extra_dict,
+            )
+            self.assertDictEqual(task, expected_result)
+
+    @patch("osm_ng_ro.ns.Ns._assign_vim")
+    def test__rebuild_start_stop_task__assign_vim_raises__task_is_not_created(
+        self, assign_vim
+    ):
+        self.ns = Ns()
+        extra_dict = {}
+        actions = ["start", "stop", "rebuild"]
+        vdu_index = "0"
+        task_index = 0
+        for action in actions:
+            params = {
+                "vim_vm_id": "f37b18ef-3caa-4dc9-ab91-15c669b16396",
+                "action": action,
+            }
+            extra_dict["params"] = params
+            assign_vim.side_effect = TestException("Can not connect to VIM.")
+            with self.assertRaises(TestException) as err:
+                task = self.ns.rebuild_start_stop_task(
+                    vdu_id,
+                    vnf_id,
+                    vdu_index,
+                    action_id,
+                    nsr_id_2,
+                    task_index,
+                    target_vim,
+                    extra_dict,
+                )
+                self.assertEqual(task, None)
+                self.assertEqual(str(err.exception), "Can not connect to VIM.")
+
+    @patch("osm_ng_ro.ns.Ns._assign_vim")
+    def test_verticalscale_task__successful(self, assign_vim):
+        self.ns = Ns()
         vdu_index = "1"
-        action_id = "bb937f49-3870-4169-b758-9732e1ff40f3"
-        nsr_id = "993166fe-723e-4680-ac4b-b1af2541ae31"
         task_index = 1
-        target_record_id = (
-            "vnfrs:665b4165-ce24-4320-bf19-b9a45bade49f:"
-            "vdur.bb9c43f9-10a2-4569-a8a8-957c3528b6d1"
+        task = self.ns.verticalscale_task(
+            vdu,
+            vnf,
+            vdu_index,
+            action_id,
+            nsr_id_2,
+            task_index,
+            extra_dict_vertical_scale,
+        )
+        self.assertDictEqual(task, expected_result_vertical_scale)
+
+    @patch("osm_ng_ro.ns.Ns._assign_vim")
+    def test_verticalscale_task__task_index_changes__task_id_changes(self, assign_vim):
+        self.ns = Ns()
+        vdu_index = "1"
+        task_index = 2
+        expected_result = deepcopy(expected_result_vertical_scale)
+        expected_result["task_id"] = "bb937f49-3870-4169-b758-9732e1ff40f3:2"
+        task = self.ns.verticalscale_task(
+            vdu,
+            vnf,
+            vdu_index,
+            action_id,
+            nsr_id_2,
+            task_index,
+            extra_dict_vertical_scale,
         )
+        self.assertDictEqual(task, expected_result)
 
+    @patch("osm_ng_ro.ns.Ns._assign_vim")
+    def test_verticalscale_task__empty_extra_dict__expected_result_without_params(
+        self, assign_vim
+    ):
+        self.ns = Ns()
+        extra_dict = {"params": {}}
+        vdu_index = "1"
+        task_index = 1
         expected_result = {
             "target_id": "vim:f9f370ac-0d44-41a7-9000-457f2332bc35",
             "action_id": "bb937f49-3870-4169-b758-9732e1ff40f3",
@@ -3164,107 +3224,140 @@ class TestNs(unittest.TestCase):
             "status": "SCHEDULED",
             "action": "EXEC",
             "item": "verticalscale",
-            "target_record": "vnfrs:665b4165-ce24-4320-bf19-b9a45bade49f:vdur.1",
-            "target_record_id": target_record_id,
+            "target_record": "vnfrs:665b4165-ce24-4320-bf19-b9a45bade49f:vdur.1.vim_info.vim:f9f370ac-0d44-41a7-9000-457f2332bc35",
+            "target_record_id": "vnfrs:665b4165-ce24-4320-bf19-b9a45bade49f:vdur.bb9c43f9-10a2-4569-a8a8-957c3528b6d1",
             "params": {
-                "vim_vm_id": "f37b18ef-3caa-4dc9-ab91-15c669b16396",
-                "flavor_dict": "flavor_dict",
-            },
-        }
-        vdu = {
-            "id": "bb9c43f9-10a2-4569-a8a8-957c3528b6d1",
-            "vim_info": {
-                "vim:f9f370ac-0d44-41a7-9000-457f2332bc35": {"interfaces": []}
+                "flavor_id": "TASK-nsrs:993166fe-723e-4680-ac4b-b1af2541ae31:flavor.0"
             },
+            "depends_on": ["nsrs:993166fe-723e-4680-ac4b-b1af2541ae31:flavor.0"],
         }
-        vnf = {"_id": "665b4165-ce24-4320-bf19-b9a45bade49f"}
-        extra_dict["params"] = {
-            "vim_vm_id": "f37b18ef-3caa-4dc9-ab91-15c669b16396",
-            "flavor_dict": "flavor_dict",
-        }
+
         task = self.ns.verticalscale_task(
-            vdu, vnf, vdu_index, action_id, nsr_id, task_index, extra_dict
+            vdu, vnf, vdu_index, action_id, nsr_id_2, task_index, extra_dict
         )
-
         self.assertDictEqual(task, expected_result)
 
     @patch("osm_ng_ro.ns.Ns._assign_vim")
-    def test_migrate_task(self, assign_vim):
+    def test_verticalscale_task__assign_vim_raises__task_is_not_created(
+        self, assign_vim
+    ):
+        self.ns = Ns()
+        vdu_index = "1"
+        task_index = 1
+        assign_vim.side_effect = TestException("Can not connect to VIM.")
+        with self.assertRaises(TestException) as err:
+            task = self.ns.verticalscale_task(
+                vdu,
+                vnf,
+                vdu_index,
+                action_id,
+                nsr_id_2,
+                task_index,
+                extra_dict_vertical_scale,
+            )
+            self.assertEqual(task, {})
+            self.assertEqual(str(err.exception), "Can not connect to VIM.")
+
+    @patch("osm_ng_ro.ns.Ns._assign_vim")
+    def test_migrate_task__successful(self, assign_vim):
         self.ns = Ns()
-        extra_dict = {}
         vdu_index = "1"
-        action_id = "bb937f49-3870-4169-b758-9732e1ff40f3"
-        nsr_id = "993166fe-723e-4680-ac4b-b1af2541ae31"
         task_index = 1
-        target_record_id = (
-            "vnfrs:665b4165-ce24-4320-bf19-b9a45bade49f:"
-            "vdur.bb9c43f9-10a2-4569-a8a8-957c3528b6d1"
+        task = self.ns.migrate_task(
+            vdu, vnf, vdu_index, action_id, nsr_id_2, task_index, extra_dict_migrate
         )
+        self.assertDictEqual(task, expected_result_migrate)
 
-        expected_result = {
-            "target_id": "vim:f9f370ac-0d44-41a7-9000-457f2332bc35",
-            "action_id": "bb937f49-3870-4169-b758-9732e1ff40f3",
-            "nsr_id": "993166fe-723e-4680-ac4b-b1af2541ae31",
-            "task_id": "bb937f49-3870-4169-b758-9732e1ff40f3:1",
-            "status": "SCHEDULED",
-            "action": "EXEC",
-            "item": "migrate",
-            "target_record": "vnfrs:665b4165-ce24-4320-bf19-b9a45bade49f:vdur.1",
-            "target_record_id": target_record_id,
-            "params": {
-                "vim_vm_id": "f37b18ef-3caa-4dc9-ab91-15c669b16396",
-                "migrate_host": "migrateToHost",
-            },
-        }
-        vdu = {
-            "id": "bb9c43f9-10a2-4569-a8a8-957c3528b6d1",
-            "vim_info": {
-                "vim:f9f370ac-0d44-41a7-9000-457f2332bc35": {"interfaces": []}
-            },
-        }
-        vnf = {"_id": "665b4165-ce24-4320-bf19-b9a45bade49f"}
-        extra_dict["params"] = {
-            "vim_vm_id": "f37b18ef-3caa-4dc9-ab91-15c669b16396",
-            "migrate_host": "migrateToHost",
-        }
+    @patch("osm_ng_ro.ns.Ns._assign_vim")
+    def test_migrate_task__empty_extra_dict__task_without_params(self, assign_vim):
+        self.ns = Ns()
+        extra_dict = {}
+        vdu_index = "1"
+        task_index = 1
+        expected_result = deepcopy(expected_result_migrate)
+        expected_result.pop("params")
         task = self.ns.migrate_task(
-            vdu, vnf, vdu_index, action_id, nsr_id, task_index, extra_dict
+            vdu, vnf, vdu_index, action_id, nsr_id_2, task_index, extra_dict
         )
+        self.assertDictEqual(task, expected_result)
 
+    @patch("osm_ng_ro.ns.Ns._assign_vim")
+    def test_migrate_task__different_vdu_index__target_record_with_different_vdu_index(
+        self, assign_vim
+    ):
+        self.ns = Ns()
+        vdu_index = "4"
+        task_index = 1
+        expected_result = deepcopy(expected_result_migrate)
+        expected_result["target_record"] = (
+            "vnfrs:665b4165-ce24-4320-bf19-b9a45bade49f:vdur.4.vim_info.vim:f9f370ac-0d44-41a7-9000-457f2332bc35"
+        )
+        task = self.ns.migrate_task(
+            vdu, vnf, vdu_index, action_id, nsr_id_2, task_index, extra_dict_migrate
+        )
         self.assertDictEqual(task, expected_result)
 
+    @patch("osm_ng_ro.ns.Ns._assign_vim")
+    def test_migrate_task__assign_vim_raises__task_is_not_created(self, assign_vim):
+        self.ns = Ns()
+        vdu_index = "1"
+        task_index = 1
+        assign_vim.side_effect = TestException("Can not connect to VIM.")
+        with self.assertRaises(TestException) as err:
+            task = self.ns.migrate_task(
+                vdu, vnf, vdu_index, action_id, nsr_id, task_index, extra_dict_migrate
+            )
+            self.assertDictEqual(task, {})
+            self.assertEqual(str(err.exception), "Can not connect to VIM.")
+
 
 class TestProcessVduParams(unittest.TestCase):
     def setUp(self):
         self.ns = Ns()
         self.logger = CopyingMock(autospec=True)
 
-    def test_find_persistent_root_volumes_empty_instantiation_vol_list(self):
+    @patch("osm_ng_ro.ns.Ns.is_volume_keeping_required")
+    def test_find_persistent_root_volumes_empty_instantiation_vol_list(
+        self, mock_volume_keeping_required
+    ):
         """Find persistent root volume, instantiation_vol_list is empty."""
         vnfd = deepcopy(vnfd_wth_persistent_storage)
         target_vdu = target_vdu_wth_persistent_storage
         vdu_instantiation_volumes_list = []
         disk_list = []
+        mock_volume_keeping_required.return_value = True
+        expected_root_disk = {
+            "id": "persistent-root-volume",
+            "type-of-storage": "persistent-storage:persistent-storage",
+            "size-of-storage": "10",
+            "vdu-storage-requirements": [{"key": "keep-volume", "value": "true"}],
+        }
         expected_persist_root_disk = {
             "persistent-root-volume": {
                 "image_id": "ubuntu20.04",
                 "size": "10",
+                "keep": True,
             }
         }
         expected_disk_list = [
             {
                 "image_id": "ubuntu20.04",
                 "size": "10",
+                "keep": True,
             },
         ]
         persist_root_disk = self.ns.find_persistent_root_volumes(
             vnfd, target_vdu, vdu_instantiation_volumes_list, disk_list
         )
         self.assertEqual(persist_root_disk, expected_persist_root_disk)
+        mock_volume_keeping_required.assert_called_once_with(expected_root_disk)
         self.assertEqual(disk_list, expected_disk_list)
         self.assertEqual(len(disk_list), 1)
 
-    def test_find_persistent_root_volumes_always_selects_first_vsd_as_root(self):
+    @patch("osm_ng_ro.ns.Ns.is_volume_keeping_required")
+    def test_find_persistent_root_volumes_always_selects_first_vsd_as_root(
+        self, mock_volume_keeping_required
+    ):
         """Find persistent root volume, always selects the first vsd as root volume."""
         vnfd = deepcopy(vnfd_wth_persistent_storage)
         vnfd["vdu"][0]["virtual-storage-desc"] = [
@@ -3275,26 +3368,38 @@ class TestProcessVduParams(unittest.TestCase):
         target_vdu = target_vdu_wth_persistent_storage
         vdu_instantiation_volumes_list = []
         disk_list = []
+        mock_volume_keeping_required.return_value = True
+        expected_root_disk = {
+            "id": "persistent-volume2",
+            "type-of-storage": "persistent-storage:persistent-storage",
+            "size-of-storage": "10",
+        }
         expected_persist_root_disk = {
             "persistent-volume2": {
                 "image_id": "ubuntu20.04",
                 "size": "10",
+                "keep": True,
             }
         }
         expected_disk_list = [
             {
                 "image_id": "ubuntu20.04",
                 "size": "10",
+                "keep": True,
             },
         ]
         persist_root_disk = self.ns.find_persistent_root_volumes(
             vnfd, target_vdu, vdu_instantiation_volumes_list, disk_list
         )
         self.assertEqual(persist_root_disk, expected_persist_root_disk)
+        mock_volume_keeping_required.assert_called_once_with(expected_root_disk)
         self.assertEqual(disk_list, expected_disk_list)
         self.assertEqual(len(disk_list), 1)
 
-    def test_find_persistent_root_volumes_empty_size_of_storage(self):
+    @patch("osm_ng_ro.ns.Ns.is_volume_keeping_required")
+    def test_find_persistent_root_volumes_empty_size_of_storage(
+        self, mock_volume_keeping_required
+    ):
         """Find persistent root volume, size of storage is empty."""
         vnfd = deepcopy(vnfd_wth_persistent_storage)
         vnfd["virtual-storage-desc"][0]["size-of-storage"] = ""
@@ -3309,35 +3414,55 @@ class TestProcessVduParams(unittest.TestCase):
         persist_root_disk = self.ns.find_persistent_root_volumes(
             vnfd, target_vdu, vdu_instantiation_volumes_list, disk_list
         )
-        self.assertEqual(persist_root_disk, None)
+        self.assertEqual(persist_root_disk, {})
+        mock_volume_keeping_required.assert_not_called()
         self.assertEqual(disk_list, [])
 
-    def test_find_persistent_root_empty_disk_list(self):
-        """Find persistent root volume, empty disk list."""
+    @patch("osm_ng_ro.ns.Ns.is_volume_keeping_required")
+    def test_find_persistent_root_volumes_keeping_is_not_required(
+        self, mock_volume_keeping_required
+    ):
+        """Find persistent root volume, volume keeping is not required."""
         vnfd = deepcopy(vnfd_wth_persistent_storage)
+        vnfd["virtual-storage-desc"][1]["vdu-storage-requirements"] = [
+            {"key": "keep-volume", "value": "false"},
+        ]
         target_vdu = target_vdu_wth_persistent_storage
         vdu_instantiation_volumes_list = []
         disk_list = []
+        mock_volume_keeping_required.return_value = False
+        expected_root_disk = {
+            "id": "persistent-root-volume",
+            "type-of-storage": "persistent-storage:persistent-storage",
+            "size-of-storage": "10",
+            "vdu-storage-requirements": [{"key": "keep-volume", "value": "false"}],
+        }
         expected_persist_root_disk = {
             "persistent-root-volume": {
                 "image_id": "ubuntu20.04",
                 "size": "10",
+                "keep": False,
             }
         }
         expected_disk_list = [
             {
                 "image_id": "ubuntu20.04",
                 "size": "10",
+                "keep": False,
             },
         ]
         persist_root_disk = self.ns.find_persistent_root_volumes(
             vnfd, target_vdu, vdu_instantiation_volumes_list, disk_list
         )
         self.assertEqual(persist_root_disk, expected_persist_root_disk)
+        mock_volume_keeping_required.assert_called_once_with(expected_root_disk)
         self.assertEqual(disk_list, expected_disk_list)
         self.assertEqual(len(disk_list), 1)
 
-    def test_find_persistent_root_volumes_target_vdu_mismatch(self):
+    @patch("osm_ng_ro.ns.Ns.is_volume_keeping_required")
+    def test_find_persistent_root_volumes_target_vdu_mismatch(
+        self, mock_volume_keeping_required
+    ):
         """Find persistent root volume, target vdu name is not matching."""
         vnfd = deepcopy(vnfd_wth_persistent_storage)
         vnfd["vdu"][0]["name"] = "Several_Volumes-VM"
@@ -3348,10 +3473,14 @@ class TestProcessVduParams(unittest.TestCase):
             vnfd, target_vdu, vdu_instantiation_volumes_list, disk_list
         )
         self.assertEqual(result, None)
+        mock_volume_keeping_required.assert_not_called()
         self.assertEqual(disk_list, [])
         self.assertEqual(len(disk_list), 0)
 
-    def test_find_persistent_root_volumes_with_instantiation_vol_list(self):
+    @patch("osm_ng_ro.ns.Ns.is_volume_keeping_required")
+    def test_find_persistent_root_volumes_with_instantiation_vol_list(
+        self, mock_volume_keeping_required
+    ):
         """Find persistent root volume, existing volume needs to be used."""
         vnfd = deepcopy(vnfd_wth_persistent_storage)
         target_vdu = target_vdu_wth_persistent_storage
@@ -3378,10 +3507,14 @@ class TestProcessVduParams(unittest.TestCase):
             vnfd, target_vdu, vdu_instantiation_volumes_list, disk_list
         )
         self.assertEqual(persist_root_disk, expected_persist_root_disk)
+        mock_volume_keeping_required.assert_not_called()
         self.assertEqual(disk_list, expected_disk_list)
         self.assertEqual(len(disk_list), 1)
 
-    def test_find_persistent_root_volumes_invalid_instantiation_params(self):
+    @patch("osm_ng_ro.ns.Ns.is_volume_keeping_required")
+    def test_find_persistent_root_volumes_invalid_instantiation_params(
+        self, mock_volume_keeping_required
+    ):
         """Find persistent root volume, existing volume id keyword is invalid."""
         vnfd = deepcopy(vnfd_wth_persistent_storage)
         target_vdu = target_vdu_wth_persistent_storage
@@ -3396,50 +3529,64 @@ class TestProcessVduParams(unittest.TestCase):
             self.ns.find_persistent_root_volumes(
                 vnfd, target_vdu, vdu_instantiation_volumes_list, disk_list
             )
-
+        mock_volume_keeping_required.assert_not_called()
         self.assertEqual(disk_list, [])
         self.assertEqual(len(disk_list), 0)
 
+    @patch("osm_ng_ro.ns.Ns.is_volume_keeping_required")
     def test_find_persistent_volumes_vdu_wth_persistent_root_disk_wthout_inst_vol_list(
-        self,
+        self, mock_volume_keeping_required
     ):
         """Find persistent ordinary volume, there is persistent root disk and instatiation volume list is empty."""
         persistent_root_disk = {
             "persistent-root-volume": {
                 "image_id": "ubuntu20.04",
                 "size": "10",
+                "keep": False,
             }
         }
-
+        mock_volume_keeping_required.return_value = False
         target_vdu = target_vdu_wth_persistent_storage
         vdu_instantiation_volumes_list = []
         disk_list = [
             {
                 "image_id": "ubuntu20.04",
                 "size": "10",
+                "keep": False,
             },
         ]
-
+        expected_disk = {
+            "id": "persistent-volume2",
+            "size-of-storage": "10",
+            "type-of-storage": "persistent-storage:persistent-storage",
+        }
         expected_disk_list = [
             {
                 "image_id": "ubuntu20.04",
                 "size": "10",
+                "keep": False,
             },
             {
                 "size": "10",
+                "keep": False,
             },
         ]
         self.ns.find_persistent_volumes(
             persistent_root_disk, target_vdu, vdu_instantiation_volumes_list, disk_list
         )
         self.assertEqual(disk_list, expected_disk_list)
+        mock_volume_keeping_required.assert_called_once_with(expected_disk)
 
-    def test_find_persistent_volumes_vdu_wth_inst_vol_list(self):
+    @patch("osm_ng_ro.ns.Ns.is_volume_keeping_required")
+    def test_find_persistent_volumes_vdu_wth_inst_vol_list(
+        self, mock_volume_keeping_required
+    ):
         """Find persistent ordinary volume, vim-volume-id is given as instantiation parameter."""
         persistent_root_disk = {
             "persistent-root-volume": {
                 "image_id": "ubuntu20.04",
                 "size": "10",
+                "keep": False,
             }
         }
         vdu_instantiation_volumes_list = [
@@ -3453,12 +3600,14 @@ class TestProcessVduParams(unittest.TestCase):
             {
                 "image_id": "ubuntu20.04",
                 "size": "10",
+                "keep": False,
             },
         ]
         expected_disk_list = [
             {
                 "image_id": "ubuntu20.04",
                 "size": "10",
+                "keep": False,
             },
             {
                 "vim_volume_id": vim_volume_id,
@@ -3468,35 +3617,47 @@ class TestProcessVduParams(unittest.TestCase):
             persistent_root_disk, target_vdu, vdu_instantiation_volumes_list, disk_list
         )
         self.assertEqual(disk_list, expected_disk_list)
+        mock_volume_keeping_required.assert_not_called()
 
-    def test_find_persistent_volumes_vdu_wthout_persistent_storage(self):
+    @patch("osm_ng_ro.ns.Ns.is_volume_keeping_required")
+    def test_find_persistent_volumes_vdu_wthout_persistent_storage(
+        self, mock_volume_keeping_required
+    ):
         """Find persistent ordinary volume, there is not any persistent disk."""
         persistent_root_disk = {}
         vdu_instantiation_volumes_list = []
+        mock_volume_keeping_required.return_value = False
         target_vdu = target_vdu_wthout_persistent_storage
         disk_list = []
         self.ns.find_persistent_volumes(
             persistent_root_disk, target_vdu, vdu_instantiation_volumes_list, disk_list
         )
         self.assertEqual(disk_list, disk_list)
+        mock_volume_keeping_required.assert_not_called()
 
+    @patch("osm_ng_ro.ns.Ns.is_volume_keeping_required")
     def test_find_persistent_volumes_vdu_wth_persistent_root_disk_wthout_ordinary_disk(
-        self,
+        self, mock_volume_keeping_required
     ):
         """There is persistent root disk, but there is not ordinary persistent disk."""
         persistent_root_disk = {
             "persistent-root-volume": {
                 "image_id": "ubuntu20.04",
                 "size": "10",
+                "keep": False,
             }
         }
         vdu_instantiation_volumes_list = []
+        mock_volume_keeping_required.return_value = False
         target_vdu = deepcopy(target_vdu_wth_persistent_storage)
         target_vdu["virtual-storages"] = [
             {
                 "id": "persistent-root-volume",
                 "size-of-storage": "10",
                 "type-of-storage": "persistent-storage:persistent-storage",
+                "vdu-storage-requirements": [
+                    {"key": "keep-volume", "value": "true"},
+                ],
             },
             {
                 "id": "ephemeral-volume",
@@ -3508,16 +3669,23 @@ class TestProcessVduParams(unittest.TestCase):
             {
                 "image_id": "ubuntu20.04",
                 "size": "10",
+                "keep": False,
             },
         ]
         self.ns.find_persistent_volumes(
             persistent_root_disk, target_vdu, vdu_instantiation_volumes_list, disk_list
         )
         self.assertEqual(disk_list, disk_list)
+        mock_volume_keeping_required.assert_not_called()
 
-    def test_find_persistent_volumes_wth_inst_vol_list_disk_id_mismatch(self):
+    @patch("osm_ng_ro.ns.Ns.is_volume_keeping_required")
+    def test_find_persistent_volumes_wth_inst_vol_list_disk_id_mismatch(
+        self, mock_volume_keeping_required
+    ):
         """Find persistent ordinary volume, volume id is not persistent_root_disk dict,
-        vim-volume-id is given as instantiation parameter but disk id is not matching."""
+        vim-volume-id is given as instantiation parameter but disk id is not matching.
+        """
+        mock_volume_keeping_required.return_value = True
         vdu_instantiation_volumes_list = [
             {
                 "vim-volume-id": vim_volume_id,
@@ -3528,29 +3696,87 @@ class TestProcessVduParams(unittest.TestCase):
             "persistent-root-volume": {
                 "image_id": "ubuntu20.04",
                 "size": "10",
+                "keep": False,
             }
         }
         disk_list = [
             {
                 "image_id": "ubuntu20.04",
                 "size": "10",
+                "keep": False,
             },
         ]
         expected_disk_list = [
             {
                 "image_id": "ubuntu20.04",
                 "size": "10",
+                "keep": False,
             },
             {
                 "size": "10",
+                "keep": True,
             },
         ]
-
+        expected_disk = {
+            "id": "persistent-volume2",
+            "size-of-storage": "10",
+            "type-of-storage": "persistent-storage:persistent-storage",
+        }
         target_vdu = target_vdu_wth_persistent_storage
         self.ns.find_persistent_volumes(
             persistent_root_disk, target_vdu, vdu_instantiation_volumes_list, disk_list
         )
         self.assertEqual(disk_list, expected_disk_list)
+        mock_volume_keeping_required.assert_called_once_with(expected_disk)
+
+    def test_is_volume_keeping_required_true(self):
+        """Volume keeping is required."""
+        virtual_storage_descriptor = {
+            "id": "persistent-root-volume",
+            "type-of-storage": "persistent-storage:persistent-storage",
+            "size-of-storage": "10",
+            "vdu-storage-requirements": [
+                {"key": "keep-volume", "value": "true"},
+            ],
+        }
+        result = self.ns.is_volume_keeping_required(virtual_storage_descriptor)
+        self.assertEqual(result, True)
+
+    def test_is_volume_keeping_required_false(self):
+        """Volume keeping is not required."""
+        virtual_storage_descriptor = {
+            "id": "persistent-root-volume",
+            "type-of-storage": "persistent-storage:persistent-storage",
+            "size-of-storage": "10",
+            "vdu-storage-requirements": [
+                {"key": "keep-volume", "value": "false"},
+            ],
+        }
+        result = self.ns.is_volume_keeping_required(virtual_storage_descriptor)
+        self.assertEqual(result, False)
+
+    def test_is_volume_keeping_required_wthout_vdu_storage_reqirement(self):
+        """Volume keeping is not required, vdu-storage-requirements key does not exist."""
+        virtual_storage_descriptor = {
+            "id": "persistent-root-volume",
+            "type-of-storage": "persistent-storage:persistent-storage",
+            "size-of-storage": "10",
+        }
+        result = self.ns.is_volume_keeping_required(virtual_storage_descriptor)
+        self.assertEqual(result, False)
+
+    def test_is_volume_keeping_required_wrong_keyword(self):
+        """vdu-storage-requirements key to indicate keeping-volume is wrong."""
+        virtual_storage_descriptor = {
+            "id": "persistent-root-volume",
+            "type-of-storage": "persistent-storage:persistent-storage",
+            "size-of-storage": "10",
+            "vdu-storage-requirements": [
+                {"key": "hold-volume", "value": "true"},
+            ],
+        }
+        result = self.ns.is_volume_keeping_required(virtual_storage_descriptor)
+        self.assertEqual(result, False)
 
     def test_sort_vdu_interfaces_position_all_wth_positions(self):
         """Interfaces are sorted according to position, all have positions."""
@@ -4459,10 +4685,11 @@ class TestProcessVduParams(unittest.TestCase):
         self.assertDictEqual(cloud_config, expected_cloud_config)
 
     @patch("osm_ng_ro.ns.Ns._select_persistent_root_disk")
-    def test_add_persistent_root_disk_to_disk_list(
-        self, mock_select_persistent_root_disk
+    @patch("osm_ng_ro.ns.Ns.is_volume_keeping_required")
+    def test_add_persistent_root_disk_to_disk_list_keep_false(
+        self, mock_volume_keeping_required, mock_select_persistent_root_disk
     ):
-        """Add persistent root disk to disk_list"""
+        """Add persistent root disk to disk_list, keep volume set to False."""
         root_disk = {
             "id": "persistent-root-volume",
             "type-of-storage": "persistent-storage:persistent-storage",
@@ -4474,10 +4701,12 @@ class TestProcessVduParams(unittest.TestCase):
         target_vdu = deepcopy(target_vdu_wth_persistent_storage)
         persistent_root_disk = {}
         disk_list = []
+        mock_volume_keeping_required.return_value = False
         expected_disk_list = [
             {
                 "image_id": "ubuntu20.04",
                 "size": "10",
+                "keep": False,
             }
         ]
         self.ns._add_persistent_root_disk_to_disk_list(
@@ -4485,10 +4714,12 @@ class TestProcessVduParams(unittest.TestCase):
         )
         self.assertEqual(disk_list, expected_disk_list)
         mock_select_persistent_root_disk.assert_called_once()
+        mock_volume_keeping_required.assert_called_once()
 
     @patch("osm_ng_ro.ns.Ns._select_persistent_root_disk")
+    @patch("osm_ng_ro.ns.Ns.is_volume_keeping_required")
     def test_add_persistent_root_disk_to_disk_list_select_persistent_root_disk_raises(
-        self, mock_select_persistent_root_disk
+        self, mock_volume_keeping_required, mock_select_persistent_root_disk
     ):
         """Add persistent root disk to disk_list"""
         root_disk = {
@@ -4508,35 +4739,93 @@ class TestProcessVduParams(unittest.TestCase):
             )
         self.assertEqual(disk_list, [])
         mock_select_persistent_root_disk.assert_called_once()
+        mock_volume_keeping_required.assert_not_called()
+
+    @patch("osm_ng_ro.ns.Ns._select_persistent_root_disk")
+    @patch("osm_ng_ro.ns.Ns.is_volume_keeping_required")
+    def test_add_persistent_root_disk_to_disk_list_keep_true(
+        self, mock_volume_keeping_required, mock_select_persistent_root_disk
+    ):
+        """Add persistent root disk, keeo volume set to True."""
+        vnfd = deepcopy(vnfd_wth_persistent_storage)
+        target_vdu = deepcopy(target_vdu_wth_persistent_storage)
+        mock_volume_keeping_required.return_value = True
+        root_disk = {
+            "id": "persistent-root-volume",
+            "type-of-storage": "persistent-storage:persistent-storage",
+            "size-of-storage": "10",
+            "vdu-storage-requirements": [
+                {"key": "keep-volume", "value": "true"},
+            ],
+        }
+        mock_select_persistent_root_disk.return_value = root_disk
+        persistent_root_disk = {}
+        disk_list = []
+        expected_disk_list = [
+            {
+                "image_id": "ubuntu20.04",
+                "size": "10",
+                "keep": True,
+            }
+        ]
+        self.ns._add_persistent_root_disk_to_disk_list(
+            vnfd, target_vdu, persistent_root_disk, disk_list
+        )
+        self.assertEqual(disk_list, expected_disk_list)
+        mock_volume_keeping_required.assert_called_once_with(root_disk)
 
-    def test_add_persistent_ordinary_disk_to_disk_list(self):
-        """Add persistent ordinary disk to disk_list"""
+    @patch("osm_ng_ro.ns.Ns.is_volume_keeping_required")
+    def test_add_persistent_ordinary_disk_to_disk_list(
+        self, mock_volume_keeping_required
+    ):
+        """Add persistent ordinary disk, keeo volume set to True."""
         target_vdu = deepcopy(target_vdu_wth_persistent_storage)
+        mock_volume_keeping_required.return_value = False
         persistent_root_disk = {
             "persistent-root-volume": {
                 "image_id": "ubuntu20.04",
                 "size": "10",
+                "keep": True,
             }
         }
+        ordinary_disk = {
+            "id": "persistent-volume2",
+            "type-of-storage": "persistent-storage:persistent-storage",
+            "size-of-storage": "10",
+        }
         persistent_ordinary_disk = {}
         disk_list = []
+        extra_dict = {}
         expected_disk_list = [
             {
                 "size": "10",
+                "keep": False,
+                "multiattach": False,
+                "name": "persistent-volume2",
             }
         ]
         self.ns._add_persistent_ordinary_disks_to_disk_list(
-            target_vdu, persistent_root_disk, persistent_ordinary_disk, disk_list
+            target_vdu,
+            persistent_root_disk,
+            persistent_ordinary_disk,
+            disk_list,
+            extra_dict,
         )
         self.assertEqual(disk_list, expected_disk_list)
+        mock_volume_keeping_required.assert_called_once_with(ordinary_disk)
 
-    def test_add_persistent_ordinary_disk_to_disk_list_vsd_id_in_root_disk_dict(self):
+    @patch("osm_ng_ro.ns.Ns.is_volume_keeping_required")
+    def test_add_persistent_ordinary_disk_to_disk_list_vsd_id_in_root_disk_dict(
+        self, mock_volume_keeping_required
+    ):
         """Add persistent ordinary disk, vsd id is in root_disk dict."""
         target_vdu = deepcopy(target_vdu_wth_persistent_storage)
+        mock_volume_keeping_required.return_value = False
         persistent_root_disk = {
             "persistent-root-volume": {
                 "image_id": "ubuntu20.04",
                 "size": "10",
+                "keep": True,
             },
             "persistent-volume2": {
                 "size": "10",
@@ -4544,15 +4833,22 @@ class TestProcessVduParams(unittest.TestCase):
         }
         persistent_ordinary_disk = {}
         disk_list = []
+        extra_dict = {}
 
         self.ns._add_persistent_ordinary_disks_to_disk_list(
-            target_vdu, persistent_root_disk, persistent_ordinary_disk, disk_list
+            target_vdu,
+            persistent_root_disk,
+            persistent_ordinary_disk,
+            disk_list,
+            extra_dict,
         )
         self.assertEqual(disk_list, [])
+        mock_volume_keeping_required.assert_not_called()
 
     @patch("osm_ng_ro.ns.Ns._select_persistent_root_disk")
+    @patch("osm_ng_ro.ns.Ns.is_volume_keeping_required")
     def test_add_persistent_root_disk_to_disk_list_vnfd_wthout_persistent_storage(
-        self, mock_select_persistent_root_disk
+        self, mock_volume_keeping_required, mock_select_persistent_root_disk
     ):
         """VNFD does not have persistent storage."""
         vnfd = deepcopy(vnfd_wthout_persistent_storage)
@@ -4565,10 +4861,12 @@ class TestProcessVduParams(unittest.TestCase):
         )
         self.assertEqual(disk_list, [])
         self.assertEqual(mock_select_persistent_root_disk.call_count, 2)
+        mock_volume_keeping_required.assert_not_called()
 
     @patch("osm_ng_ro.ns.Ns._select_persistent_root_disk")
+    @patch("osm_ng_ro.ns.Ns.is_volume_keeping_required")
     def test_add_persistent_root_disk_to_disk_list_wthout_persistent_root_disk(
-        self, mock_select_persistent_root_disk
+        self, mock_volume_keeping_required, mock_select_persistent_root_disk
     ):
         """Persistent_root_disk dict is empty."""
         vnfd = deepcopy(vnfd_wthout_persistent_storage)
@@ -4581,6 +4879,7 @@ class TestProcessVduParams(unittest.TestCase):
         )
         self.assertEqual(disk_list, [])
         self.assertEqual(mock_select_persistent_root_disk.call_count, 2)
+        mock_volume_keeping_required.assert_not_called()
 
     def test_prepare_vdu_affinity_group_list_invalid_extra_dict(self):
         """Invalid extra dict."""
@@ -4979,6 +5278,7 @@ class TestProcessVduParams(unittest.TestCase):
             "persistent-root-volume": {
                 "image_id": "ubuntu20.04",
                 "size": "10",
+                "keep": True,
             }
         }
         mock_find_persistent_root_volumes.return_value = persistent_root_disk
@@ -5053,6 +5353,7 @@ class TestProcessVduParams(unittest.TestCase):
             "persistent-root-volume": {
                 "image_id": "ubuntu20.04",
                 "size": "10",
+                "keep": True,
             }
         }
         mock_find_persistent_root_volumes.return_value = persistent_root_disk
@@ -5126,6 +5427,7 @@ class TestProcessVduParams(unittest.TestCase):
             "persistent-root-volume": {
                 "image_id": "ubuntu20.04",
                 "size": "10",
+                "keep": True,
             }
         }
         mock_find_persistent_root_volumes.return_value = persistent_root_disk
@@ -5298,3 +5600,234 @@ class TestProcessVduParams(unittest.TestCase):
         vsd = deepcopy(vnfd_wth_persistent_storage)["virtual-storage-desc"]
         with self.assertRaises(AttributeError):
             Ns._select_persistent_root_disk(vsd, vdu)
+
+
+class TestSFC(unittest.TestCase):
+    def setUp(self):
+        self.ns = Ns()
+        self.logger = CopyingMock(autospec=True)
+
+    @patch("osm_ng_ro.ns.Ns._prefix_ip_address")
+    @patch("osm_ng_ro.ns.Ns._process_ip_proto")
+    @patch("osm_ng_ro.ns.Ns._get_vnfr_vdur_text")
+    def test_process_classification_params(
+        self, mock_get_vnfr_vdur_text, mock_process_ip_proto, mock_prefix_ip_address
+    ):
+        db = Mock()
+        mock_prefix_ip_address.side_effect = ["10.10.10.10/32", "20.20.20.20/32"]
+        mock_process_ip_proto.return_value = "tcp"
+        mock_get_vnfr_vdur_text.return_value = "vdur_text"
+        vim_info, indata, target_record_id = {}, {}, ""
+        target_classification = {
+            "vnfr_id": "1234",
+            "source-ip-address": "10.10.10.10",
+            "destination-ip-address": "20.20.20.20",
+            "ip-proto": "6",
+            "id": "rule1",
+            "source-port": "0",
+            "destination-port": 5555,
+            "vdur_id": "5678",
+            "ingress_port_index": 0,
+            "vim_info": vim_info,
+        }
+        kwargs = {"db": db}
+
+        expected_result = {
+            "depends_on": ["vdur_text"],
+            "params": {
+                "destination_ip_prefix": "20.20.20.20/32",
+                "destination_port_range_max": 5555,
+                "destination_port_range_min": 5555,
+                "logical_source_port": "TASK-vdur_text",
+                "logical_source_port_index": 0,
+                "name": "rule1",
+                "protocol": "tcp",
+                "source_ip_prefix": "10.10.10.10/32",
+                "source_port_range_max": "0",
+                "source_port_range_min": "0",
+            },
+        }
+
+        result = self.ns._process_classification_params(
+            target_classification, indata, vim_info, target_record_id, **kwargs
+        )
+        self.assertEqual(expected_result, result)
+
+    def test_process_sfp_params(self):
+        sf_text = "nsrs:1234:sf.sf1"
+        classi_text = "nsrs:1234:classification.rule1"
+        vim_info, indata, target_record_id = {}, {}, ""
+        target_sfp = {
+            "id": "sfp1",
+            "sfs": ["sf1"],
+            "classifications": ["rule1"],
+            "vim_info": vim_info,
+        }
+
+        kwargs = {"nsr_id": "1234"}
+
+        expected_result = {
+            "depends_on": [sf_text, classi_text],
+            "params": {
+                "name": "sfp1",
+                "sfs": ["TASK-" + sf_text],
+                "classifications": ["TASK-" + classi_text],
+            },
+        }
+
+        result = self.ns._process_sfp_params(
+            target_sfp, indata, vim_info, target_record_id, **kwargs
+        )
+        self.assertEqual(expected_result, result)
+
+    def test_process_sf_params(self):
+        sfi_text = "nsrs::sfi.sfi1"
+        vim_info, indata, target_record_id = {}, {}, ""
+        target_sf = {"id": "sf1", "sfis": ["sfi1"], "vim_info": vim_info}
+
+        kwargs = {"ns_id": "1234"}
+
+        expected_result = {
+            "depends_on": [sfi_text],
+            "params": {
+                "name": "sf1",
+                "sfis": ["TASK-" + sfi_text],
+            },
+        }
+
+        result = self.ns._process_sf_params(
+            target_sf, indata, vim_info, target_record_id, **kwargs
+        )
+        self.assertEqual(expected_result, result)
+
+    @patch("osm_ng_ro.ns.Ns._get_vnfr_vdur_text")
+    def test_process_sfi_params(self, mock_get_vnfr_vdur_text):
+        db = Mock()
+        mock_get_vnfr_vdur_text.return_value = "vdur_text"
+        vim_info, indata, target_record_id = {}, {}, ""
+        target_sfi = {
+            "id": "sfi1",
+            "ingress_port": "vnf-cp0-ext",
+            "egress_port": "vnf-cp0-ext",
+            "vnfr_id": "1234",
+            "vdur_id": "5678",
+            "ingress_port_index": 0,
+            "egress_port_index": 0,
+            "vim_info": {},
+        }
+        kwargs = {"db": db}
+
+        expected_result = {
+            "depends_on": ["vdur_text"],
+            "params": {
+                "name": "sfi1",
+                "ingress_port": "TASK-vdur_text",
+                "egress_port": "TASK-vdur_text",
+                "ingress_port_index": 0,
+                "egress_port_index": 0,
+            },
+        }
+
+        result = self.ns._process_sfi_params(
+            target_sfi, indata, vim_info, target_record_id, **kwargs
+        )
+        self.assertEqual(expected_result, result)
+
+    def test_process_vnfgd_sfp(self):
+        sfp = {
+            "id": "sfp1",
+            "position-desc-id": [
+                {
+                    "id": "position1",
+                    "cp-profile-id": [{"id": "sf1"}],
+                    "match-attributes": [{"id": "rule1"}],
+                }
+            ],
+        }
+        expected_result = {"id": "sfp1", "sfs": ["sf1"], "classifications": ["rule1"]}
+
+        result = self.ns._process_vnfgd_sfp(sfp)
+        self.assertEqual(expected_result, result)
+
+    def test_process_vnfgd_sf(self):
+        sf = {"id": "sf1", "constituent-profile-elements": [{"id": "sfi1", "order": 0}]}
+        expected_result = {"id": "sf1", "sfis": ["sfi1"]}
+
+        result = self.ns._process_vnfgd_sf(sf)
+        self.assertEqual(expected_result, result)
+
+    def test_process_vnfgd_sfi(self):
+        sfi = {
+            "id": "sfi1",
+            "constituent-base-element-id": "vnf",
+            "order": 0,
+            "ingress-constituent-cpd-id": "vnf-cp0-ext",
+            "egress-constituent-cpd-id": "vnf-cp0-ext",
+        }
+        db_vnfrs = {
+            "1234": {
+                "id": "1234",
+                "member-vnf-index-ref": "vnf",
+                "connection-point": [
+                    {
+                        "name": "vnf-cp0-ext",
+                        "connection-point-id": "vdu-eth0-int",
+                        "connection-point-vdu-id": "5678",
+                        "id": "vnf-cp0-ext",
+                    }
+                ],
+            }
+        }
+        expected_result = {
+            "id": "sfi1",
+            "ingress_port": "vnf-cp0-ext",
+            "egress_port": "vnf-cp0-ext",
+            "vnfr_id": "1234",
+            "vdur_id": "5678",
+            "ingress_port_index": 0,
+            "egress_port_index": 0,
+        }
+
+        result = self.ns._process_vnfgd_sfi(sfi, db_vnfrs)
+        self.assertEqual(expected_result, result)
+
+    def test_process_vnfgd_classification(self):
+        classification = {
+            "id": "rule1",
+            "ip-proto": 6,
+            "source-ip-address": "10.10.10.10",
+            "destination-ip-address": "20.20.20.20",
+            "constituent-base-element-id": "vnf",
+            "constituent-cpd-id": "vnf-cp0-ext",
+            "destination-port": 5555,
+        }
+        db_vnfrs = {
+            "1234": {
+                "id": "1234",
+                "member-vnf-index-ref": "vnf",
+                "connection-point": [
+                    {
+                        "name": "vnf-cp0-ext",
+                        "connection-point-id": "vdu-eth0-int",
+                        "connection-point-vdu-id": "5678",
+                        "id": "vnf-cp0-ext",
+                    }
+                ],
+            }
+        }
+
+        expected_result = {
+            "id": "rule1",
+            "ip-proto": 6,
+            "source-ip-address": "10.10.10.10",
+            "destination-ip-address": "20.20.20.20",
+            "destination-port": 5555,
+            "vnfr_id": "1234",
+            "vdur_id": "5678",
+            "ingress_port_index": 0,
+            "constituent-base-element-id": "vnf",
+            "constituent-cpd-id": "vnf-cp0-ext",
+        }
+
+        result = self.ns._process_vnfgd_classification(classification, db_vnfrs)
+        self.assertEqual(expected_result, result)