diff --git a/releasenotes/notes/support-k8s-namespace-9e861c87e4aa1aaa.yaml b/releasenotes/notes/support-k8s-namespace-9e861c87e4aa1aaa.yaml new file mode 100644 index 000000000..bbe41e846 --- /dev/null +++ b/releasenotes/notes/support-k8s-namespace-9e861c87e4aa1aaa.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + The user specifies the target namespace in the InstantiateVnfRequest to + deploy the CNF on the Kubernetes VIM. The additionalParams field provides + the new parameter ``namespace`` for the target namespace. The Kubernetes + resources in the VNF must be in the same namespace. diff --git a/tacker/common/exceptions.py b/tacker/common/exceptions.py index 19ad46f6e..ff65ca951 100644 --- a/tacker/common/exceptions.py +++ b/tacker/common/exceptions.py @@ -431,3 +431,8 @@ class VnfConflictStateWithErrorPoint(Conflict): class InvalidIpAddr(TackerException): message = _('Invalid ip address value in resource %(id)s.') + + +class NamespaceIsNotUnique(TackerException): + message = _('There are multiple namespaces in the manifest files. ' + 'Only one namespace can be used in one VNF.') diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/Definitions/helloworld3_df_simple.yaml b/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/Definitions/helloworld3_df_simple.yaml new file mode 100644 index 000000000..c21f44fc9 --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/Definitions/helloworld3_df_simple.yaml @@ -0,0 +1,150 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: Sample VNF + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + - helloworld3_types.yaml + +topology_template: + inputs: + descriptor_id: + type: string + descriptor_version: + type: string + provider: + type: string + product_name: + type: string + software_version: + type: string + vnfm_info: + type: list + entry_schema: + type: string + flavour_id: + type: string + flavour_description: + type: string + + substitution_mappings: + node_type: company.provider.VNF + properties: + flavour_id: simple + requirements: + virtual_link_external: [] + + node_templates: + VNF: + type: company.provider.VNF + properties: + flavour_description: A simple flavour + + VDU1: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: vdu1 + description: kubernetes controller resource as VDU + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 3 + + VDU2: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: vdu2 + description: kubernetes controller resource as VDU + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 3 + + policies: + - scaling_aspects: + type: tosca.policies.nfv.ScalingAspects + properties: + aspects: + vdu1_aspect: + name: vdu1_aspect + description: vdu1 scaling aspect + max_scale_level: 2 + step_deltas: + - delta_1 + vdu2_aspect: + name: vdu2_aspect + description: vdu2 scaling aspect + max_scale_level: 2 + step_deltas: + - delta_1 + + - instantiation_levels: + type: tosca.policies.nfv.InstantiationLevels + properties: + levels: + instantiation_level_1: + description: Smallest size + scale_info: + vdu1_aspect: + scale_level: 0 + vdu2_aspect: + scale_level: 0 + instantiation_level_2: + description: Largest size + scale_info: + vdu1_aspect: + scale_level: 2 + vdu2_aspect: + scale_level: 2 + default_level: instantiation_level_1 + + - vdu1_initial_delta: + type: tosca.policies.nfv.VduInitialDelta + properties: + initial_delta: + number_of_instances: 1 + targets: [ VDU1 ] + + - vdu1_scaling_aspect_deltas: + type: tosca.policies.nfv.VduScalingAspectDeltas + properties: + aspect: vdu1_aspect + deltas: + delta_1: + number_of_instances: 1 + targets: [ VDU1 ] + + - vdu1_instantiation_levels: + type: tosca.policies.nfv.VduInstantiationLevels + properties: + levels: + instantiation_level_1: + number_of_instances: 1 + instantiation_level_2: + number_of_instances: 3 + targets: [ VDU1 ] + + - vdu2_initial_delta: + type: tosca.policies.nfv.VduInitialDelta + properties: + initial_delta: + number_of_instances: 1 + targets: [ VDU2 ] + + - vdu2_scaling_aspect_deltas: + type: tosca.policies.nfv.VduScalingAspectDeltas + properties: + aspect: vdu2_aspect + deltas: + delta_1: + number_of_instances: 1 + targets: [ VDU2 ] + + - vdu2_instantiation_levels: + type: tosca.policies.nfv.VduInstantiationLevels + properties: + levels: + instantiation_level_1: + number_of_instances: 1 + instantiation_level_2: + number_of_instances: 3 + targets: [ VDU2 ] \ No newline at end of file diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/Definitions/helloworld3_top.vnfd.yaml b/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/Definitions/helloworld3_top.vnfd.yaml new file mode 100644 index 000000000..bbb9ac5da --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/Definitions/helloworld3_top.vnfd.yaml @@ -0,0 +1,31 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: Sample VNF + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + - helloworld3_types.yaml + - helloworld3_df_simple.yaml + +topology_template: + inputs: + selected_flavour: + type: string + description: VNF deployment flavour selected by the consumer. It is provided in the API + + node_templates: + VNF: + type: company.provider.VNF + properties: + flavour_id: { get_input: selected_flavour } + descriptor_id: b1bb0ce7-ebca-4fa7-95ed-4840d70a8993 + provider: Company + product_name: Sample VNF + software_version: '1.0' + descriptor_version: '1.0' + vnfm_info: + - Tacker + requirements: + #- virtual_link_external # mapped in lower-level templates + #- virtual_link_internal # mapped in lower-level templates diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/Definitions/helloworld3_types.yaml b/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/Definitions/helloworld3_types.yaml new file mode 100644 index 000000000..bd93b4004 --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/Definitions/helloworld3_types.yaml @@ -0,0 +1,53 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: VNF type definition + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + +node_types: + company.provider.VNF: + derived_from: tosca.nodes.nfv.VNF + properties: + descriptor_id: + type: string + constraints: [ valid_values: [ b1bb0ce7-ebca-4fa7-95ed-4840d70a8993 ] ] + default: b1bb0ce7-ebca-4fa7-95ed-4840d70a8993 + descriptor_version: + type: string + constraints: [ valid_values: [ '1.0' ] ] + default: '1.0' + provider: + type: string + constraints: [ valid_values: [ 'Company' ] ] + default: 'Company' + product_name: + type: string + constraints: [ valid_values: [ 'Sample VNF' ] ] + default: 'Sample VNF' + software_version: + type: string + constraints: [ valid_values: [ '1.0' ] ] + default: '1.0' + vnfm_info: + type: list + entry_schema: + type: string + constraints: [ valid_values: [ Tacker ] ] + default: [ Tacker ] + flavour_id: + type: string + constraints: [ valid_values: [ simple ] ] + default: simple + flavour_description: + type: string + default: "" + requirements: + - virtual_link_external: + capability: tosca.capabilities.nfv.VirtualLinkable + - virtual_link_internal: + capability: tosca.capabilities.nfv.VirtualLinkable + interfaces: + Vnflcm: + type: tosca.interfaces.nfv.Vnflcm diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/Files/kubernetes/deployment_has_namespace.yaml b/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/Files/kubernetes/deployment_has_namespace.yaml new file mode 100644 index 000000000..da3455440 --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/Files/kubernetes/deployment_has_namespace.yaml @@ -0,0 +1,22 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: vdu1 + namespace: multi-namespace02 +spec: + replicas: 1 + selector: + matchLabels: + app: webserver + template: + metadata: + labels: + app: webserver + spec: + containers: + - name: nginx + image: nginx + imagePullPolicy: IfNotPresent + ports: + - containerPort: 80 + protocol: TCP \ No newline at end of file diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/Files/kubernetes/deployment_no_namespace.yaml b/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/Files/kubernetes/deployment_no_namespace.yaml new file mode 100644 index 000000000..79b2a4c3f --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/Files/kubernetes/deployment_no_namespace.yaml @@ -0,0 +1,21 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: vdu2 +spec: + replicas: 1 + selector: + matchLabels: + app: webserver + template: + metadata: + labels: + app: webserver + spec: + containers: + - name: nginx + image: nginx + imagePullPolicy: IfNotPresent + ports: + - containerPort: 80 + protocol: TCP \ No newline at end of file diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/Files/kubernetes/namespace01.yaml b/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/Files/kubernetes/namespace01.yaml new file mode 100644 index 000000000..4d7e052ba --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/Files/kubernetes/namespace01.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: multi-namespace01 \ No newline at end of file diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/Files/kubernetes/namespace02.yaml b/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/Files/kubernetes/namespace02.yaml new file mode 100644 index 000000000..18185ee1b --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/Files/kubernetes/namespace02.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: multi-namespace02 \ No newline at end of file diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/TOSCA-Metadata/TOSCA.meta b/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/TOSCA-Metadata/TOSCA.meta new file mode 100644 index 000000000..725843a6d --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_multi_ns/TOSCA-Metadata/TOSCA.meta @@ -0,0 +1,24 @@ +TOSCA-Meta-File-Version: 1.0 +Created-by: dummy_user +CSAR-Version: 1.1 +Entry-Definitions: Definitions/helloworld3_top.vnfd.yaml + +Name: Files/kubernetes/deployment_has_namespace.yaml +Content-Type: application/yaml +Algorithm: SHA-256 +Hash: c33b1ec0793619e4752fb0bca2c5c20c9ae2e1717ade94e7d4466efc80a7c6f4 + +Name: Files/kubernetes/deployment_no_namespace.yaml +Content-Type: application/yaml +Algorithm: SHA-256 +Hash: 064c5f54722d74dd7faae6a3f83a504eed579135b366b1251e6d2f024951a7a0 + +Name: Files/kubernetes/namespace01.yaml +Content-Type: application/yaml +Algorithm: SHA-256 +Hash: 6cee66e9786c158edae7da6b1c4639246070cb6ccbfcfbe7f5cec4184552b07d + +Name: Files/kubernetes/namespace02.yaml +Content-Type: application/yaml +Algorithm: SHA-256 +Hash: 04a7db97412b8d88fe6390c34489ac8e963c70d828c11737592723a7fbd30d8c \ No newline at end of file diff --git a/tacker/tests/functional/sol_kubernetes/vnflcm/test_kubernetes_multi_ns.py b/tacker/tests/functional/sol_kubernetes/vnflcm/test_kubernetes_multi_ns.py new file mode 100644 index 000000000..ea73d30ad --- /dev/null +++ b/tacker/tests/functional/sol_kubernetes/vnflcm/test_kubernetes_multi_ns.py @@ -0,0 +1,146 @@ +# All Rights Reserved. +# +# 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. + +from tacker.tests.functional.sol_kubernetes.vnflcm import base as vnflcm_base + + +class VnfLcmKubernetesMultiNsTest(vnflcm_base.BaseVnfLcmKubernetesTest): + + @classmethod + def setUpClass(cls): + super(VnfLcmKubernetesMultiNsTest, cls).setUpClass() + vnf_package_id, cls.vnfd_id = cls._create_and_upload_vnf_package( + cls, cls.tacker_client, "test_cnf_multi_ns", + {"key": "sample_multi_ns_functional"}) + cls.vnf_package_ids.append(vnf_package_id) + + @classmethod + def tearDownClass(cls): + super(VnfLcmKubernetesMultiNsTest, cls).tearDownClass() + + def _test_cnf_scale(self, vnf_instance, aspect_id, + number_of_steps=1, error=False): + scale_level = self._get_scale_level_by_aspect_id( + vnf_instance, aspect_id) + + # test scale out + scale_level = self._test_scale( + vnf_instance['id'], 'SCALE_OUT', aspect_id, scale_level, + number_of_steps, error) + if error: + return scale_level + + # test scale in + scale_level = self._test_scale( + vnf_instance['id'], 'SCALE_IN', aspect_id, scale_level, + number_of_steps) + + return scale_level + + def test_multi_tenant_k8s_additional_params(self): + vnf_instance_name = "multi_tenant_k8s_additional_params" + vnf_instance_description = "multi tenant k8s additional params" + files = ["Files/kubernetes/deployment_has_namespace.yaml", + "Files/kubernetes/namespace01.yaml"] + additional_param = { + "lcm-kubernetes-def-files": files, + "namespace": "multi-namespace01"} + # instantiate + vnf_instance = self._create_and_instantiate_vnf_instance( + self.vnfd_id, "simple", vnf_instance_name, + vnf_instance_description, additional_param) + # scale + self._test_cnf_scale(vnf_instance, "vdu1_aspect", number_of_steps=1) + + before_vnfc_rscs = self._get_vnfc_resource_info(vnf_instance) + deployment_target_vnfc = None + for vnfc_rsc in before_vnfc_rscs: + if vnfc_rsc['vduId'] == 'VDU1': + deployment_target_vnfc = vnfc_rsc + vnfc_instance_id = [deployment_target_vnfc['id']] + # heal + after_vnfc_rscs = self._test_heal(vnf_instance, vnfc_instance_id) + for vnfc_rsc in after_vnfc_rscs: + after_pod_name = vnfc_rsc['computeResource']['resourceId'] + if vnfc_rsc['id'] == deployment_target_vnfc['id']: + after_resource = deployment_target_vnfc + compute_resource = after_resource['computeResource'] + before_pod_name = compute_resource['resourceId'] + self.assertNotEqual(after_pod_name, before_pod_name) + # terminate + self._terminate_vnf_instance(vnf_instance['id']) + self._delete_vnf_instance(vnf_instance['id']) + + def test_multi_tenant_k8s_manifest(self): + vnf_instance_name = "multi_tenant_k8s_manifest" + vnf_instance_description = "multi tenant k8s manifest" + files = ["Files/kubernetes/deployment_has_namespace.yaml", + "Files/kubernetes/namespace02.yaml"] + additional_param = {"lcm-kubernetes-def-files": files} + # instantiate + vnf_instance = self._create_and_instantiate_vnf_instance( + self.vnfd_id, "simple", vnf_instance_name, + vnf_instance_description, additional_param) + # scale + self._test_cnf_scale(vnf_instance, "vdu1_aspect", number_of_steps=1) + + before_vnfc_rscs = self._get_vnfc_resource_info(vnf_instance) + deployment_target_vnfc = None + for vnfc_rsc in before_vnfc_rscs: + if vnfc_rsc['vduId'] == 'VDU1': + deployment_target_vnfc = vnfc_rsc + vnfc_instance_id = [deployment_target_vnfc['id']] + # heal + after_vnfc_rscs = self._test_heal(vnf_instance, vnfc_instance_id) + for vnfc_rsc in after_vnfc_rscs: + after_pod_name = vnfc_rsc['computeResource']['resourceId'] + if vnfc_rsc['id'] == deployment_target_vnfc['id']: + after_resource = deployment_target_vnfc + compute_resource = after_resource['computeResource'] + before_pod_name = compute_resource['resourceId'] + self.assertNotEqual(after_pod_name, before_pod_name) + # terminate + self._terminate_vnf_instance(vnf_instance['id']) + self._delete_vnf_instance(vnf_instance['id']) + + def test_multi_tenant_k8s_default(self): + vnf_instance_name = "multi_tenant_k8s_default" + vnf_instance_description = "multi tenant k8s default" + files = ["Files/kubernetes/deployment_no_namespace.yaml"] + additional_param = {"lcm-kubernetes-def-files": files} + # instantiate + vnf_instance = self._create_and_instantiate_vnf_instance( + self.vnfd_id, "simple", vnf_instance_name, + vnf_instance_description, additional_param) + # scale + self._test_cnf_scale(vnf_instance, "vdu2_aspect", number_of_steps=1) + + before_vnfc_rscs = self._get_vnfc_resource_info(vnf_instance) + deployment_target_vnfc = None + for vnfc_rsc in before_vnfc_rscs: + if vnfc_rsc['vduId'] == 'VDU2': + deployment_target_vnfc = vnfc_rsc + vnfc_instance_id = [deployment_target_vnfc['id']] + # heal + after_vnfc_rscs = self._test_heal(vnf_instance, vnfc_instance_id) + for vnfc_rsc in after_vnfc_rscs: + after_pod_name = vnfc_rsc['computeResource']['resourceId'] + if vnfc_rsc['id'] == deployment_target_vnfc['id']: + after_resource = deployment_target_vnfc + compute_resource = after_resource['computeResource'] + before_pod_name = compute_resource['resourceId'] + self.assertNotEqual(after_pod_name, before_pod_name) + # terminate + self._terminate_vnf_instance(vnf_instance['id']) + self._delete_vnf_instance(vnf_instance['id']) diff --git a/tacker/tests/unit/vnfm/infra_drivers/kubernetes/fakes.py b/tacker/tests/unit/vnfm/infra_drivers/kubernetes/fakes.py index da1c38f61..e7ace17c3 100644 --- a/tacker/tests/unit/vnfm/infra_drivers/kubernetes/fakes.py +++ b/tacker/tests/unit/vnfm/infra_drivers/kubernetes/fakes.py @@ -1048,10 +1048,8 @@ def get_scale_policy(type, aspect_id='vdu1', delta_num=1, is_legacy=False): def get_vnf_resource_list(kind, name='fake_name'): vnf_resource = models.VnfResource() vnf_resource.vnf_instance_id = uuidsentinel.vnf_instance_id - vnf_resource.resource_name = \ - _("fake_namespace,{name}").format(name=name) - vnf_resource.resource_type = \ - _("v1,{kind}").format(kind=kind) + vnf_resource.resource_name = name + vnf_resource.resource_type = f"v1,{kind}" return [vnf_resource] diff --git a/tacker/tests/unit/vnfm/infra_drivers/kubernetes/test_kubernetes_driver.py b/tacker/tests/unit/vnfm/infra_drivers/kubernetes/test_kubernetes_driver.py index 48e688b74..1b229b503 100644 --- a/tacker/tests/unit/vnfm/infra_drivers/kubernetes/test_kubernetes_driver.py +++ b/tacker/tests/unit/vnfm/infra_drivers/kubernetes/test_kubernetes_driver.py @@ -594,7 +594,7 @@ class TestKubernetes(base.TestCase): mock_vnf_by_id.return_value = fake_vnf_get_by_id vnf_resource = vnf_resource_obj.VnfResource(context=self.context) vnf_resource.vnf_instance_id = vnf_instance.id - vnf_resource.resource_name = "curry-ns,curry-endpoint-test001" + vnf_resource.resource_name = "curry-endpoint-test001" vnf_resource.resource_type = "v1,Pod" vnf_resource.resource_identifier = '' vnf_resource.resource_status = '' @@ -647,9 +647,11 @@ class TestKubernetes(base.TestCase): vnf_software_images, instantiate_vnf_req, vnf_package_path) + @mock.patch('tacker.objects.vnf_instance.VnfInstance.save') @mock.patch.object(vnf_package.VnfPackage, "get_by_id") @mock.patch.object(vnf_package_vnfd.VnfPackageVnfd, "get_by_id") - def test_pre_instantiation_vnf(self, mock_vnfd_by_id, mock_vnf_by_id): + def test_pre_instantiation_vnf( + self, mock_vnfd_by_id, mock_vnf_by_id, mock_save): vnf_instance = fd_utils.get_vnf_instance_object() vim_connection_info = None vnf_software_images = None @@ -686,8 +688,7 @@ class TestKubernetes(base.TestCase): vnf_software_images, instantiate_vnf_req, vnf_package_path) for item in new_k8s_objs.values(): - self.assertEqual(item[0].resource_name, 'curry-ns,' - 'curry-endpoint-test001') + self.assertEqual(item[0].resource_name, 'curry-endpoint-test001') self.assertEqual(item[0].resource_type, 'v1,Pod') def _delete_single_vnf_resource(self, mock_vnf_resource_list, @@ -696,6 +697,7 @@ class TestKubernetes(base.TestCase): vnf_id = 'fake_vnf_id' vnf_instance = fd_utils.get_vnf_instance_object() vnf_instance_id = vnf_instance.id + vnf_instance.vnf_metadata['namespace'] = "default" vnf_resource = models.VnfResource() vnf_resource.vnf_instance_id = vnf_instance_id vnf_resource.resource_name = resource_name @@ -714,7 +716,7 @@ class TestKubernetes(base.TestCase): terminate_vnf_req = objects.TerminateVnfRequest( termination_type=fields.VnfInstanceTerminationType.GRACEFUL, graceful_termination_timeout=5) - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "v1,Pod" mock_delete_namespaced_pod.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -730,7 +732,7 @@ class TestKubernetes(base.TestCase): mock_delete_namespaced_pod): terminate_vnf_req = objects.TerminateVnfRequest( termination_type=fields.VnfInstanceTerminationType.FORCEFUL) - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "v1,Pod" mock_delete_namespaced_pod.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -744,7 +746,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_pod_terminate_vnfreq_none(self, mock_vnf_resource_list, mock_delete_namespaced_pod): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "v1,Pod" mock_delete_namespaced_pod.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -758,7 +760,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_service(self, mock_vnf_resource_list, mock_delete_namespaced_service): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "v1,Service" mock_delete_namespaced_service.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -772,7 +774,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_secret(self, mock_vnf_resource_list, mock_delete_namespaced_secret): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "v1,Secret" mock_delete_namespaced_secret.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -786,7 +788,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_config_map(self, mock_vnf_resource_list, mock_delete_namespaced_config_map): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "v1,ConfigMap" mock_delete_namespaced_config_map.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -801,7 +803,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_persistent_volume_claim(self, mock_vnf_resource_list, mock_delete_namespaced_persistent_volume_claim): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "v1,PersistentVolumeClaim" mock_delete_namespaced_persistent_volume_claim.return_value = \ client.V1Status() @@ -816,7 +818,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_limit_range(self, mock_vnf_resource_list, mock_delete_namespaced_limit_range): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "v1,LimitRange" mock_delete_namespaced_limit_range.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -830,7 +832,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_pod_template(self, mock_vnf_resource_list, mock_delete_namespaced_pod_template): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "v1,PodTemplate" mock_delete_namespaced_pod_template.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -844,7 +846,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_namespace(self, mock_vnf_resource_list, mock_delete_namespace): - resource_name = ",fake_name" + resource_name = "fake_name" resource_type = "v1,Namespace" mock_delete_namespace.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -858,7 +860,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_persistent_volume(self, mock_vnf_resource_list, mock_delete_persistent_volume): - resource_name = ",fake_name" + resource_name = "fake_name" resource_type = "v1,PersistentVolume" mock_delete_persistent_volume.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -872,7 +874,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_resource_quota(self, mock_vnf_resource_list, mock_delete_namespaced_resource_quota): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "v1,ResourceQuota" mock_delete_namespaced_resource_quota.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -886,7 +888,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_service_account(self, mock_vnf_resource_list, mock_delete_namespaced_service_account): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "v1,ServiceAccount" mock_delete_namespaced_service_account.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -900,7 +902,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_api_service(self, mock_vnf_resource_list, mock_delete_api_service): - resource_name = ",fake_name" + resource_name = "fake_name" resource_type = "apiregistration.k8s.io/v1,APIService" mock_delete_api_service.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -914,7 +916,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_daemon_set(self, mock_vnf_resource_list, mock_delete_namespaced_daemon_set): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "apps/v1,DaemonSet" mock_delete_namespaced_daemon_set.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -928,7 +930,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_deployment(self, mock_vnf_resource_list, mock_delete_namespaced_deployment): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "apps/v1,Deployment" mock_delete_namespaced_deployment.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -942,7 +944,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_replica_set(self, mock_vnf_resource_list, mock_delete_namespaced_replica_set): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "apps/v1,ReplicaSet" mock_delete_namespaced_replica_set.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -964,7 +966,7 @@ class TestKubernetes(base.TestCase): mock_read_namespaced_stateful_set, mock_list_namespaced_persistent_volume_claim, mock_delete_namespaced_persistent_volume_claim): - resource_name = "curryns,curry-test001" + resource_name = "curry-test001" resource_type = "apps/v1,StatefulSet" mock_delete_namespaced_stateful_set.return_value = client.V1Status() mock_delete_namespaced_persistent_volume_claim.return_value = \ @@ -997,7 +999,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_controller_revision(self, mock_vnf_resource_list, mock_delete_namespaced_controller_revision): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "apps/v1,ControllerRevision" mock_delete_namespaced_controller_revision.return_value = \ client.V1Status() @@ -1013,7 +1015,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_horizontal_pod_autoscaler(self, mock_vnf_resource_list, mock_delete_namespaced_horizontal_pod_autoscaler): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "autoscaling/v1,HorizontalPodAutoscaler" mock_delete_namespaced_horizontal_pod_autoscaler.return_value = \ client.V1Status() @@ -1028,7 +1030,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_job(self, mock_vnf_resource_list, mock_delete_namespaced_job): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "batch/v1,Job" mock_delete_namespaced_job.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -1042,7 +1044,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_lease(self, mock_vnf_resource_list, mock_delete_namespaced_lease): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "coordination.k8s.io/v1,Lease" mock_delete_namespaced_lease.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -1057,7 +1059,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_network_policy(self, mock_vnf_resource_list, mock_delete_namespaced_network_policy): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "networking.k8s.io/v1,NetworkPolicy" mock_delete_namespaced_network_policy.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -1072,7 +1074,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_cluster_role(self, mock_vnf_resource_list, mock_delete_cluster_role): - resource_name = ",fake_name" + resource_name = "fake_name" resource_type = "rbac.authorization.k8s.io/v1,ClusterRole" mock_delete_cluster_role.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -1087,7 +1089,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_cluster_role_binding(self, mock_vnf_resource_list, mock_delete_cluster_role_binding): - resource_name = ",fake_name" + resource_name = "fake_name" resource_type = "rbac.authorization.k8s.io/v1,ClusterRoleBinding" mock_delete_cluster_role_binding.return_value = \ client.V1Status() @@ -1103,7 +1105,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_role(self, mock_vnf_resource_list, mock_delete_namespaced_role): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "rbac.authorization.k8s.io/v1,Role" mock_delete_namespaced_role.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -1118,7 +1120,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_role_binding(self, mock_vnf_resource_list, mock_delete_namespaced_role_binding): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "rbac.authorization.k8s.io/v1,RoleBinding" mock_delete_namespaced_role_binding.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -1132,7 +1134,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_priority_class(self, mock_vnf_resource_list, mock_delete_priority_class): - resource_name = ",fake_name" + resource_name = "fake_name" resource_type = "scheduling.k8s.io/v1,PriorityClass" mock_delete_priority_class.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -1146,7 +1148,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_storage_class(self, mock_vnf_resource_list, mock_delete_storage_class): - resource_name = ",fake_name" + resource_name = "fake_name" resource_type = "storage.k8s.io/v1,StorageClass" mock_delete_storage_class.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -1160,7 +1162,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_volume_attachment(self, mock_vnf_resource_list, mock_delete_volume_attachment): - resource_name = ",fake_name" + resource_name = "fake_name" resource_type = "storage.k8s.io/v1,VolumeAttachment" mock_delete_volume_attachment.return_value = client.V1Status() self._delete_single_vnf_resource( @@ -1182,20 +1184,21 @@ class TestKubernetes(base.TestCase): vnf_id = 'fake_vnf_id' vnf_instance = fd_utils.get_vnf_instance_object() vnf_instance_id = vnf_instance.id + vnf_instance.vnf_metadata['namespace'] = "default" terminate_vnf_req = objects.TerminateVnfRequest( termination_type=fields.VnfInstanceTerminationType.GRACEFUL, graceful_termination_timeout=5) vnf_resource1 = models.VnfResource() vnf_resource1.vnf_instance_id = vnf_instance_id - vnf_resource1.resource_name = ",fake_name1" + vnf_resource1.resource_name = "fake_name1" vnf_resource1.resource_type = "storage.k8s.io/v1,StorageClass" vnf_resource2 = models.VnfResource() vnf_resource2.vnf_instance_id = vnf_instance_id - vnf_resource2.resource_name = ",fake_name2" + vnf_resource2.resource_name = "fake_name2" vnf_resource2.resource_type = "v1,PersistentVolume" vnf_resource3 = models.VnfResource() vnf_resource3.vnf_instance_id = vnf_instance_id - vnf_resource3.resource_name = "fake_namespace,fake_name3" + vnf_resource3.resource_name = "fake_name3" vnf_resource3.resource_type = "v1,PersistentVolumeClaim" mock_vnf_resource_list.return_value = \ [vnf_resource1, vnf_resource2, vnf_resource3] @@ -1217,7 +1220,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_pod_api_fail(self, mock_vnf_resource_list, mock_delete_namespaced_pod): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "v1,Pod" mock_delete_namespaced_pod.side_effect = Exception() self._delete_single_vnf_resource( @@ -1236,7 +1239,7 @@ class TestKubernetes(base.TestCase): mock_delete_namespaced_stateful_set, mock_read_namespaced_stateful_set, mock_list_namespaced_persistent_volume_claim): - resource_name = "curryns,curry-test001" + resource_name = "curry-test001" resource_type = "apps/v1,StatefulSet" mock_delete_namespaced_stateful_set.return_value = client.V1Status() stateful_set_obj = fakes.fake_v1_stateful_set() @@ -1257,7 +1260,7 @@ class TestKubernetes(base.TestCase): def test_delete_stateful_set_read_sfs_fail(self, mock_vnf_resource_list, mock_delete_namespaced_stateful_set, mock_read_namespaced_stateful_set): - resource_name = "curryns,curry-test001" + resource_name = "curry-test001" resource_type = "apps/v1,StatefulSet" mock_delete_namespaced_stateful_set.return_value = client.V1Status() mock_read_namespaced_stateful_set.side_effect = Exception() @@ -1275,6 +1278,7 @@ class TestKubernetes(base.TestCase): vnf_instance_id = '4a4c2d44-8a52-4895-9a75-9d1c76c3e738' vnf_instance = fd_utils.get_vnf_instance_object() vnf_instance.id = vnf_instance_id + vnf_instance.vnf_metadata['namespace'] = "default" vnf_resource = models.VnfResource() vnf_resource.vnf_instance_id = vnf_instance_id vnf_resource.resource_name = resource_name @@ -1290,7 +1294,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_pod(self, mock_vnf_resource_list, mock_read_namespaced_pod): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "v1,Pod" mock_read_namespaced_pod.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1303,7 +1307,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_service(self, mock_vnf_resource_list, mock_read_namespaced_service): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "v1,Service" mock_read_namespaced_service.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1316,7 +1320,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_secret(self, mock_vnf_resource_list, mock_read_namespaced_secret): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "v1,Secret" mock_read_namespaced_secret.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1329,7 +1333,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_config_map(self, mock_vnf_resource_list, mock_read_namespaced_config_map): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "v1,ConfigMap" mock_read_namespaced_config_map.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1343,7 +1347,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_persistent_volume_claim(self, mock_vnf_resource_list, mock_read_namespaced_persistent_volume_claim): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "v1,PersistentVolumeClaim" mock_read_namespaced_persistent_volume_claim.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1356,7 +1360,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_limit_range(self, mock_vnf_resource_list, mock_read_namespaced_limit_range): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "v1,LimitRange" mock_read_namespaced_limit_range.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1369,7 +1373,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_pod_template(self, mock_vnf_resource_list, mock_read_namespaced_pod_template): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "v1,PodTemplate" mock_read_namespaced_pod_template.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1382,7 +1386,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_namespace(self, mock_vnf_resource_list, mock_read_namespace): - resource_name = ",fake_name" + resource_name = "fake_name" resource_type = "v1,Namespace" mock_read_namespace.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1395,7 +1399,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_persistent_volume(self, mock_vnf_resource_list, mock_read_persistent_volume): - resource_name = ",fake_name" + resource_name = "fake_name" resource_type = "v1,PersistentVolume" mock_read_persistent_volume.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1408,7 +1412,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_resource_quota(self, mock_vnf_resource_list, mock_read_namespaced_resource_quota): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "v1,ResourceQuota" mock_read_namespaced_resource_quota.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1421,7 +1425,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_service_account(self, mock_vnf_resource_list, mock_read_namespaced_service_account): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "v1,ServiceAccount" mock_read_namespaced_service_account.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1434,7 +1438,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_api_service(self, mock_vnf_resource_list, mock_read_api_service): - resource_name = ",fake_name" + resource_name = "fake_name" resource_type = "apiregistration.k8s.io/v1,APIService" mock_read_api_service.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1447,7 +1451,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_daemon_set(self, mock_vnf_resource_list, mock_read_namespaced_daemon_set): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "apps/v1,DaemonSet" mock_read_namespaced_daemon_set.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1460,7 +1464,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_deployment(self, mock_vnf_resource_list, mock_read_namespaced_deployment): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "apps/v1,Deployment" mock_read_namespaced_deployment.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1473,7 +1477,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_replica_set(self, mock_vnf_resource_list, mock_read_namespaced_replica_set): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "apps/v1,ReplicaSet" mock_read_namespaced_replica_set.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1486,7 +1490,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_stateful_set(self, mock_vnf_resource_list, mock_read_namespaced_stateful_set): - resource_name = "curryns,curry-test001" + resource_name = "curry-test001" resource_type = "apps/v1,StatefulSet" mock_read_namespaced_stateful_set.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1500,7 +1504,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_controller_revision(self, mock_vnf_resource_list, mock_read_namespaced_controller_revision): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "apps/v1,ControllerRevision" mock_read_namespaced_controller_revision.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1515,7 +1519,7 @@ class TestKubernetes(base.TestCase): def test_delete_wait_horizontal_pod_autoscaler(self, mock_vnf_resource_list, mock_read_namespaced_horizontal_pod_autoscaler): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "autoscaling/v1,HorizontalPodAutoscaler" mock_read_namespaced_horizontal_pod_autoscaler.side_effect = \ Exception() @@ -1529,7 +1533,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_job(self, mock_vnf_resource_list, mock_read_namespaced_job): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "batch/v1,Job" mock_read_namespaced_job.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1542,7 +1546,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_lease(self, mock_vnf_resource_list, mock_read_namespaced_lease): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "coordination.k8s.io/v1,Lease" mock_read_namespaced_lease.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1556,7 +1560,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_network_policy(self, mock_vnf_resource_list, mock_read_namespaced_network_policy): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "networking.k8s.io/v1,NetworkPolicy" mock_read_namespaced_network_policy.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1570,7 +1574,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_cluster_role(self, mock_vnf_resource_list, mock_read_cluster_role): - resource_name = ",fake_name" + resource_name = "fake_name" resource_type = "rbac.authorization.k8s.io/v1,ClusterRole" mock_read_cluster_role.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1584,7 +1588,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_cluster_role_binding(self, mock_vnf_resource_list, mock_read_cluster_role_binding): - resource_name = ",fake_name" + resource_name = "fake_name" resource_type = "rbac.authorization.k8s.io/v1,ClusterRoleBinding" mock_read_cluster_role_binding.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1598,7 +1602,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_role(self, mock_vnf_resource_list, mock_read_namespaced_role): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "rbac.authorization.k8s.io/v1,Role" mock_read_namespaced_role.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1612,7 +1616,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_role_binding(self, mock_vnf_resource_list, mock_read_namespaced_role_binding): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "rbac.authorization.k8s.io/v1,RoleBinding" mock_read_namespaced_role_binding.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1625,7 +1629,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_priority_class(self, mock_vnf_resource_list, mock_read_priority_class): - resource_name = ",fake_name" + resource_name = "fake_name" resource_type = "scheduling.k8s.io/v1,PriorityClass" mock_read_priority_class.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1638,7 +1642,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_storage_class(self, mock_vnf_resource_list, mock_read_storage_class): - resource_name = ",fake_name" + resource_name = "fake_name" resource_type = "storage.k8s.io/v1,StorageClass" mock_read_storage_class.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1651,7 +1655,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_volume_attachment(self, mock_vnf_resource_list, mock_read_volume_attachment): - resource_name = ",fake_name" + resource_name = "fake_name" resource_type = "storage.k8s.io/v1,VolumeAttachment" mock_read_volume_attachment.side_effect = Exception() self._delete_wait_single_vnf_resource( @@ -1664,7 +1668,7 @@ class TestKubernetes(base.TestCase): @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_delete_wait_retry(self, mock_vnf_resource_list, mock_read_namespaced_pod): - resource_name = "fake_namespace,fake_name" + resource_name = "fake_name" resource_type = "v1,Pod" mock_read_namespaced_pod.return_value = client.V1Status() self._delete_wait_single_vnf_resource( @@ -1789,12 +1793,7 @@ class TestKubernetes(base.TestCase): 'deploy_kubernetes_objects') def test_instantiate_vnf_without_target_k8s_files( self, mock_deploy_kubernetes_objects): - vnf = { - 'vnfd': { - 'attributes': { - 'vnfd': { - 'tosca_definitions_version': 'tosca_simple_yaml_1_0'} - }}} + vnf = objects.VnfInstance(vnf_metadata={'namespace': 'default'}) vim_connection_info = objects.VimConnectionInfo( access_info={'auth_url': 'http://fake-url/identity/v3'}) vnfd_dict = fakes.fake_vnf_dict() @@ -1829,12 +1828,7 @@ class TestKubernetes(base.TestCase): mock_read_namespaced_deployment, mock_deploy_k8s, mock_get_k8s_objs_from_yaml): - vnf = { - 'vnfd': { - 'attributes': { - 'vnfd': { - 'tosca_definitions_version': 'tosca_simple_yaml_1_0'} - }}} + vnf = objects.VnfInstance(vnf_metadata={'namespace': 'default'}) vim_connection_info = objects.VimConnectionInfo( access_info={'auth_url': 'http://fake-url/identity/v3'}) deployment_obj = fakes.fake_v1_deployment() @@ -2093,6 +2087,7 @@ class TestKubernetes(base.TestCase): fakes.get_fake_pod_info(kind='Pod', name='vdu2')]) instantiate_vnf_req = objects.InstantiateVnfRequest( additional_params={'lcm-kubernetes-def-files': ["dummy.yaml"]}) + self.vnf_instance.vnf_metadata['namespace'] = 'default' self.kubernetes.post_vnf_instantiation( context=self.context, vnf_instance=self.vnf_instance, @@ -2208,12 +2203,14 @@ class TestKubernetes(base.TestCase): fakes.fake_vim_connection_info(), instantiate_vnf_req) + @mock.patch.object(objects.VnfInstance, "get_by_id") @mock.patch.object(client.AppsV1Api, 'patch_namespaced_deployment_scale') @mock.patch.object(client.AppsV1Api, 'read_namespaced_deployment_scale') @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_scale_in_deployment(self, mock_vnf_resource_list, mock_read_namespaced_deployment_scale, - mock_patch_namespaced_deployment_scale): + mock_patch_namespaced_deployment_scale, + mock_vnf_instance): policy = fakes.get_scale_policy(type='in') mock_vnf_resource_list.return_value = \ fakes.get_vnf_resource_list(kind='Deployment') @@ -2230,12 +2227,14 @@ class TestKubernetes(base.TestCase): mock_read_namespaced_deployment_scale.assert_called_once() mock_patch_namespaced_deployment_scale.assert_called_once() + @mock.patch.object(objects.VnfInstance, "get_by_id") @mock.patch.object(client.AppsV1Api, 'patch_namespaced_stateful_set_scale') @mock.patch.object(client.AppsV1Api, 'read_namespaced_stateful_set_scale') @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_scale_in_stateful_set(self, mock_vnf_resource_list, mock_read_namespaced_stateful_set_scale, - mock_patch_namespaced_stateful_set_scale): + mock_patch_namespaced_stateful_set_scale, + mock_vnf_instance): policy = fakes.get_scale_policy(type='in') mock_vnf_resource_list.return_value = \ fakes.get_vnf_resource_list(kind='StatefulSet') @@ -2252,12 +2251,14 @@ class TestKubernetes(base.TestCase): mock_read_namespaced_stateful_set_scale.assert_called_once() mock_patch_namespaced_stateful_set_scale.assert_called_once() + @mock.patch.object(objects.VnfInstance, "get_by_id") @mock.patch.object(client.AppsV1Api, 'patch_namespaced_replica_set_scale') @mock.patch.object(client.AppsV1Api, 'read_namespaced_replica_set_scale') @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_scale_in_replica_set(self, mock_vnf_resource_list, mock_read_namespaced_replica_set_scale, - mock_patch_namespaced_replica_set_scale): + mock_patch_namespaced_replica_set_scale, + mock_vnf_instance): policy = fakes.get_scale_policy(type='in') mock_vnf_resource_list.return_value = \ fakes.get_vnf_resource_list(kind='ReplicaSet') @@ -2274,12 +2275,14 @@ class TestKubernetes(base.TestCase): mock_read_namespaced_replica_set_scale.assert_called_once() mock_patch_namespaced_replica_set_scale.assert_called_once() + @mock.patch.object(objects.VnfInstance, "get_by_id") @mock.patch.object(client.AppsV1Api, 'patch_namespaced_deployment_scale') @mock.patch.object(client.AppsV1Api, 'read_namespaced_deployment_scale') @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_scale_out(self, mock_vnf_resource_list, mock_read_namespaced_deployment_scale, - mock_patch_namespaced_deployment_scale): + mock_patch_namespaced_deployment_scale, + mock_vnf_instance): policy = fakes.get_scale_policy(type='out') mock_vnf_resource_list.return_value = \ fakes.get_vnf_resource_list(kind='Deployment') @@ -2296,8 +2299,10 @@ class TestKubernetes(base.TestCase): mock_read_namespaced_deployment_scale.assert_called_once() mock_patch_namespaced_deployment_scale.assert_called_once() + @mock.patch.object(objects.VnfInstance, "get_by_id") @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") - def test_scale_target_not_found(self, mock_vnf_resource_list): + def test_scale_target_not_found( + self, mock_vnf_resource_list, mock_vnf_instance): policy = fakes.get_scale_policy(type='in') mock_vnf_resource_list.return_value = \ fakes.get_vnf_resource_list(kind='Depoyment', name='other_name') @@ -2306,8 +2311,10 @@ class TestKubernetes(base.TestCase): self.context, None, utils.get_vim_auth_obj(), policy, None) + @mock.patch.object(objects.VnfInstance, "get_by_id") @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") - def test_scale_out_of_target_kind(self, mock_vnf_resource_list): + def test_scale_out_of_target_kind( + self, mock_vnf_resource_list, mock_vnf_instance): policy = fakes.get_scale_policy(type='in') mock_vnf_resource_list.return_value = \ fakes.get_vnf_resource_list(kind='Pod') @@ -2316,10 +2323,12 @@ class TestKubernetes(base.TestCase): self.context, None, utils.get_vim_auth_obj(), policy, None) + @mock.patch.object(objects.VnfInstance, "get_by_id") @mock.patch.object(client.AppsV1Api, 'read_namespaced_deployment_scale') @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_scale_in_less_than_min_replicas(self, mock_vnf_resource_list, - mock_read_namespaced_deployment_scale): + mock_read_namespaced_deployment_scale, + mock_vnf_instance): policy = fakes.get_scale_policy(type='in') mock_vnf_resource_list.return_value = \ fakes.get_vnf_resource_list(kind='Deployment') @@ -2331,10 +2340,12 @@ class TestKubernetes(base.TestCase): self.context, None, utils.get_vim_auth_obj(), policy, None) + @mock.patch.object(objects.VnfInstance, "get_by_id") @mock.patch.object(client.AppsV1Api, 'read_namespaced_deployment_scale') @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_scale_out_over_max_replicas(self, mock_vnf_resource_list, - mock_read_namespaced_deployment_scale): + mock_read_namespaced_deployment_scale, + mock_vnf_instance): policy = fakes.get_scale_policy(type='out') mock_vnf_resource_list.return_value = \ fakes.get_vnf_resource_list(kind='Deployment') @@ -2448,12 +2459,14 @@ class TestKubernetes(base.TestCase): mock_read_namespaced_horizontal_pod_autoscaler.assert_called_once() mock_patch_namespaced_deployment_scale.assert_called_once() + @mock.patch.object(objects.VnfInstance, "get_by_id") @mock.patch.object(client.AppsV1Api, 'read_namespaced_deployment_scale') @mock.patch.object(client.CoreV1Api, 'list_namespaced_pod') @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_scale_wait_deployment(self, mock_vnf_resource_list, mock_list_namespaced_pod, - mock_read_namespaced_deployment_scale): + mock_read_namespaced_deployment_scale, + mock_vnf_instance): policy = fakes.get_scale_policy(type='out') mock_vnf_resource_list.return_value = \ fakes.get_vnf_resource_list(kind='Deployment') @@ -2470,12 +2483,14 @@ class TestKubernetes(base.TestCase): last_event_id=None) mock_list_namespaced_pod.assert_called_once() + @mock.patch.object(objects.VnfInstance, "get_by_id") @mock.patch.object(client.AppsV1Api, 'read_namespaced_stateful_set_scale') @mock.patch.object(client.CoreV1Api, 'list_namespaced_pod') @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_scale_wait_stateful_set(self, mock_vnf_resource_list, mock_list_namespaced_pod, - mock_read_namespaced_stateful_set_scale): + mock_read_namespaced_stateful_set_scale, + mock_vnf_instance): policy = fakes.get_scale_policy(type='out') mock_vnf_resource_list.return_value = \ fakes.get_vnf_resource_list(kind='StatefulSet') @@ -2492,12 +2507,14 @@ class TestKubernetes(base.TestCase): last_event_id=None) mock_list_namespaced_pod.assert_called_once() + @mock.patch.object(objects.VnfInstance, "get_by_id") @mock.patch.object(client.AppsV1Api, 'read_namespaced_replica_set_scale') @mock.patch.object(client.CoreV1Api, 'list_namespaced_pod') @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_scale_wait_replica_set(self, mock_vnf_resource_list, mock_list_namespaced_pod, - mock_read_namespaced_replica_set_scale): + mock_read_namespaced_replica_set_scale, + mock_vnf_instance): policy = fakes.get_scale_policy(type='out') mock_vnf_resource_list.return_value = \ fakes.get_vnf_resource_list(kind='ReplicaSet') @@ -2514,8 +2531,10 @@ class TestKubernetes(base.TestCase): last_event_id=None) mock_list_namespaced_pod.assert_called_once() + @mock.patch.object(objects.VnfInstance, "get_by_id") @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") - def test_scale_wait_target_not_found(self, mock_vnf_resource_list): + def test_scale_wait_target_not_found( + self, mock_vnf_resource_list, mock_vnf_instance): policy = fakes.get_scale_policy(type='out') mock_vnf_resource_list.return_value = \ fakes.get_vnf_resource_list(kind='Depoyment', name='other_name') @@ -2524,12 +2543,14 @@ class TestKubernetes(base.TestCase): self.context, None, utils.get_vim_auth_obj(), policy, None, None) + @mock.patch.object(objects.VnfInstance, "get_by_id") @mock.patch.object(client.AppsV1Api, 'read_namespaced_deployment_scale') @mock.patch.object(client.CoreV1Api, 'list_namespaced_pod') @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_scale_wait_retry_over(self, mock_vnf_resource_list, mock_list_namespaced_pod, - mock_read_namespaced_deployment_scale): + mock_read_namespaced_deployment_scale, + mock_vnf_instance): policy = fakes.get_scale_policy(type='out') mock_vnf_resource_list.return_value = \ fakes.get_vnf_resource_list(kind='Deployment') @@ -2545,12 +2566,14 @@ class TestKubernetes(base.TestCase): self.context, None, utils.get_vim_auth_obj(), policy, None, None) + @mock.patch.object(objects.VnfInstance, "get_by_id") @mock.patch.object(client.AppsV1Api, 'read_namespaced_deployment_scale') @mock.patch.object(client.CoreV1Api, 'list_namespaced_pod') @mock.patch.object(objects.VnfResourceList, "get_by_vnf_instance_id") def test_scale_wait_status_unknown(self, mock_vnf_resource_list, mock_list_namespaced_pod, - mock_read_namespaced_deployment_scale): + mock_read_namespaced_deployment_scale, + mock_vnf_instance): policy = fakes.get_scale_policy(type='out') mock_vnf_resource_list.return_value = \ fakes.get_vnf_resource_list(kind='Deployment') @@ -2634,10 +2657,11 @@ class TestKubernetes(base.TestCase): "SCALE_OUT", "vdu1_aspect", 1, "False") scale_status = objects.ScaleInfo( aspect_id='vdu1_aspect', scale_level=1) - mock_vnf_instance_get_by_id.return_value = \ - vnflcm_fakes.return_vnf_instance( - fields.VnfInstanceState.INSTANTIATED, - scale_status=scale_status) + scale_vnf_instance = vnflcm_fakes.return_vnf_instance( + fields.VnfInstanceState.INSTANTIATED, + scale_status=scale_status) + scale_vnf_instance.vnf_metadata['namespace'] = "default" + mock_vnf_instance_get_by_id.return_value = scale_vnf_instance mock_vnf_resource_list.return_value = \ fakes.get_vnf_resource_list(kind='Deployment', name='vdu1') mock_vnf_package_vnfd_get_by_id.return_value = \ @@ -2675,10 +2699,11 @@ class TestKubernetes(base.TestCase): vnf_info['vnf_lcm_op_occ'] = vnflcm_fakes.vnflcm_scale_out_cnf() scale_status = objects.ScaleInfo( aspect_id='vdu1_aspect', scale_level=1) - mock_vnf_instance_get_by_id.return_value = \ - vnflcm_fakes.return_vnf_instance( - fields.VnfInstanceState.INSTANTIATED, - scale_status=scale_status) + scale_vnf_instance = vnflcm_fakes.return_vnf_instance( + fields.VnfInstanceState.INSTANTIATED, + scale_status=scale_status) + scale_vnf_instance.vnf_metadata['namespace'] = "default" + mock_vnf_instance_get_by_id.return_value = scale_vnf_instance mock_vnf_resource_list.return_value = \ fakes.get_vnf_resource_list(kind='Deployment', name='vdu1') mock_vnf_package_vnfd_get_by_id.return_value = \ @@ -2710,10 +2735,10 @@ class TestKubernetes(base.TestCase): vnf_resource_list = [] vnf_resource_list.append(models.VnfResource()) vnf_resource_list[0].vnf_instance_id = self.vnf_instance.id - vnf_resource_list[0].resource_name = "default,vdu0" + vnf_resource_list[0].resource_name = "vdu0" vnf_resource_list[0].resource_type = "apps/v1,Deployment" vnf_resource_list.append(copy.deepcopy(vnf_resource_list[0])) - vnf_resource_list[1].resource_name = "default,vdu1" + vnf_resource_list[1].resource_name = "vdu1" mock_vnf_resource_list.return_value = vnf_resource_list vnfc_resource_info = [] vnfc_resource_info.append( @@ -2776,7 +2801,7 @@ class TestKubernetes(base.TestCase): vnflcm_fakes.return_vnf_package_vnfd() vnf_resource = models.VnfResource() vnf_resource.vnf_instance_id = self.vnf_instance.id - vnf_resource.resource_name = "default,vdu1" + vnf_resource.resource_name = "vdu1" vnf_resource.resource_type = "apps/v1,Deployment" mock_vnf_resource_list.return_value = [vnf_resource] vnfc_resource_info = [] @@ -2830,7 +2855,7 @@ class TestKubernetes(base.TestCase): vnflcm_fakes.return_vnf_package_vnfd() vnf_resource = models.VnfResource() vnf_resource.vnf_instance_id = self.vnf_instance.id - vnf_resource.resource_name = "default,vdu1" + vnf_resource.resource_name = "vdu1" vnf_resource.resource_type = "apps/v1,Deployment" mock_vnf_resource_list.return_value = [vnf_resource] vnfc_resource_info = [] @@ -2856,6 +2881,7 @@ class TestKubernetes(base.TestCase): client.rest.ApiException(status=500) vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = fakes.fake_vnfc_resource_info(rsc_kind='Pod') vnf_instance_obj.instantiated_vnf_info.vnfc_resource_info = \ [vnfc_resource_info_obj] @@ -2883,6 +2909,7 @@ class TestKubernetes(base.TestCase): mock_delete_namespaced_pod.return_value = client.V1Status() vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = fakes.fake_vnfc_resource_info(rsc_kind='Pod') vnf_instance_obj.instantiated_vnf_info.vnfc_resource_info = \ [vnfc_resource_info_obj] @@ -2915,6 +2942,7 @@ class TestKubernetes(base.TestCase): mock_create_namespaced_pod.return_value = client.V1Status() vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = fakes.fake_vnfc_resource_info(rsc_kind='Pod') vnf_instance_obj.instantiated_vnf_info.vnfc_resource_info = \ [vnfc_resource_info_obj] @@ -2946,6 +2974,7 @@ class TestKubernetes(base.TestCase): mock_create_namespaced_pod.return_value = client.V1Status() vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = fakes.fake_vnfc_resource_info(rsc_kind='Pod') vnf_instance_obj.instantiated_vnf_info.vnfc_resource_info = \ [vnfc_resource_info_obj] @@ -2971,6 +3000,7 @@ class TestKubernetes(base.TestCase): mock_delete_namespaced_pod.return_value = client.V1Status() vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = fakes.fake_vnfc_resource_info( rsc_kind='Deployment') vnf_instance_obj.instantiated_vnf_info.vnfc_resource_info = \ @@ -2998,6 +3028,7 @@ class TestKubernetes(base.TestCase): client.rest.ApiException(status=404) vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = fakes.fake_vnfc_resource_info( rsc_kind='Deployment') vnf_instance_obj.instantiated_vnf_info.vnfc_resource_info = \ @@ -3027,6 +3058,7 @@ class TestKubernetes(base.TestCase): client.rest.ApiException(status=500) vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = fakes.fake_vnfc_resource_info( rsc_kind='Deployment') vnf_instance_obj.instantiated_vnf_info.vnfc_resource_info = \ @@ -3049,6 +3081,7 @@ class TestKubernetes(base.TestCase): fakes.get_fake_pod_info(kind='ReplicaSet')]) vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = fakes.fake_vnfc_resource_info( rsc_kind='ReplicaSet') # change Kubernetes resource kind to Job (for illegal route) @@ -3086,6 +3119,7 @@ class TestKubernetes(base.TestCase): fields.VnfInstanceState.INSTANTIATED) vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info = [] vnfc_resource_info.append(fakes.fake_vnfc_resource_info( vdu_id='VDU1', rsc_kind='Deployment', rsc_name='fake_name', @@ -3123,6 +3157,7 @@ class TestKubernetes(base.TestCase): client.rest.ApiException(status=500) vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = fakes.fake_vnfc_resource_info(rsc_kind='Pod') vnf_instance_obj.instantiated_vnf_info.vnfc_resource_info = \ [vnfc_resource_info_obj] @@ -3143,6 +3178,7 @@ class TestKubernetes(base.TestCase): fakes.get_fake_pod_info(kind='Pod')]) vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = fakes.fake_vnfc_resource_info(rsc_kind='Pod') vnf_instance_obj.instantiated_vnf_info.vnfc_resource_info = \ [vnfc_resource_info_obj] @@ -3167,6 +3203,7 @@ class TestKubernetes(base.TestCase): status=client.V1ScaleStatus(replicas=1)) vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = fakes.fake_vnfc_resource_info( rsc_kind='Deployment') vnf_instance_obj.instantiated_vnf_info.vnfc_resource_info = \ @@ -3187,6 +3224,7 @@ class TestKubernetes(base.TestCase): fakes.get_fake_pod_info(kind='DaemonSet')]) vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = fakes.fake_vnfc_resource_info( rsc_kind='DaemonSet') vnf_instance_obj.instantiated_vnf_info.vnfc_resource_info = \ @@ -3212,6 +3250,7 @@ class TestKubernetes(base.TestCase): status=client.V1ScaleStatus(replicas=1)) vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = fakes.fake_vnfc_resource_info( rsc_kind='StatefulSet') vnf_instance_obj.instantiated_vnf_info.vnfc_resource_info = \ @@ -3237,6 +3276,7 @@ class TestKubernetes(base.TestCase): status=client.V1ScaleStatus(replicas=1)) vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = fakes.fake_vnfc_resource_info( rsc_kind='ReplicaSet') vnf_instance_obj.instantiated_vnf_info.vnfc_resource_info = \ @@ -3263,6 +3303,7 @@ class TestKubernetes(base.TestCase): status=client.V1ScaleStatus(replicas=1)) vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_list = [ fakes.fake_vnfc_resource_info(rsc_kind='Deployment'), fakes.fake_vnfc_resource_info( @@ -3285,6 +3326,7 @@ class TestKubernetes(base.TestCase): mock_list_namespaced_pod): vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = fakes.fake_vnfc_resource_info( rsc_kind='Deployment', pod_name="POD_NOT_FOUND") vnf_instance_obj.instantiated_vnf_info.vnfc_resource_info = \ @@ -3310,6 +3352,7 @@ class TestKubernetes(base.TestCase): status=client.V1ScaleStatus(replicas=1)) vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = \ fakes.fake_vnfc_resource_info(rsc_kind='Deployment') vnf_instance_obj.instantiated_vnf_info.vnfc_resource_info = \ @@ -3336,6 +3379,7 @@ class TestKubernetes(base.TestCase): status=client.V1ScaleStatus(replicas=1)) vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = \ fakes.fake_vnfc_resource_info(rsc_kind='Deployment') vnf_instance_obj.instantiated_vnf_info.vnfc_resource_info = \ @@ -3363,6 +3407,7 @@ class TestKubernetes(base.TestCase): status=client.V1ScaleStatus(replicas=1)) vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = \ fakes.fake_vnfc_resource_info(rsc_kind='Deployment') vnf_instance_obj.instantiated_vnf_info.vnfc_resource_info = \ @@ -3384,6 +3429,7 @@ class TestKubernetes(base.TestCase): client.rest.ApiException(status=500) vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = fakes.fake_vnfc_resource_info( rsc_kind='Deployment') vnf_instance_obj.instantiated_vnf_info.vnfc_resource_info = \ @@ -3411,6 +3457,7 @@ class TestKubernetes(base.TestCase): name='fake_name', pod_name="fake_name-1234567890-actp3")]) vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_list = [ fakes.fake_vnfc_resource_info(rsc_kind='Deployment', rsc_name='fake_name', pod_name="fake_name-1234567890-strp1"), @@ -3451,6 +3498,7 @@ class TestKubernetes(base.TestCase): name='fake_name', pod_name="fake_name-1234567890-abcdf")]) vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_list = [ fakes.fake_vnfc_resource_info(rsc_kind='Deployment', rsc_name='fake_name', pod_name="POD_NOT_FOUND")] @@ -3477,6 +3525,7 @@ class TestKubernetes(base.TestCase): name='fake_name', pod_name="fake_name-12346")]) vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = fakes.fake_vnfc_resource_info( rsc_kind='DaemonSet', rsc_name='fake_name') @@ -3506,6 +3555,7 @@ class TestKubernetes(base.TestCase): name='fake_name')]) vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = fakes.fake_vnfc_resource_info( rsc_kind='Deployment', rsc_name='fake_name') @@ -3536,6 +3586,7 @@ class TestKubernetes(base.TestCase): fakes.get_fake_pod_info(kind='DaemonSet')]) vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = fakes.fake_vnfc_resource_info( rsc_kind='DaemonSet') vnf_instance_obj.instantiated_vnf_info.vnfc_resource_info = \ @@ -3556,6 +3607,7 @@ class TestKubernetes(base.TestCase): fakes.get_fake_pod_info(kind='Pod')]) vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = fakes.fake_vnfc_resource_info( rsc_kind='Pod') vnf_instance_obj.instantiated_vnf_info.vnfc_resource_info =\ @@ -3576,6 +3628,7 @@ class TestKubernetes(base.TestCase): fakes.get_fake_pod_info(kind='StatefulSet')]) vnf_instance_obj = vnflcm_fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) + vnf_instance_obj.vnf_metadata['namespace'] = "default" vnfc_resource_info_obj = fakes.fake_vnfc_resource_info( rsc_kind='StatefulSet') vnf_instance_obj.instantiated_vnf_info.vnfc_resource_info =\ diff --git a/tacker/tests/unit/vnfm/infra_drivers/kubernetes/test_kubernetes_driver_helm.py b/tacker/tests/unit/vnfm/infra_drivers/kubernetes/test_kubernetes_driver_helm.py index 49832cd2b..d8e49c934 100644 --- a/tacker/tests/unit/vnfm/infra_drivers/kubernetes/test_kubernetes_driver_helm.py +++ b/tacker/tests/unit/vnfm/infra_drivers/kubernetes/test_kubernetes_driver_helm.py @@ -1,509 +1,512 @@ -# 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. - -import copy -import eventlet -import os -import paramiko - -from ddt import ddt -from kubernetes import client -from oslo_serialization import jsonutils -from tacker import context -from tacker.db.db_sqlalchemy import models -from tacker.extensions import common_services as cs -from tacker.extensions import vnfm -from tacker import objects -from tacker.tests.unit import base -from tacker.tests.unit.db import utils -from tacker.tests.unit.vnflcm import fakes as vnflcm_fakes -from tacker.tests.unit.vnfm.infra_drivers.kubernetes import fakes -from tacker.tests.unit.vnfm.infra_drivers.openstack.fixture_data import \ - fixture_data_utils as fd_utils -from tacker.vnfm.infra_drivers.kubernetes.helm import helm_client -from tacker.vnfm.infra_drivers.kubernetes import kubernetes_driver -from tacker.vnfm import vim_client -from unittest import mock - - -class FakeRemoteCommandExecutor(mock.Mock): - def close_session(self): - return - - -class FakeCommander(mock.Mock): - def config(self, is_success, errmsg=None): - self.is_success = is_success - self.errmsg = errmsg - - def execute_command(self, *args, **kwargs): - is_success = self.is_success - fake_result = FakeCmdResult() - stderr = '' - stdout = '' - return_code = (0) if is_success else (1) - stderr, stdout = ('', '') if is_success else ('err', '') - if self.errmsg: - stderr = [self.errmsg] - fake_result.set_std(stderr, stdout, return_code) - return fake_result - - -class FakeCmdResult(mock.Mock): - def set_std(self, stderr, stdout, return_code): - self.stderr = stderr - self.stdout = stdout - self.return_code = return_code - - def get_stderr(self): - return self.stderr - - def get_stdout(self): - return self.stdout - - def get_return_code(self): - return self.return_code - - -class FakeTransport(mock.Mock): - pass - - -@ddt -class TestKubernetesHelm(base.TestCase): - def setUp(self): - super(TestKubernetesHelm, self).setUp() - self.kubernetes = kubernetes_driver.Kubernetes() - self.kubernetes.STACK_RETRIES = 1 - self.kubernetes.STACK_RETRY_WAIT = 5 - self.k8s_client_dict = fakes.fake_k8s_client_dict() - self.context = context.get_admin_context() - self.vnf_instance = fd_utils.get_vnf_instance_object() - self.package_path = os.path.join( - os.path.dirname(os.path.abspath(__file__)), - "../../../../etc/samples/etsi/nfv/test_cnf_helmchart") - self._mock_remote_command_executor() - self._mock_transport() - self.helm_client = helm_client.HelmClient('127.0.0.1', 'user', 'pass') - self.helm_client.commander = FakeCommander() - - def _mock_remote_command_executor(self): - self.commander = mock.Mock(wraps=FakeRemoteCommandExecutor()) - fake_commander = mock.Mock() - fake_commander.return_value = self.commander - self._mock( - 'tacker.common.cmd_executer.RemoteCommandExecutor', - fake_commander) - - def _mock_transport(self): - self.transport = mock.Mock(wraps=FakeTransport()) - fake_transport = mock.Mock() - fake_transport.return_value = self.transport - self._mock('paramiko.Transport', fake_transport) - - def _mock(self, target, new=mock.DEFAULT): - patcher = mock.patch(target, new) - return patcher.start() - - @mock.patch.object(eventlet, 'monkey_patch') - def test_execute_command_success(self, mock_monkey_patch): - self.helm_client.commander.config(True) - ssh_command = 'helm install' - timeout = 120 - retry = 1 - self.helm_client._execute_command( - ssh_command, timeout, retry) - - @mock.patch.object(eventlet, 'monkey_patch') - def test_execute_command_failed(self, mock_monkey_patch): - self.helm_client.commander.config(False) - ssh_command = 'helm install' - timeout = 120 - retry = 1 - self.assertRaises(vnfm.HelmClientRemoteCommandError, - self.helm_client._execute_command, - ssh_command, timeout, retry) - - @mock.patch.object(eventlet, 'monkey_patch') - @mock.patch.object(FakeCommander, 'execute_command') - def test_execute_command_timeout(self, mock_execute_command, - mock_monkey_patch): - mock_execute_command.side_effect = eventlet.timeout.Timeout - ssh_command = 'helm install' - timeout = 120 - retry = 1 - self.assertRaises(vnfm.HelmClientOtherError, - self.helm_client._execute_command, - ssh_command, timeout, retry) - - def test_pre_instantiation_vnf_helm(self): - vnf_instance = fd_utils.get_vnf_instance_object() - vim_connection_info = fakes.fake_vim_connection_info_with_extra() - vnf_software_images = None - vnf_package_path = self.package_path - instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart() - vnf_resources = self.kubernetes.pre_instantiation_vnf( - self.context, vnf_instance, vim_connection_info, - vnf_software_images, - instantiate_vnf_req, vnf_package_path) - self.assertEqual(vnf_resources, {}) - - def test_pre_helm_install_with_bool_param(self): - vnf_instance = fd_utils.get_vnf_instance_object() - vim_connection_info = fakes.fake_vim_connection_info_with_extra() - vnf_software_images = None - vnf_package_path = self.package_path - instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart() - instantiate_vnf_req.additional_params['use_helm'] = True - using_helm_inst_params = instantiate_vnf_req.additional_params[ - 'using_helm_install_param'] - using_helm_inst_params[0]['exthelmchart'] = True - using_helm_inst_params[1]['exthelmchart'] = False - vnf_resources = self.kubernetes.pre_instantiation_vnf( - self.context, vnf_instance, vim_connection_info, - vnf_software_images, - instantiate_vnf_req, vnf_package_path) - self.assertEqual(vnf_resources, {}) - - def test_pre_helm_install_invaid_vimconnectioninfo_no_helm_info(self): - vim_connection_info = fakes.fake_vim_connection_info_with_extra() - del vim_connection_info.extra['helm_info'] - vnf_package_path = self.package_path - instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart() - exc = self.assertRaises(vnfm.InvalidVimConnectionInfo, - self.kubernetes._pre_helm_install, - vim_connection_info, instantiate_vnf_req, - vnf_package_path) - msg = ("Invalid vim_connection_info: " - "helm_info is missing in vim_connection_info.extra.") - self.assertEqual(msg, exc.format_message()) - - def test_pre_helm_install_invaid_vimconnectioninfo_no_masternode_ip(self): - vim_connection_info = fakes.fake_vim_connection_info_with_extra( - del_field='masternode_ip') - vnf_package_path = self.package_path - instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart() - exc = self.assertRaises(vnfm.InvalidVimConnectionInfo, - self.kubernetes._pre_helm_install, - vim_connection_info, instantiate_vnf_req, - vnf_package_path) - msg = ("Invalid vim_connection_info: " - "content of helm_info is invalid.") - self.assertEqual(msg, exc.format_message()) - - def test_pre_helm_install_invalid_helm_param(self): - vim_connection_info = fakes.fake_vim_connection_info_with_extra() - vnf_package_path = self.package_path - instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( - external=True) - using_helm_inst_params = instantiate_vnf_req.additional_params[ - 'using_helm_install_param'] - del using_helm_inst_params[0]['exthelmchart'] - exc = self.assertRaises(cs.InputValuesMissing, - self.kubernetes._pre_helm_install, - vim_connection_info, instantiate_vnf_req, - vnf_package_path) - msg = ("Parameter input values missing for the key '{param}'".format( - param='exthelmchart')) - self.assertEqual(msg, exc.format_message()) - - def test_pre_helm_install_empty_helm_param(self): - vim_connection_info = fakes.fake_vim_connection_info_with_extra() - vnf_package_path = self.package_path - instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( - external=False, local=False) - exc = self.assertRaises(cs.InputValuesMissing, - self.kubernetes._pre_helm_install, - vim_connection_info, instantiate_vnf_req, - vnf_package_path) - msg = ("Parameter input values missing for the key '{param}'".format( - param='using_helm_install_param')) - self.assertEqual(msg, exc.format_message()) - - def test_pre_helm_install_invalid_chartfile_path(self): - vim_connection_info = fakes.fake_vim_connection_info_with_extra() - vnf_package_path = self.package_path - instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( - external=False) - using_helm_inst_params = instantiate_vnf_req.additional_params[ - 'using_helm_install_param'] - using_helm_inst_params[0]['helmchartfile_path'] = 'invalid_path' - exc = self.assertRaises(vnfm.CnfDefinitionNotFound, - self.kubernetes._pre_helm_install, - vim_connection_info, instantiate_vnf_req, - vnf_package_path) - msg = _("CNF definition file with path {path} is not found " - "in vnf_artifacts.").format( - path=using_helm_inst_params[0]['helmchartfile_path']) - self.assertEqual(msg, exc.format_message()) - - @mock.patch.object(objects.VnfResource, 'create') - @mock.patch.object(paramiko.Transport, 'close') - @mock.patch.object(paramiko.SFTPClient, 'put') - @mock.patch.object(paramiko.SFTPClient, 'from_transport') - @mock.patch.object(paramiko.Transport, 'connect') - @mock.patch.object(helm_client.HelmClient, '_execute_command') - @mock.patch.object(client.AppsV1Api, 'read_namespaced_deployment') - def test_instantiate_vnf_using_helmchart( - self, mock_read_namespaced_deployment, mock_command, - mock_connect, mock_from_transport, mock_put, mock_close, - mock_vnf_resource_create): - vnf_instance = fd_utils.get_vnf_instance_object() - vim_connection_info = fakes.fake_vim_connection_info_with_extra() - deployment_obj = fakes.fake_v1_deployment_for_helm() - mock_read_namespaced_deployment.return_value = deployment_obj - vnfd_dict = fakes.fake_vnf_dict() - instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( - external=False) - grant_response = None - base_hot_dict = None - vnf_package_path = self.package_path - mock_command.side_effect = fakes.execute_cmd_helm_client - result = self.kubernetes.instantiate_vnf( - self.context, vnf_instance, vnfd_dict, vim_connection_info, - instantiate_vnf_req, grant_response, vnf_package_path, - base_hot_dict) - self.assertEqual( - result, - "{'namespace': '', 'name': 'vdu1', " + - "'apiVersion': 'apps/v1', 'kind': 'Deployment', " + - "'status': 'Create_complete'}") - self.assertEqual(mock_read_namespaced_deployment.call_count, 1) - - @mock.patch.object(objects.VnfResource, 'create') - @mock.patch.object(paramiko.Transport, 'close') - @mock.patch.object(paramiko.SFTPClient, 'put') - @mock.patch.object(paramiko.SFTPClient, 'from_transport') - @mock.patch.object(paramiko.Transport, 'connect') - @mock.patch.object(helm_client.HelmClient, '_execute_command') - @mock.patch.object(client.AppsV1Api, 'read_namespaced_deployment') - def test_instantiate_vnf_using_helmchart_with_namespace( - self, mock_read_namespaced_deployment, mock_command, - mock_connect, mock_from_transport, mock_put, mock_close, - mock_vnf_resource_create): - vnf_instance = fd_utils.get_vnf_instance_object() - vim_connection_info = fakes.fake_vim_connection_info_with_extra() - deployment_obj = fakes.fake_v1_deployment_for_helm() - mock_read_namespaced_deployment.return_value = deployment_obj - vnfd_dict = fakes.fake_vnf_dict() - instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( - local=False, namespace='dummy_namespace') - grant_response = None - base_hot_dict = None - vnf_package_path = self.package_path - mock_command.side_effect = fakes.execute_cmd_helm_client - result = self.kubernetes.instantiate_vnf( - self.context, vnf_instance, vnfd_dict, vim_connection_info, - instantiate_vnf_req, grant_response, vnf_package_path, - base_hot_dict) - self.assertEqual( - result, - "{'namespace': 'dummy_namespace', 'name': 'vdu1', " + - "'apiVersion': 'apps/v1', 'kind': 'Deployment', " + - "'status': 'Create_complete'}") - self.assertEqual(mock_read_namespaced_deployment.call_count, 1) - - @mock.patch.object(objects.VnfResource, 'create') - @mock.patch.object(paramiko.Transport, 'close') - @mock.patch.object(paramiko.SFTPClient, 'put') - @mock.patch.object(paramiko.SFTPClient, 'from_transport') - @mock.patch.object(paramiko.Transport, 'connect') - @mock.patch.object(helm_client.HelmClient, '_execute_command') - @mock.patch.object(client.AppsV1Api, 'read_namespaced_deployment') - def test_instantiate_vnf_using_helmchart_multiple_ips( - self, mock_read_namespaced_deployment, mock_command, - mock_connect, mock_from_transport, mock_put, mock_close, - mock_vnf_resource_create): - vnf_instance = fd_utils.get_vnf_instance_object() - vim_connection_info = fakes.fake_vim_connection_info_with_extra( - multi_ip=True) - deployment_obj = fakes.fake_v1_deployment_for_helm() - mock_read_namespaced_deployment.return_value = deployment_obj - vnfd_dict = fakes.fake_vnf_dict() - instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( - external=False) - grant_response = None - base_hot_dict = None - vnf_package_path = self.package_path - mock_command.side_effect = fakes.execute_cmd_helm_client - result = self.kubernetes.instantiate_vnf( - self.context, vnf_instance, vnfd_dict, vim_connection_info, - instantiate_vnf_req, grant_response, vnf_package_path, - base_hot_dict) - self.assertEqual( - result, - "{'namespace': '', 'name': 'vdu1', " + - "'apiVersion': 'apps/v1', 'kind': 'Deployment', " + - "'status': 'Create_complete'}") - self.assertEqual(mock_read_namespaced_deployment.call_count, 1) - - @mock.patch.object(paramiko.Transport, 'close') - @mock.patch.object(paramiko.SFTPClient, 'put') - @mock.patch.object(paramiko.SFTPClient, 'from_transport') - @mock.patch.object(paramiko.Transport, 'connect') - @mock.patch.object(helm_client.HelmClient, '_execute_command') - def test_instantiate_vnf_using_helmchart_put_helmchart_fail( - self, mock_command, - mock_connect, mock_from_transport, mock_put, mock_close): - vnf_instance = fd_utils.get_vnf_instance_object() - vim_connection_info = fakes.fake_vim_connection_info_with_extra() - vnfd_dict = fakes.fake_vnf_dict() - instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( - external=False) - grant_response = None - base_hot_dict = None - vnf_package_path = self.package_path - mock_command.side_effect = fakes.execute_cmd_helm_client - mock_from_transport.side_effect = paramiko.SSHException() - self.assertRaises(paramiko.SSHException, - self.kubernetes.instantiate_vnf, - self.context, vnf_instance, vnfd_dict, vim_connection_info, - instantiate_vnf_req, grant_response, vnf_package_path, - base_hot_dict) - - @mock.patch.object(helm_client.HelmClient, '_execute_command') - @mock.patch.object(client.CoreV1Api, 'list_namespaced_pod') - @mock.patch.object(objects.VnfPackageVnfd, 'get_by_id') - @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') - def test_post_vnf_instantiation_using_helmchart( - self, mock_vnfd_dict, mock_vnf_package_vnfd_get_by_id, - mock_list_namespaced_pod, mock_command): - vim_connection_info = fakes.fake_vim_connection_info_with_extra() - mock_vnfd_dict.return_value = vnflcm_fakes.vnfd_dict_cnf() - mock_vnf_package_vnfd_get_by_id.return_value = \ - vnflcm_fakes.return_vnf_package_vnfd() - mock_list_namespaced_pod.return_value =\ - client.V1PodList(items=[ - fakes.get_fake_pod_info(kind='Deployment', name='vdu1')]) - instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( - external=False) - mock_command.side_effect = fakes.execute_cmd_helm_client - self.kubernetes.post_vnf_instantiation( - context=self.context, - vnf_instance=self.vnf_instance, - vim_connection_info=vim_connection_info, - instantiate_vnf_req=instantiate_vnf_req) - self.assertEqual(mock_list_namespaced_pod.call_count, 1) - # validate stored VnfcResourceInfo - vnfc_resource_info_after = \ - self.vnf_instance.instantiated_vnf_info.vnfc_resource_info - self.assertEqual(len(vnfc_resource_info_after), 1) - expected_pod = fakes.get_fake_pod_info('Deployment', 'vdu1') - self.assertEqual( - vnfc_resource_info_after[0].compute_resource.resource_id, - expected_pod.metadata.name) - self.assertEqual(vnfc_resource_info_after[0].compute_resource. - vim_level_resource_type, 'Deployment') - self.assertEqual(vnfc_resource_info_after[0].vdu_id, 'VDU1') - metadata_after = vnfc_resource_info_after[0].metadata - self.assertEqual(jsonutils.loads( - metadata_after.get('Deployment')).get('name'), 'vdu1') - - @mock.patch.object(helm_client.HelmClient, '_execute_command') - @mock.patch.object(vim_client.VimClient, 'get_vim') - def test_delete_using_helmchart( - self, mock_get_vim, mock_command): - vnf_id = 'fake_vnf_id' - mock_get_vim.return_value = fakes.fake_k8s_vim_obj() - vim_connection_info = fakes.fake_vim_connection_info_with_extra() - instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( - external=False) - vnf_instance = copy.deepcopy(self.vnf_instance) - vnf_instance.vim_connection_info = [vim_connection_info] - vnf_instance.instantiated_vnf_info.additional_params = \ - instantiate_vnf_req.additional_params - terminate_vnf_req = objects.TerminateVnfRequest() - mock_command.side_effect = fakes.execute_cmd_helm_client - self.kubernetes.delete(plugin=None, context=self.context, - vnf_id=vnf_id, - auth_attr=utils.get_vim_auth_obj(), - vnf_instance=vnf_instance, - terminate_vnf_req=terminate_vnf_req) - - @mock.patch.object(helm_client.HelmClient, '_execute_command') - @mock.patch.object(vim_client.VimClient, 'get_vim') - def test_delete_using_helmchart_with_namespace( - self, mock_get_vim, mock_command): - vnf_id = 'fake_vnf_id' - mock_get_vim.return_value = fakes.fake_k8s_vim_obj() - vim_connection_info = fakes.fake_vim_connection_info_with_extra() - instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( - local=False, namespace='dummy_namespace') - vnf_instance = copy.deepcopy(self.vnf_instance) - vnf_instance.vim_connection_info = [vim_connection_info] - vnf_instance.instantiated_vnf_info.additional_params = \ - instantiate_vnf_req.additional_params - terminate_vnf_req = objects.TerminateVnfRequest() - mock_command.side_effect = fakes.execute_cmd_helm_client - self.kubernetes.delete(plugin=None, context=self.context, - vnf_id=vnf_id, - auth_attr=utils.get_vim_auth_obj(), - vnf_instance=vnf_instance, - terminate_vnf_req=terminate_vnf_req) - - @mock.patch.object(helm_client.HelmClient, '_execute_command') - @mock.patch.object(vim_client.VimClient, 'get_vim') - @mock.patch.object(client.AppsV1Api, 'read_namespaced_deployment') - @mock.patch.object(objects.VnfResourceList, 'get_by_vnf_instance_id') - def test_delete_wait_using_helmchart( - self, mock_vnf_resource_list, mock_read_namespaced_deployment, - mock_get_vim, mock_command): - vnf_id = 'fake_vnf_id' - mock_get_vim.return_value = fakes.fake_k8s_vim_obj() - vim_connection_info = fakes.fake_vim_connection_info_with_extra() - instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( - external=False) - vnf_instance = copy.deepcopy(self.vnf_instance) - vnf_instance.vim_connection_info = [vim_connection_info] - vnf_instance.instantiated_vnf_info.additional_params = \ - instantiate_vnf_req.additional_params - vnf_resource = models.VnfResource() - vnf_resource.vnf_instance_id = vnf_instance.id - vnf_resource.resource_name = 'default,vdu1' - vnf_resource.resource_type = 'apps/v1,Deployment' - mock_vnf_resource_list.return_value = [vnf_resource] - mock_command.side_effect = fakes.execute_cmd_helm_client - self.kubernetes.delete_wait(plugin=None, context=self.context, - vnf_id=vnf_id, - auth_attr=utils.get_vim_auth_obj(), - region_name=None, - vnf_instance=vnf_instance) - self.assertEqual(mock_read_namespaced_deployment.call_count, 1) - - @mock.patch.object(helm_client.HelmClient, '_execute_command') - @mock.patch.object(vim_client.VimClient, 'get_vim') - @mock.patch.object(client.AppsV1Api, 'read_namespaced_deployment') - @mock.patch.object(objects.VnfResourceList, 'get_by_vnf_instance_id') - def test_delete_wait_using_helmchart_unknown_apiversion( - self, mock_vnf_resource_list, mock_read_namespaced_deployment, - mock_get_vim, mock_command): - vnf_id = 'fake_vnf_id' - mock_get_vim.return_value = fakes.fake_k8s_vim_obj() - vim_connection_info = fakes.fake_vim_connection_info_with_extra() - instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( - local=False) - vnf_instance = copy.deepcopy(self.vnf_instance) - vnf_instance.vim_connection_info = [vim_connection_info] - vnf_instance.instantiated_vnf_info.additional_params = \ - instantiate_vnf_req.additional_params - vnf_resource = models.VnfResource() - vnf_resource.vnf_instance_id = vnf_instance.id - vnf_resource.resource_name = 'default,vdu1' - vnf_resource.resource_type = 'apps/v1unknown,Deployment' - mock_vnf_resource_list.return_value = [vnf_resource] - mock_command.side_effect = fakes.execute_cmd_helm_client - self.kubernetes.delete_wait(plugin=None, context=self.context, - vnf_id=vnf_id, - auth_attr=utils.get_vim_auth_obj(), - region_name=None, - vnf_instance=vnf_instance) - self.assertEqual(mock_read_namespaced_deployment.call_count, 0) +# 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. + +import copy +import eventlet +import os +import paramiko + +from ddt import ddt +from kubernetes import client +from oslo_serialization import jsonutils +from tacker import context +from tacker.db.db_sqlalchemy import models +from tacker.extensions import common_services as cs +from tacker.extensions import vnfm +from tacker import objects +from tacker.tests.unit import base +from tacker.tests.unit.db import utils +from tacker.tests.unit.vnflcm import fakes as vnflcm_fakes +from tacker.tests.unit.vnfm.infra_drivers.kubernetes import fakes +from tacker.tests.unit.vnfm.infra_drivers.openstack.fixture_data import \ + fixture_data_utils as fd_utils +from tacker.vnfm.infra_drivers.kubernetes.helm import helm_client +from tacker.vnfm.infra_drivers.kubernetes import kubernetes_driver +from tacker.vnfm import vim_client +from unittest import mock + + +class FakeRemoteCommandExecutor(mock.Mock): + def close_session(self): + return + + +class FakeCommander(mock.Mock): + def config(self, is_success, errmsg=None): + self.is_success = is_success + self.errmsg = errmsg + + def execute_command(self, *args, **kwargs): + is_success = self.is_success + fake_result = FakeCmdResult() + stderr = '' + stdout = '' + return_code = (0) if is_success else (1) + stderr, stdout = ('', '') if is_success else ('err', '') + if self.errmsg: + stderr = [self.errmsg] + fake_result.set_std(stderr, stdout, return_code) + return fake_result + + +class FakeCmdResult(mock.Mock): + def set_std(self, stderr, stdout, return_code): + self.stderr = stderr + self.stdout = stdout + self.return_code = return_code + + def get_stderr(self): + return self.stderr + + def get_stdout(self): + return self.stdout + + def get_return_code(self): + return self.return_code + + +class FakeTransport(mock.Mock): + pass + + +@ddt +class TestKubernetesHelm(base.TestCase): + def setUp(self): + super(TestKubernetesHelm, self).setUp() + self.kubernetes = kubernetes_driver.Kubernetes() + self.kubernetes.STACK_RETRIES = 1 + self.kubernetes.STACK_RETRY_WAIT = 5 + self.k8s_client_dict = fakes.fake_k8s_client_dict() + self.context = context.get_admin_context() + self.vnf_instance = fd_utils.get_vnf_instance_object() + self.package_path = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "../../../../etc/samples/etsi/nfv/test_cnf_helmchart") + self._mock_remote_command_executor() + self._mock_transport() + self.helm_client = helm_client.HelmClient('127.0.0.1', 'user', 'pass') + self.helm_client.commander = FakeCommander() + + def _mock_remote_command_executor(self): + self.commander = mock.Mock(wraps=FakeRemoteCommandExecutor()) + fake_commander = mock.Mock() + fake_commander.return_value = self.commander + self._mock( + 'tacker.common.cmd_executer.RemoteCommandExecutor', + fake_commander) + + def _mock_transport(self): + self.transport = mock.Mock(wraps=FakeTransport()) + fake_transport = mock.Mock() + fake_transport.return_value = self.transport + self._mock('paramiko.Transport', fake_transport) + + def _mock(self, target, new=mock.DEFAULT): + patcher = mock.patch(target, new) + return patcher.start() + + @mock.patch.object(eventlet, 'monkey_patch') + def test_execute_command_success(self, mock_monkey_patch): + self.helm_client.commander.config(True) + ssh_command = 'helm install' + timeout = 120 + retry = 1 + self.helm_client._execute_command( + ssh_command, timeout, retry) + + @mock.patch.object(eventlet, 'monkey_patch') + def test_execute_command_failed(self, mock_monkey_patch): + self.helm_client.commander.config(False) + ssh_command = 'helm install' + timeout = 120 + retry = 1 + self.assertRaises(vnfm.HelmClientRemoteCommandError, + self.helm_client._execute_command, + ssh_command, timeout, retry) + + @mock.patch.object(eventlet, 'monkey_patch') + @mock.patch.object(FakeCommander, 'execute_command') + def test_execute_command_timeout(self, mock_execute_command, + mock_monkey_patch): + mock_execute_command.side_effect = eventlet.timeout.Timeout + ssh_command = 'helm install' + timeout = 120 + retry = 1 + self.assertRaises(vnfm.HelmClientOtherError, + self.helm_client._execute_command, + ssh_command, timeout, retry) + + @mock.patch('tacker.objects.vnf_instance.VnfInstance.save') + def test_pre_instantiation_vnf_helm(self, mock_save): + vnf_instance = fd_utils.get_vnf_instance_object() + vim_connection_info = fakes.fake_vim_connection_info_with_extra() + vnf_software_images = None + vnf_package_path = self.package_path + instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart() + vnf_resources = self.kubernetes.pre_instantiation_vnf( + self.context, vnf_instance, vim_connection_info, + vnf_software_images, + instantiate_vnf_req, vnf_package_path) + self.assertEqual(vnf_resources, {}) + + @mock.patch('tacker.objects.vnf_instance.VnfInstance.save') + def test_pre_helm_install_with_bool_param(self, mock_save): + vnf_instance = fd_utils.get_vnf_instance_object() + vim_connection_info = fakes.fake_vim_connection_info_with_extra() + vnf_software_images = None + vnf_package_path = self.package_path + instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart() + instantiate_vnf_req.additional_params['use_helm'] = True + using_helm_inst_params = instantiate_vnf_req.additional_params[ + 'using_helm_install_param'] + using_helm_inst_params[0]['exthelmchart'] = True + using_helm_inst_params[1]['exthelmchart'] = False + vnf_resources = self.kubernetes.pre_instantiation_vnf( + self.context, vnf_instance, vim_connection_info, + vnf_software_images, + instantiate_vnf_req, vnf_package_path) + self.assertEqual(vnf_resources, {}) + + def test_pre_helm_install_invaid_vimconnectioninfo_no_helm_info(self): + vim_connection_info = fakes.fake_vim_connection_info_with_extra() + del vim_connection_info.extra['helm_info'] + vnf_package_path = self.package_path + instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart() + exc = self.assertRaises(vnfm.InvalidVimConnectionInfo, + self.kubernetes._pre_helm_install, + vim_connection_info, instantiate_vnf_req, + vnf_package_path) + msg = ("Invalid vim_connection_info: " + "helm_info is missing in vim_connection_info.extra.") + self.assertEqual(msg, exc.format_message()) + + def test_pre_helm_install_invaid_vimconnectioninfo_no_masternode_ip(self): + vim_connection_info = fakes.fake_vim_connection_info_with_extra( + del_field='masternode_ip') + vnf_package_path = self.package_path + instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart() + exc = self.assertRaises(vnfm.InvalidVimConnectionInfo, + self.kubernetes._pre_helm_install, + vim_connection_info, instantiate_vnf_req, + vnf_package_path) + msg = ("Invalid vim_connection_info: " + "content of helm_info is invalid.") + self.assertEqual(msg, exc.format_message()) + + def test_pre_helm_install_invalid_helm_param(self): + vim_connection_info = fakes.fake_vim_connection_info_with_extra() + vnf_package_path = self.package_path + instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( + external=True) + using_helm_inst_params = instantiate_vnf_req.additional_params[ + 'using_helm_install_param'] + del using_helm_inst_params[0]['exthelmchart'] + exc = self.assertRaises(cs.InputValuesMissing, + self.kubernetes._pre_helm_install, + vim_connection_info, instantiate_vnf_req, + vnf_package_path) + msg = ("Parameter input values missing for the key '{param}'".format( + param='exthelmchart')) + self.assertEqual(msg, exc.format_message()) + + def test_pre_helm_install_empty_helm_param(self): + vim_connection_info = fakes.fake_vim_connection_info_with_extra() + vnf_package_path = self.package_path + instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( + external=False, local=False) + exc = self.assertRaises(cs.InputValuesMissing, + self.kubernetes._pre_helm_install, + vim_connection_info, instantiate_vnf_req, + vnf_package_path) + msg = ("Parameter input values missing for the key '{param}'".format( + param='using_helm_install_param')) + self.assertEqual(msg, exc.format_message()) + + def test_pre_helm_install_invalid_chartfile_path(self): + vim_connection_info = fakes.fake_vim_connection_info_with_extra() + vnf_package_path = self.package_path + instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( + external=False) + using_helm_inst_params = instantiate_vnf_req.additional_params[ + 'using_helm_install_param'] + using_helm_inst_params[0]['helmchartfile_path'] = 'invalid_path' + exc = self.assertRaises(vnfm.CnfDefinitionNotFound, + self.kubernetes._pre_helm_install, + vim_connection_info, instantiate_vnf_req, + vnf_package_path) + msg = _("CNF definition file with path {path} is not found " + "in vnf_artifacts.").format( + path=using_helm_inst_params[0]['helmchartfile_path']) + self.assertEqual(msg, exc.format_message()) + + @mock.patch.object(objects.VnfResource, 'create') + @mock.patch.object(paramiko.Transport, 'close') + @mock.patch.object(paramiko.SFTPClient, 'put') + @mock.patch.object(paramiko.SFTPClient, 'from_transport') + @mock.patch.object(paramiko.Transport, 'connect') + @mock.patch.object(helm_client.HelmClient, '_execute_command') + @mock.patch.object(client.AppsV1Api, 'read_namespaced_deployment') + def test_instantiate_vnf_using_helmchart( + self, mock_read_namespaced_deployment, mock_command, + mock_connect, mock_from_transport, mock_put, mock_close, + mock_vnf_resource_create): + vnf_instance = fd_utils.get_vnf_instance_object() + vim_connection_info = fakes.fake_vim_connection_info_with_extra() + deployment_obj = fakes.fake_v1_deployment_for_helm() + mock_read_namespaced_deployment.return_value = deployment_obj + vnfd_dict = fakes.fake_vnf_dict() + instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( + external=False) + grant_response = None + base_hot_dict = None + vnf_package_path = self.package_path + mock_command.side_effect = fakes.execute_cmd_helm_client + result = self.kubernetes.instantiate_vnf( + self.context, vnf_instance, vnfd_dict, vim_connection_info, + instantiate_vnf_req, grant_response, vnf_package_path, + base_hot_dict) + self.assertEqual( + result, + "{'namespace': 'default', 'name': 'vdu1', " + + "'apiVersion': 'apps/v1', 'kind': 'Deployment', " + + "'status': 'Create_complete'}") + self.assertEqual(mock_read_namespaced_deployment.call_count, 1) + + @mock.patch.object(objects.VnfResource, 'create') + @mock.patch.object(paramiko.Transport, 'close') + @mock.patch.object(paramiko.SFTPClient, 'put') + @mock.patch.object(paramiko.SFTPClient, 'from_transport') + @mock.patch.object(paramiko.Transport, 'connect') + @mock.patch.object(helm_client.HelmClient, '_execute_command') + @mock.patch.object(client.AppsV1Api, 'read_namespaced_deployment') + def test_instantiate_vnf_using_helmchart_with_namespace( + self, mock_read_namespaced_deployment, mock_command, + mock_connect, mock_from_transport, mock_put, mock_close, + mock_vnf_resource_create): + vnf_instance = fd_utils.get_vnf_instance_object() + vnf_instance.vnf_metadata['namespace'] = 'dummy_namespace' + vim_connection_info = fakes.fake_vim_connection_info_with_extra() + deployment_obj = fakes.fake_v1_deployment_for_helm() + mock_read_namespaced_deployment.return_value = deployment_obj + vnfd_dict = fakes.fake_vnf_dict() + instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( + local=False, namespace='dummy_namespace') + grant_response = None + base_hot_dict = None + vnf_package_path = self.package_path + mock_command.side_effect = fakes.execute_cmd_helm_client + result = self.kubernetes.instantiate_vnf( + self.context, vnf_instance, vnfd_dict, vim_connection_info, + instantiate_vnf_req, grant_response, vnf_package_path, + base_hot_dict) + self.assertEqual( + result, + "{'namespace': 'dummy_namespace', 'name': 'vdu1', " + + "'apiVersion': 'apps/v1', 'kind': 'Deployment', " + + "'status': 'Create_complete'}") + self.assertEqual(mock_read_namespaced_deployment.call_count, 1) + + @mock.patch.object(objects.VnfResource, 'create') + @mock.patch.object(paramiko.Transport, 'close') + @mock.patch.object(paramiko.SFTPClient, 'put') + @mock.patch.object(paramiko.SFTPClient, 'from_transport') + @mock.patch.object(paramiko.Transport, 'connect') + @mock.patch.object(helm_client.HelmClient, '_execute_command') + @mock.patch.object(client.AppsV1Api, 'read_namespaced_deployment') + def test_instantiate_vnf_using_helmchart_multiple_ips( + self, mock_read_namespaced_deployment, mock_command, + mock_connect, mock_from_transport, mock_put, mock_close, + mock_vnf_resource_create): + vnf_instance = fd_utils.get_vnf_instance_object() + vim_connection_info = fakes.fake_vim_connection_info_with_extra( + multi_ip=True) + deployment_obj = fakes.fake_v1_deployment_for_helm() + mock_read_namespaced_deployment.return_value = deployment_obj + vnfd_dict = fakes.fake_vnf_dict() + instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( + external=False) + grant_response = None + base_hot_dict = None + vnf_package_path = self.package_path + mock_command.side_effect = fakes.execute_cmd_helm_client + result = self.kubernetes.instantiate_vnf( + self.context, vnf_instance, vnfd_dict, vim_connection_info, + instantiate_vnf_req, grant_response, vnf_package_path, + base_hot_dict) + self.assertEqual( + result, + "{'namespace': 'default', 'name': 'vdu1', " + + "'apiVersion': 'apps/v1', 'kind': 'Deployment', " + + "'status': 'Create_complete'}") + self.assertEqual(mock_read_namespaced_deployment.call_count, 1) + + @mock.patch.object(paramiko.Transport, 'close') + @mock.patch.object(paramiko.SFTPClient, 'put') + @mock.patch.object(paramiko.SFTPClient, 'from_transport') + @mock.patch.object(paramiko.Transport, 'connect') + @mock.patch.object(helm_client.HelmClient, '_execute_command') + def test_instantiate_vnf_using_helmchart_put_helmchart_fail( + self, mock_command, + mock_connect, mock_from_transport, mock_put, mock_close): + vnf_instance = fd_utils.get_vnf_instance_object() + vim_connection_info = fakes.fake_vim_connection_info_with_extra() + vnfd_dict = fakes.fake_vnf_dict() + instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( + external=False) + grant_response = None + base_hot_dict = None + vnf_package_path = self.package_path + mock_command.side_effect = fakes.execute_cmd_helm_client + mock_from_transport.side_effect = paramiko.SSHException() + self.assertRaises(paramiko.SSHException, + self.kubernetes.instantiate_vnf, + self.context, vnf_instance, vnfd_dict, vim_connection_info, + instantiate_vnf_req, grant_response, vnf_package_path, + base_hot_dict) + + @mock.patch.object(helm_client.HelmClient, '_execute_command') + @mock.patch.object(client.CoreV1Api, 'list_namespaced_pod') + @mock.patch.object(objects.VnfPackageVnfd, 'get_by_id') + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + def test_post_vnf_instantiation_using_helmchart( + self, mock_vnfd_dict, mock_vnf_package_vnfd_get_by_id, + mock_list_namespaced_pod, mock_command): + vim_connection_info = fakes.fake_vim_connection_info_with_extra() + mock_vnfd_dict.return_value = vnflcm_fakes.vnfd_dict_cnf() + mock_vnf_package_vnfd_get_by_id.return_value = \ + vnflcm_fakes.return_vnf_package_vnfd() + mock_list_namespaced_pod.return_value =\ + client.V1PodList(items=[ + fakes.get_fake_pod_info(kind='Deployment', name='vdu1')]) + instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( + external=False) + mock_command.side_effect = fakes.execute_cmd_helm_client + self.kubernetes.post_vnf_instantiation( + context=self.context, + vnf_instance=self.vnf_instance, + vim_connection_info=vim_connection_info, + instantiate_vnf_req=instantiate_vnf_req) + self.assertEqual(mock_list_namespaced_pod.call_count, 1) + # validate stored VnfcResourceInfo + vnfc_resource_info_after = \ + self.vnf_instance.instantiated_vnf_info.vnfc_resource_info + self.assertEqual(len(vnfc_resource_info_after), 1) + expected_pod = fakes.get_fake_pod_info('Deployment', 'vdu1') + self.assertEqual( + vnfc_resource_info_after[0].compute_resource.resource_id, + expected_pod.metadata.name) + self.assertEqual(vnfc_resource_info_after[0].compute_resource. + vim_level_resource_type, 'Deployment') + self.assertEqual(vnfc_resource_info_after[0].vdu_id, 'VDU1') + metadata_after = vnfc_resource_info_after[0].metadata + self.assertEqual(jsonutils.loads( + metadata_after.get('Deployment')).get('name'), 'vdu1') + + @mock.patch.object(helm_client.HelmClient, '_execute_command') + @mock.patch.object(vim_client.VimClient, 'get_vim') + def test_delete_using_helmchart( + self, mock_get_vim, mock_command): + vnf_id = 'fake_vnf_id' + mock_get_vim.return_value = fakes.fake_k8s_vim_obj() + vim_connection_info = fakes.fake_vim_connection_info_with_extra() + instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( + external=False) + vnf_instance = copy.deepcopy(self.vnf_instance) + vnf_instance.vim_connection_info = [vim_connection_info] + vnf_instance.instantiated_vnf_info.additional_params = \ + instantiate_vnf_req.additional_params + terminate_vnf_req = objects.TerminateVnfRequest() + mock_command.side_effect = fakes.execute_cmd_helm_client + self.kubernetes.delete(plugin=None, context=self.context, + vnf_id=vnf_id, + auth_attr=utils.get_vim_auth_obj(), + vnf_instance=vnf_instance, + terminate_vnf_req=terminate_vnf_req) + + @mock.patch.object(helm_client.HelmClient, '_execute_command') + @mock.patch.object(vim_client.VimClient, 'get_vim') + def test_delete_using_helmchart_with_namespace( + self, mock_get_vim, mock_command): + vnf_id = 'fake_vnf_id' + mock_get_vim.return_value = fakes.fake_k8s_vim_obj() + vim_connection_info = fakes.fake_vim_connection_info_with_extra() + instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( + local=False, namespace='dummy_namespace') + vnf_instance = copy.deepcopy(self.vnf_instance) + vnf_instance.vim_connection_info = [vim_connection_info] + vnf_instance.instantiated_vnf_info.additional_params = \ + instantiate_vnf_req.additional_params + terminate_vnf_req = objects.TerminateVnfRequest() + mock_command.side_effect = fakes.execute_cmd_helm_client + self.kubernetes.delete(plugin=None, context=self.context, + vnf_id=vnf_id, + auth_attr=utils.get_vim_auth_obj(), + vnf_instance=vnf_instance, + terminate_vnf_req=terminate_vnf_req) + + @mock.patch.object(helm_client.HelmClient, '_execute_command') + @mock.patch.object(vim_client.VimClient, 'get_vim') + @mock.patch.object(client.AppsV1Api, 'read_namespaced_deployment') + @mock.patch.object(objects.VnfResourceList, 'get_by_vnf_instance_id') + def test_delete_wait_using_helmchart( + self, mock_vnf_resource_list, mock_read_namespaced_deployment, + mock_get_vim, mock_command): + vnf_id = 'fake_vnf_id' + mock_get_vim.return_value = fakes.fake_k8s_vim_obj() + vim_connection_info = fakes.fake_vim_connection_info_with_extra() + instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( + external=False) + vnf_instance = copy.deepcopy(self.vnf_instance) + vnf_instance.vim_connection_info = [vim_connection_info] + vnf_instance.instantiated_vnf_info.additional_params = \ + instantiate_vnf_req.additional_params + vnf_resource = models.VnfResource() + vnf_resource.vnf_instance_id = vnf_instance.id + vnf_resource.resource_name = 'default,vdu1' + vnf_resource.resource_type = 'apps/v1,Deployment' + mock_vnf_resource_list.return_value = [vnf_resource] + mock_command.side_effect = fakes.execute_cmd_helm_client + self.kubernetes.delete_wait(plugin=None, context=self.context, + vnf_id=vnf_id, + auth_attr=utils.get_vim_auth_obj(), + region_name=None, + vnf_instance=vnf_instance) + self.assertEqual(mock_read_namespaced_deployment.call_count, 1) + + @mock.patch.object(helm_client.HelmClient, '_execute_command') + @mock.patch.object(vim_client.VimClient, 'get_vim') + @mock.patch.object(client.AppsV1Api, 'read_namespaced_deployment') + @mock.patch.object(objects.VnfResourceList, 'get_by_vnf_instance_id') + def test_delete_wait_using_helmchart_unknown_apiversion( + self, mock_vnf_resource_list, mock_read_namespaced_deployment, + mock_get_vim, mock_command): + vnf_id = 'fake_vnf_id' + mock_get_vim.return_value = fakes.fake_k8s_vim_obj() + vim_connection_info = fakes.fake_vim_connection_info_with_extra() + instantiate_vnf_req = fakes.fake_inst_vnf_req_for_helmchart( + local=False) + vnf_instance = copy.deepcopy(self.vnf_instance) + vnf_instance.vim_connection_info = [vim_connection_info] + vnf_instance.instantiated_vnf_info.additional_params = \ + instantiate_vnf_req.additional_params + vnf_resource = models.VnfResource() + vnf_resource.vnf_instance_id = vnf_instance.id + vnf_resource.resource_name = 'default,vdu1' + vnf_resource.resource_type = 'apps/v1unknown,Deployment' + mock_vnf_resource_list.return_value = [vnf_resource] + mock_command.side_effect = fakes.execute_cmd_helm_client + self.kubernetes.delete_wait(plugin=None, context=self.context, + vnf_id=vnf_id, + auth_attr=utils.get_vim_auth_obj(), + region_name=None, + vnf_instance=vnf_instance) + self.assertEqual(mock_read_namespaced_deployment.call_count, 0) diff --git a/tacker/tests/unit/vnfm/infra_drivers/kubernetes/test_translate_outputs.py b/tacker/tests/unit/vnfm/infra_drivers/kubernetes/test_translate_outputs.py index 132b10d81..e50099b30 100644 --- a/tacker/tests/unit/vnfm/infra_drivers/kubernetes/test_translate_outputs.py +++ b/tacker/tests/unit/vnfm/infra_drivers/kubernetes/test_translate_outputs.py @@ -62,7 +62,7 @@ class TestTransformer(base.TestCase): def test_deployment(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['deployment.yaml'], self.yaml_path) + ['deployment.yaml'], self.yaml_path, '') k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) self.assertEqual(k8s_objs[0].get('namespace'), '') @@ -83,7 +83,7 @@ class TestTransformer(base.TestCase): def test_api_service(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['api-service.yaml'], self.yaml_path + ['api-service.yaml'], self.yaml_path, '' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -97,7 +97,7 @@ class TestTransformer(base.TestCase): def test_cluster_role(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['cluster-role.yaml'], self.yaml_path + ['cluster-role.yaml'], self.yaml_path, '' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -109,7 +109,7 @@ class TestTransformer(base.TestCase): def test_cluster_role_binding(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['cluster-role-binding.yaml'], self.yaml_path + ['cluster-role-binding.yaml'], self.yaml_path, '' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -129,7 +129,7 @@ class TestTransformer(base.TestCase): def test_config_map(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['config-map.yaml'], self.yaml_path + ['config-map.yaml'], self.yaml_path, 'curryns' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -139,7 +139,7 @@ class TestTransformer(base.TestCase): def test_daemon_set(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['daemon-set.yaml'], self.yaml_path + ['daemon-set.yaml'], self.yaml_path, '' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -160,7 +160,7 @@ class TestTransformer(base.TestCase): def test_horizontal_pod_autoscaler(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['horizontal-pod-autoscaler.yaml'], self.yaml_path + ['horizontal-pod-autoscaler.yaml'], self.yaml_path, 'default' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -180,7 +180,7 @@ class TestTransformer(base.TestCase): def test_job(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['job.yaml'], self.yaml_path + ['job.yaml'], self.yaml_path, '' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -195,7 +195,7 @@ class TestTransformer(base.TestCase): def test_lease(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['lease.yaml'], self.yaml_path + ['lease.yaml'], self.yaml_path, 'default' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -205,7 +205,7 @@ class TestTransformer(base.TestCase): def test_local_subject_access_review(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['local-subject-access-review.yaml'], self.yaml_path + ['local-subject-access-review.yaml'], self.yaml_path, 'curry-ns' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -216,7 +216,7 @@ class TestTransformer(base.TestCase): def test_namespace(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['namespace.yaml'], self.yaml_path + ['namespace.yaml'], self.yaml_path, '' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -230,7 +230,7 @@ class TestTransformer(base.TestCase): def test_network_policy(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['network-policy.yaml'], self.yaml_path + ['network-policy.yaml'], self.yaml_path, '' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -246,7 +246,7 @@ class TestTransformer(base.TestCase): def test_node(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['node.yaml'], self.yaml_path + ['node.yaml'], self.yaml_path, '' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -293,7 +293,7 @@ class TestTransformer(base.TestCase): def test_persistent_volume(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['persistent-volume.yaml'], self.yaml_path + ['persistent-volume.yaml'], self.yaml_path, '' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -345,7 +345,7 @@ class TestTransformer(base.TestCase): def test_persistent_volume_claim(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['persistent-volume-claim.yaml'], self.yaml_path + ['persistent-volume-claim.yaml'], self.yaml_path, '' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -364,7 +364,7 @@ class TestTransformer(base.TestCase): def test_pod(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['pod.yaml'], self.yaml_path + ['pod.yaml'], self.yaml_path, '' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -479,7 +479,7 @@ class TestTransformer(base.TestCase): def test_priority_class(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['priority-class.yaml'], self.yaml_path + ['priority-class.yaml'], self.yaml_path, '' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -491,7 +491,7 @@ class TestTransformer(base.TestCase): def test_replica_set(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['replica-set.yaml'], self.yaml_path + ['replica-set.yaml'], self.yaml_path, '' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -510,7 +510,7 @@ class TestTransformer(base.TestCase): def test_resource_quota(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['resource-quota.yaml'], self.yaml_path + ['resource-quota.yaml'], self.yaml_path, 'curryns' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -525,7 +525,7 @@ class TestTransformer(base.TestCase): def test_role(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['role.yaml'], self.yaml_path + ['role.yaml'], self.yaml_path, 'curry-ns' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -535,7 +535,7 @@ class TestTransformer(base.TestCase): def test_role_binding(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['role-bindings.yaml'], self.yaml_path + ['role-bindings.yaml'], self.yaml_path, 'curry-ns' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -547,7 +547,7 @@ class TestTransformer(base.TestCase): def test_secret(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['secret.yaml'], self.yaml_path + ['secret.yaml'], self.yaml_path, 'default' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -557,7 +557,7 @@ class TestTransformer(base.TestCase): def test_self_subject_access_review(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['self-subject-access-review.yaml'], self.yaml_path + ['self-subject-access-review.yaml'], self.yaml_path, '' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -569,7 +569,7 @@ class TestTransformer(base.TestCase): def test_self_subject_rules_review(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['self-subject-rule-review.yaml'], self.yaml_path + ['self-subject-rule-review.yaml'], self.yaml_path, '' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -589,7 +589,7 @@ class TestTransformer(base.TestCase): def test_service(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['service.yaml'], self.yaml_path + ['service.yaml'], self.yaml_path, 'default' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -601,7 +601,7 @@ class TestTransformer(base.TestCase): def test_service_account(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['service-account.yaml'], self.yaml_path + ['service-account.yaml'], self.yaml_path, 'default' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -611,7 +611,7 @@ class TestTransformer(base.TestCase): def test_stateful_set(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['stateful-set.yaml'], self.yaml_path + ['stateful-set.yaml'], self.yaml_path, '' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -630,7 +630,7 @@ class TestTransformer(base.TestCase): def test_storage_class(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['storage-class.yaml'], self.yaml_path + ['storage-class.yaml'], self.yaml_path, '' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -649,7 +649,7 @@ class TestTransformer(base.TestCase): def test_subject_access_review(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['subject-access-review.yaml'], self.yaml_path + ['subject-access-review.yaml'], self.yaml_path, '' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -663,7 +663,7 @@ class TestTransformer(base.TestCase): def test_token_review(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['token-review.yaml'], self.yaml_path + ['token-review.yaml'], self.yaml_path, '' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -675,7 +675,7 @@ class TestTransformer(base.TestCase): def test_limit_range(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['limit-range.yaml'], self.yaml_path + ['limit-range.yaml'], self.yaml_path, 'curryns' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -688,7 +688,7 @@ class TestTransformer(base.TestCase): def test_pod_template(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['pod-template.yaml'], self.yaml_path + ['pod-template.yaml'], self.yaml_path, 'curryns' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -812,7 +812,7 @@ class TestTransformer(base.TestCase): def test_volume_attachment(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['volume-attachment.yaml'], self.yaml_path + ['volume-attachment.yaml'], self.yaml_path, 'curryns' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -830,7 +830,7 @@ class TestTransformer(base.TestCase): def test_bindings(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['bindings.yaml'], self.yaml_path + ['bindings.yaml'], self.yaml_path, 'curryns' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) @@ -842,7 +842,7 @@ class TestTransformer(base.TestCase): def test_controller_revision(self): k8s_objs = self.transfromer.get_k8s_objs_from_yaml( - ['controller-revision.yaml'], self.yaml_path + ['controller-revision.yaml'], self.yaml_path, 'curryns' ) k8s_obj = k8s_objs[0].get('object') self.assertIsNotNone(k8s_obj) diff --git a/tacker/tests/unit/vnfm/infra_drivers/kubernetes/test_utils.py b/tacker/tests/unit/vnfm/infra_drivers/kubernetes/test_utils.py new file mode 100644 index 000000000..6870e1491 --- /dev/null +++ b/tacker/tests/unit/vnfm/infra_drivers/kubernetes/test_utils.py @@ -0,0 +1,69 @@ +# 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. + +from tacker.common import exceptions +from tacker import objects +from tacker.tests.unit import base +from tacker.tests.unit.vnfm.infra_drivers.openstack.fixture_data import \ + fixture_data_utils as fd_utils +from tacker.vnfm.infra_drivers.kubernetes import utils as k8s_utils +from unittest import mock + + +class KubernetesUtilsTestCase(base.TestCase): + + @mock.patch('tacker.objects.vnf_instance.VnfInstance.save') + def test_check_and_save_namespace_multi_namespace(self, mock_save): + instantiate_vnf_req = objects.InstantiateVnfRequest( + additional_params=None) + chk_namespaces = [{"namespace": "a", "kind": "CronJob"}, + {"namespace": "b", "kind": "Deployment"}, + {"namespace": "c", "kind": "Service"}] + vnf_instance = fd_utils.get_vnf_instance_object() + + self.assertRaises( + exceptions.NamespaceIsNotUnique, + k8s_utils.check_and_save_namespace, None, instantiate_vnf_req, + chk_namespaces, vnf_instance) + + @mock.patch('tacker.objects.vnf_instance.VnfInstance.save') + def test_check_and_save_namespace_no_namespace(self, mock_save): + instantiate_vnf_req = objects.InstantiateVnfRequest( + additional_params=None) + chk_namespaces = [] + vnf_instance = fd_utils.get_vnf_instance_object() + vnf_instance.vnf_metadata['namespace'] = '' + k8s_utils.check_and_save_namespace( + None, instantiate_vnf_req, chk_namespaces, vnf_instance) + self.assertEqual('default', vnf_instance.vnf_metadata['namespace']) + + @mock.patch('tacker.objects.vnf_instance.VnfInstance.save') + def test_check_and_save_namespace_additional_params(self, mock_save): + instantiate_vnf_req = objects.InstantiateVnfRequest( + additional_params={'namespace': 'ns1'}) + chk_namespaces = [] + vnf_instance = fd_utils.get_vnf_instance_object() + vnf_instance.vnf_metadata['namespace'] = '' + k8s_utils.check_and_save_namespace( + None, instantiate_vnf_req, chk_namespaces, vnf_instance) + self.assertEqual('ns1', vnf_instance.vnf_metadata['namespace']) + + @mock.patch('tacker.objects.vnf_instance.VnfInstance.save') + def test_check_and_save_namespace_manifests(self, mock_save): + instantiate_vnf_req = objects.InstantiateVnfRequest( + additional_params=None) + chk_namespaces = [{"namespace": "ns2", "kind": "Deployment"}] + vnf_instance = fd_utils.get_vnf_instance_object() + vnf_instance.vnf_metadata = {} + k8s_utils.check_and_save_namespace( + None, instantiate_vnf_req, chk_namespaces, vnf_instance) + self.assertEqual('ns2', vnf_instance.vnf_metadata['namespace']) diff --git a/tacker/tests/unit/vnfm/infra_drivers/openstack/fixture_data/fixture_data_utils.py b/tacker/tests/unit/vnfm/infra_drivers/openstack/fixture_data/fixture_data_utils.py index 95d2d38c0..1eecf388d 100644 --- a/tacker/tests/unit/vnfm/infra_drivers/openstack/fixture_data/fixture_data_utils.py +++ b/tacker/tests/unit/vnfm/infra_drivers/openstack/fixture_data/fixture_data_utils.py @@ -90,7 +90,8 @@ def get_vnf_instance_object(instantiated_vnf_info=None, instantiation_state=instantiation_state, vnfd_id=uuidsentinel.vnfd_id, vnf_provider="sample provider", vnf_product_name="vnf product name", vnf_software_version='1.0', vnfd_version="2", - instantiated_vnf_info=inst_vnf_info) + instantiated_vnf_info=inst_vnf_info, + vnf_metadata={'namespace': 'default'}) return vnf_instance diff --git a/tacker/vnfm/infra_drivers/kubernetes/k8s/translate_outputs.py b/tacker/vnfm/infra_drivers/kubernetes/k8s/translate_outputs.py index 453a0be48..44ab2763b 100644 --- a/tacker/vnfm/infra_drivers/kubernetes/k8s/translate_outputs.py +++ b/tacker/vnfm/infra_drivers/kubernetes/k8s/translate_outputs.py @@ -341,20 +341,15 @@ class Transformer(object): kind=file_content_dict.get('kind', ''), reason=e) LOG.error(msg) raise exceptions.InitApiFalse(error=msg) - if not file_content_dict.get('metadata', '') and not namespace: - k8s_obj['namespace'] = '' - elif file_content_dict.get('metadata', '').\ - get('namespace', ''): - k8s_obj['namespace'] = \ - file_content_dict.get('metadata', '').get( - 'namespace', '') - elif namespace: - k8s_obj['namespace'] = namespace - else: - k8s_obj['namespace'] = '' + + k8s_obj['namespace'] = namespace + if k8s_obj['object'].metadata: + k8s_obj['object'].metadata.namespace = namespace + return k8s_obj - def get_k8s_objs_from_yaml(self, artifact_files, vnf_package_path): + def get_k8s_objs_from_yaml(self, artifact_files, vnf_package_path, + namespace=None): k8s_objs = [] for artifact_file in artifact_files: if ((urlparse(artifact_file).scheme == 'file') or @@ -369,11 +364,11 @@ class Transformer(object): file_content_dicts = list(yaml.safe_load_all(file_content)) for file_content_dict in file_content_dicts: k8s_obj = self._get_k8s_obj_from_file_content_dict( - file_content_dict) + file_content_dict, namespace) k8s_objs.append(k8s_obj) return k8s_objs - def get_k8s_objs_from_manifest(self, mf_content, namespace=None): + def get_k8s_objs_from_manifest(self, mf_content, namespace): mkobj_kind_list = [ "Pod", "Service", diff --git a/tacker/vnfm/infra_drivers/kubernetes/kubernetes_driver.py b/tacker/vnfm/infra_drivers/kubernetes/kubernetes_driver.py index 844f409b8..c72b19dea 100644 --- a/tacker/vnfm/infra_drivers/kubernetes/kubernetes_driver.py +++ b/tacker/vnfm/infra_drivers/kubernetes/kubernetes_driver.py @@ -43,6 +43,7 @@ from tacker.vnfm.infra_drivers import abstract_driver from tacker.vnfm.infra_drivers.kubernetes.helm import helm_client from tacker.vnfm.infra_drivers.kubernetes.k8s import translate_outputs from tacker.vnfm.infra_drivers.kubernetes import translate_template +from tacker.vnfm.infra_drivers.kubernetes import utils as k8s_utils from tacker.vnfm.infra_drivers import scale_driver from urllib.parse import urlparse @@ -761,11 +762,9 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, return pvc_list_for_delete @log.log - def _delete_k8s_obj(self, kind, k8s_client_dict, vnf_resource, body): - namespace = vnf_resource.resource_name.\ - split(COMMA_CHARACTER)[0] - name = vnf_resource.resource_name.\ - split(COMMA_CHARACTER)[1] + def _delete_k8s_obj(self, kind, k8s_client_dict, vnf_resource, body, + namespace): + name = vnf_resource.resource_name api_version = vnf_resource.resource_type.\ split(COMMA_CHARACTER)[0] @@ -818,7 +817,7 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, def _helm_uninstall(self, context, vnf_instance): inst_vnf_info = vnf_instance.instantiated_vnf_info additional_params = inst_vnf_info.additional_params - namespace = additional_params.get('namespace', '') + namespace = vnf_instance.vnf_metadata['namespace'] helm_inst_param_list = additional_params.get( 'using_helm_install_param') vim_info = vnflcm_utils._get_vim(context, @@ -898,6 +897,7 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, # 7. Delete `Namespace` finally 'Namespace' ] + namespace = vnf_instance.vnf_metadata['namespace'] for kind in ordered_kind: for vnf_resource in vnf_resources: obj_kind = vnf_resource.resource_type.\ @@ -907,7 +907,7 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, kind=obj_kind, k8s_client_dict=k8s_client_dict, vnf_resource=vnf_resource, - body=body) + body=body, namespace=namespace) except Exception as e: LOG.error('Deleting VNF got an error due to %s', e) raise @@ -988,8 +988,9 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, name_with_underscores).lower() snake_case_kind = convert(kind) + kubernetes = translate_outputs.Transformer(None, None, None, None) try: - if namespace: + if 'namespaced' in kubernetes.method_value.get(kind): read_api = eval('k8s_client_dict[api_version].' 'read_namespaced_%s' % snake_case_kind) response = read_api(name=name, namespace=namespace) @@ -1053,6 +1054,7 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, get_by_vnf_instance_id(context, vnf_instance.id) k8s_client_dict = self.kubernetes.\ get_k8s_client_dict(auth=auth_cred) + namespace = vnf_instance.vnf_metadata['namespace'] keep_going = True stack_retries = self.STACK_RETRIES @@ -1061,10 +1063,7 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, count = 0 for vnf_resource in vnf_resources: - namespace = vnf_resource.resource_name.\ - split(COMMA_CHARACTER)[0] - name = vnf_resource.resource_name.\ - split(COMMA_CHARACTER)[1] + name = vnf_resource.resource_name api_version = vnf_resource.resource_type.\ split(COMMA_CHARACTER)[0] kind = vnf_resource.resource_type.\ @@ -1206,6 +1205,9 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, # execute legacy scale method self._scale_legacy(policy, auth_cred) else: + vnf_instance = objects.VnfInstance.get_by_id( + context, policy['vnf_instance_id']) + namespace = vnf_instance.vnf_metadata['namespace'] vnf_resources = objects.VnfResourceList.get_by_vnf_instance_id( context, policy['vnf_instance_id']) app_v1_api_client = self.kubernetes.get_app_v1_api_client( @@ -1222,15 +1224,10 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, # name defined in `metadata.name` of Kubernetes object # file) matches the value of `properties.name` of VDU # defined in VNFD. - name = vnf_resource.resource_name.\ - split(COMMA_CHARACTER)[1] + name = vnf_resource.resource_name for vdu_id, vdu_def in vdu_defs.items(): vdu_properties = vdu_def.get('properties') if name == vdu_properties.get('name'): - namespace = vnf_resource.resource_name.\ - split(COMMA_CHARACTER)[0] - if not namespace: - namespace = "default" kind = vnf_resource.resource_type.\ split(COMMA_CHARACTER)[1] if kind in target_kinds: @@ -1367,6 +1364,9 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, # execute legacy scale_wait method self._scale_wait_legacy(policy, auth_cred) else: + vnf_instance = objects.VnfInstance.get_by_id( + context, policy['vnf_instance_id']) + namespace = vnf_instance.vnf_metadata['namespace'] vnf_resources = objects.VnfResourceList.get_by_vnf_instance_id( context, policy['vnf_instance_id']) core_v1_api_client = self.kubernetes.get_core_v1_api_client( @@ -1379,15 +1379,10 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, error_reason = None target_kinds = ["Deployment", "ReplicaSet", "StatefulSet"] for vnf_resource in vnf_resources: - name = vnf_resource.resource_name.\ - split(COMMA_CHARACTER)[1] + name = vnf_resource.resource_name for vdu_id, vdu_def in vdu_defs.items(): vdu_properties = vdu_def.get('properties') if name == vdu_properties.get('name'): - namespace = vnf_resource.resource_name.\ - split(COMMA_CHARACTER)[0] - if not namespace: - namespace = "default" kind = vnf_resource.resource_type.\ split(COMMA_CHARACTER)[1] if kind in target_kinds: @@ -1559,19 +1554,17 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, return target_k8s_files def _create_vnf_resource(self, context, vnf_instance, file_content_dict, - namespace=None): + chk_namespaces): vnf_resource = vnf_resource_obj.VnfResource( context=context) vnf_resource.vnf_instance_id = vnf_instance.id metadata = file_content_dict.get('metadata', {}) - if metadata and metadata.get('namespace', ''): - namespace = metadata.get('namespace', '') - elif namespace: - namespace = namespace - else: - namespace = '' - vnf_resource.resource_name = ','.join([ - namespace, metadata.get('name', '')]) + + chk_namespaces.append( + {'namespace': metadata.get('namespace', ''), + 'kind': file_content_dict.get('kind', '')}) + + vnf_resource.resource_name = metadata.get('name', ' ') vnf_resource.resource_type = ','.join([ file_content_dict.get('apiVersion', ''), file_content_dict.get('kind', '')]) @@ -1589,6 +1582,16 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, vim_connection_info, instantiate_vnf_req, vnf_package_path) # NOTE: In case of using helm, vnf_resources is created # after `helm install` command is executed. + + namespace = (instantiate_vnf_req.additional_params + .get('namespace', '')) + if not namespace: + namespace = 'default' + if not vnf_instance.vnf_metadata: + vnf_instance.vnf_metadata = {} + vnf_instance.vnf_metadata['namespace'] = namespace + vnf_instance.save() + return {} vnf_resources = dict() @@ -1627,6 +1630,9 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, setattr(vnf_instance, 'task_state', None) vnf_instance.save() raise exceptions.VnfArtifactNotFound(id=vnf_package.id) + + chk_namespaces = [] + for target_k8s_index, target_k8s_file \ in enumerate(target_k8s_files): if ((urlparse(target_k8s_file).scheme == 'file') or @@ -1642,9 +1648,15 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, vnf_resources_temp = [] for file_content_dict in file_content_dict_list: vnf_resource = self._create_vnf_resource( - context, vnf_instance, file_content_dict) + context, vnf_instance, file_content_dict, + chk_namespaces) vnf_resources_temp.append(vnf_resource) vnf_resources[target_k8s_index] = vnf_resources_temp + + LOG.debug(f"all manifest namespace and kind: {chk_namespaces}") + k8s_utils.check_and_save_namespace( + context, instantiate_vnf_req, chk_namespaces, vnf_instance) + return vnf_resources def delete_vnf_instance_resource(self, context, vnf_instance, @@ -1654,7 +1666,7 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, def _helm_install(self, context, vnf_instance, vim_connection_info, instantiate_vnf_req, vnf_package_path, transformer): additional_params = instantiate_vnf_req.additional_params - namespace = additional_params.get('namespace', '') + namespace = vnf_instance.vnf_metadata['namespace'] helm_inst_param_list = additional_params.get( 'using_helm_install_param') helm_info = self._get_helm_info(vim_connection_info) @@ -1704,7 +1716,7 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, mf_content_dicts = list(yaml.safe_load_all(mf_content)) for mf_content_dict in mf_content_dicts: vnf_resource = self._create_vnf_resource( - context, vnf_instance, mf_content_dict, namespace) + context, vnf_instance, mf_content_dict, []) vnf_resources.append(vnf_resource) helmclient.close_session() # save the vnf resources in the db @@ -1717,6 +1729,7 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, grant_response, vnf_package_path, plugin=None): target_k8s_files = self._get_target_k8s_files(instantiate_vnf_req) + namespace = vnf_instance.vnf_metadata['namespace'] auth_attr = vim_connection_info.access_info use_helm_flag = self._is_use_helm_flag( instantiate_vnf_req.additional_params) @@ -1738,7 +1751,8 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, instantiate_vnf_req, vnf_package_path, transformer) else: k8s_objs = transformer.\ - get_k8s_objs_from_yaml(target_k8s_files, vnf_package_path) + get_k8s_objs_from_yaml(target_k8s_files, vnf_package_path, + namespace) k8s_objs = transformer.deploy_k8s(k8s_objs) vnfd_dict['current_error_point'] = EP.POST_VIM_CONTROL k8s_objs = self.create_wait_k8s( @@ -1765,9 +1779,8 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, return resource_info_str def _post_helm_install(self, context, vim_connection_info, - instantiate_vnf_req, transformer): + instantiate_vnf_req, transformer, namespace): additional_params = instantiate_vnf_req.additional_params - namespace = additional_params.get('namespace', '') helm_inst_param_list = additional_params.get( 'using_helm_install_param') helm_info = self._get_helm_info(vim_connection_info) @@ -1797,6 +1810,7 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, """ auth_attr = vim_connection_info.access_info auth_cred, file_descriptor = self._get_auth_creds(auth_attr) + namespace = vnf_instance.vnf_metadata['namespace'] try: # get Kubernetes object files target_k8s_files = self._get_target_k8s_files(instantiate_vnf_req) @@ -1807,11 +1821,12 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, None, None, None, None) if self._is_use_helm_flag(instantiate_vnf_req.additional_params): k8s_objs = self._post_helm_install(context, - vim_connection_info, instantiate_vnf_req, transformer) + vim_connection_info, instantiate_vnf_req, transformer, + namespace) else: # get Kubernetes object k8s_objs = transformer.get_k8s_objs_from_yaml( - target_k8s_files, vnf_package_path) + target_k8s_files, vnf_package_path, namespace) # get TOSCA node templates vnfd_dict = vnflcm_utils._get_vnfd_dict( context, vnf_instance.vnfd_id, @@ -1840,9 +1855,6 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, # Skip if rsc_kind is not target kind continue rsc_name = k8s_obj.get('object').metadata.name - namespace = k8s_obj.get('object').metadata.namespace - if not namespace: - namespace = "default" # get V1PodList by namespace if namespace in pod_list_dict.keys(): pod_list = pod_list_dict.get(namespace) @@ -1896,14 +1908,11 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, return vnfc_resources def _get_added_pod_names(self, core_v1_api_client, inst_vnf_info, vdu_id, - vnfc_resource, pod_list_dict): + vnfc_resource, pod_list_dict, namespace): compute_resource = vnfc_resource.compute_resource rsc_kind = compute_resource.vim_level_resource_type rsc_metadata = jsonutils.loads( vnfc_resource.metadata.get(rsc_kind)) - namespace = rsc_metadata.get('namespace') - if not namespace: - namespace = "default" rsc_name = rsc_metadata.get('name') # Get pod list from kubernetes if namespace in pod_list_dict.keys(): @@ -1948,6 +1957,7 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, auth_attr = vim_connection_info.access_info auth_cred, file_descriptor = self._get_auth_creds(auth_attr) inst_vnf_info = vnf_instance.instantiated_vnf_info + namespace = vnf_instance.vnf_metadata['namespace'] try: core_v1_api_client = self.kubernetes.get_core_v1_api_client( auth=auth_cred) @@ -1969,7 +1979,7 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, continue actual_pod_names, added_pod_names = self._get_added_pod_names( core_v1_api_client, inst_vnf_info, vdu_id, vnfc_resource, - pod_list_dict) + pod_list_dict, namespace) if added_pod_names: heal_target_ids = heal_vnf_request.vnfc_instance_id @@ -1998,9 +2008,6 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, pod_name = compute_resource.resource_id rsc_metadata = jsonutils.loads( vnfc_resource.metadata.get(rsc_kind)) - namespace = rsc_metadata.get('namespace') - if not namespace: - namespace = "default" if rsc_kind == 'Pod': rsc_name = rsc_metadata.get('name') @@ -2105,6 +2112,7 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, # initialize Kubernetes APIs auth_attr = vim_connection_info.access_info auth_cred, file_descriptor = self._get_auth_creds(auth_attr) + namespace = vnf_instance.vnf_metadata['namespace'] try: core_v1_api_client = self.kubernetes.get_core_v1_api_client( auth=auth_cred) @@ -2131,7 +2139,7 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, rsc_metadata = jsonutils.loads( vnfc_resource.metadata.get(info['kind'])) info['name'] = rsc_metadata.get('name') - info['namespace'] = rsc_metadata.get('namespace') + info['namespace'] = namespace if not info['namespace']: info['namespace'] = "default" k8s_resources.append(info) @@ -2221,6 +2229,7 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, auth_attr = vim_connection_info.access_info auth_cred, file_descriptor = self._get_auth_creds(auth_attr) inst_vnf_info = vnf_instance.instantiated_vnf_info + namespace = vnf_instance.vnf_metadata['namespace'] try: core_v1_api_client = self.kubernetes.get_core_v1_api_client( auth=auth_cred) @@ -2248,7 +2257,7 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, # (Deployment, DaemonSet, ReplicaSet) actual_pod_names, added_pod_names = self._get_added_pod_names( core_v1_api_client, inst_vnf_info, vdu_id, vnfc_resource, - pod_list_dict) + pod_list_dict, namespace) updated_vnfc_ids = [] # Update entries that pod was not found when heal_vnf method @@ -2350,6 +2359,7 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, extract_policy_infos=extract_policy_infos, aspect_id=scale_vnf_request.aspect_id, tosca=tosca) + namespace = vnf_instance.vnf_metadata['namespace'] is_found = False target_kinds = ["Deployment", "ReplicaSet", "StatefulSet"] for vnf_resource in vnf_resources: @@ -2357,11 +2367,10 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, # stored in vnfc_resource as follows: # - resource_name : "namespace,name" # - resource_type : "api_version,kind" - rsc_name = vnf_resource.resource_name.split(',')[1] + rsc_name = vnf_resource.resource_name for vdu_id, vdu_def in vdu_defs.items(): vdu_properties = vdu_def.get('properties') if rsc_name == vdu_properties.get('name'): - namespace = vnf_resource.resource_name.split(',')[0] rsc_kind = vnf_resource.resource_type.split(',')[1] target_vdu_id = vdu_id if rsc_kind in target_kinds: diff --git a/tacker/vnfm/infra_drivers/kubernetes/utils.py b/tacker/vnfm/infra_drivers/kubernetes/utils.py new file mode 100644 index 000000000..47fd815d9 --- /dev/null +++ b/tacker/vnfm/infra_drivers/kubernetes/utils.py @@ -0,0 +1,83 @@ +# All Rights Reserved. +# +# +# 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. + +"""Utilities and helper functions.""" + +from oslo_log import log as logging + +from tacker.common import exceptions + +LOG = logging.getLogger(__name__) + +supported_k8s_resource_kinds = { + "Pod", + "Binding", + "ConfigMap", + "LimitRange", + "PersistentVolumeClaim", + "PodTemplate", + "ResourceQuota", + "Secret", + "ServiceAccount", + "Service", + "ControllerRevision", + "DaemonSet", + "Deployment", + "ReplicaSet", + "StatefulSet", + "LocalSubjectAccessReview", + "HorizontalPodAutoscaler", + "Job", + "Lease", + "NetworkPolicy", + "RoleBinding", + "Role" +} + + +def check_and_save_namespace( + context, instantiate_vnf_req, chk_namespaces, vnf_instance): + namespace = '' + if instantiate_vnf_req.additional_params: + namespace = instantiate_vnf_req.additional_params.get('namespace', '') + if not namespace: + try: + namespace = get_namespace_from_manifests(chk_namespaces) + except exceptions.NamespaceIsNotUnique as e: + LOG.error(e) + raise e + if not namespace: + namespace = 'default' + + if not vnf_instance.vnf_metadata: + vnf_instance.vnf_metadata = {} + vnf_instance.vnf_metadata['namespace'] = namespace + vnf_instance.save() + + +def get_namespace_from_manifests(chk_namespaces): + namespaces = { + chk_namespace['namespace'] for chk_namespace in + chk_namespaces if (chk_namespace['kind'] in + supported_k8s_resource_kinds) + } + + if len(namespaces) > 1: + LOG.error(f'Multiple namespaces found: {namespaces}') + raise exceptions.NamespaceIsNotUnique() + + if namespaces: + return namespaces.pop() + return None