Support specifying namespace for deploying CNF

This patch implements that in the instantiate operation
of ESTI NFV-SOL003 VNF Lifecycle Management 2.6.1, users
can specify the target namespace in InstantiateVnfRequest
to deploy CNF on Kubernetes VIM.

Implements: blueprint k8s-namespace
Change-Id: I292256bc58b54e248da54ccbf3c7e82bd28fd022
This commit is contained in:
Yi Feng 2022-01-18 17:21:08 +09:00
parent 35aaba1aab
commit de63219e38
20 changed files with 1404 additions and 726 deletions

View File

@ -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.

View File

@ -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.')

View File

@ -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 ]

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: multi-namespace01

View File

@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: multi-namespace02

View File

@ -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

View File

@ -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'])

View File

@ -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]

View File

@ -145,7 +145,8 @@ class TestKubernetesHelm(base.TestCase):
self.helm_client._execute_command,
ssh_command, timeout, retry)
def test_pre_instantiation_vnf_helm(self):
@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
@ -157,7 +158,8 @@ class TestKubernetesHelm(base.TestCase):
instantiate_vnf_req, vnf_package_path)
self.assertEqual(vnf_resources, {})
def test_pre_helm_install_with_bool_param(self):
@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
@ -274,7 +276,7 @@ class TestKubernetesHelm(base.TestCase):
base_hot_dict)
self.assertEqual(
result,
"{'namespace': '', 'name': 'vdu1', " +
"{'namespace': 'default', 'name': 'vdu1', " +
"'apiVersion': 'apps/v1', 'kind': 'Deployment', " +
"'status': 'Create_complete'}")
self.assertEqual(mock_read_namespaced_deployment.call_count, 1)
@ -291,6 +293,7 @@ class TestKubernetesHelm(base.TestCase):
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
@ -341,7 +344,7 @@ class TestKubernetesHelm(base.TestCase):
base_hot_dict)
self.assertEqual(
result,
"{'namespace': '', 'name': 'vdu1', " +
"{'namespace': 'default', 'name': 'vdu1', " +
"'apiVersion': 'apps/v1', 'kind': 'Deployment', " +
"'status': 'Create_complete'}")
self.assertEqual(mock_read_namespaced_deployment.call_count, 1)

View File

@ -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)

View File

@ -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'])

View File

@ -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

View File

@ -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'] = ''
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",

View File

@ -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:

View File

@ -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