diff --git a/doc/source/user/mgmt_driver_for_container_update.rst b/doc/source/user/mgmt_driver_for_container_update.rst index 26de54868..7470c0b75 100644 --- a/doc/source/user/mgmt_driver_for_container_update.rst +++ b/doc/source/user/mgmt_driver_for_container_update.rst @@ -47,8 +47,8 @@ Use Cases In this user guide, the provided sample VNF Packages will be instantiated and then updated. The sample Mgmt Driver will update resources on Kubernetes during update. Update the ConfigMap and Secret, and also -update the image in the Pod and Deployment, and other resources will -not change. +update the image in the Pod, Deployment, DaemonSet and ReplicaSet, and other +resources will not change. Prerequisites ------------- @@ -199,7 +199,13 @@ You can see resource definition files are included as a value of "Files/kubernetes/pod_env.yaml", "Files/kubernetes/pod_volume.yaml", "Files/kubernetes/replicaset.yaml", - "Files/kubernetes/secret_1.yaml" + "Files/kubernetes/secret_1.yaml", + "Files/kubernetes/configmap_3.yaml", + "Files/kubernetes/pod_env_2.yaml", + "Files/kubernetes/pod_volume_2.yaml", + "Files/kubernetes/daemonset.yaml", + "Files/kubernetes/deployment_2.yaml", + "Files/kubernetes/secret_3.yaml" ], "namespace": "default" }, @@ -228,27 +234,27 @@ As mentioned in Prerequisites, the VNF must be instantiated before performing updating. Next, the user can use the original vnf package as a template to make a new -vnf package, in which the yaml of ConfigMap, Secret, Pod and Deployment can -be changed. +vnf package, in which the yaml of ConfigMap, Secret, Pod, Deployment, DaemonSet +and ReplicaSet can be changed. .. note:: * The yaml of ConfigMap and Secret can be changed. The kind, namespace and name cannot be changed, but the file name and file path can be changed. - * The yaml of Pod and Deployment can also be changed, but only the - image field can be changed, and no other fields can be changed. + * The yaml of Pod, Deployment, DaemonSet and ReplicaSet can also be + changed, but only the image field can be changed, and no other fields can + be changed. * No other yaml is allowed to be changed. - - * If changes other than images are made to the yaml of Pod and - Deployment, those will not take effect. However, if heal entire - VNF at this time, the resource will be based on the new yaml - during the instantiation, and all changes will take effect. + * If changes other than images are made to the yaml of Pod, Deployment, + DaemonSet and ReplicaSet , those will not take effect. However, if heal + entire VNF at this time, the resource will be based on the new yaml + during the instantiation, and all changes will take effect. Then after creating and uploading the new vnf package, you can perform the update operation. After the update, the Mgmt Driver will restart the pod to update and -recreate the deployment to update. +recreate the deployment, DaemonSet and ReplicaSet to update. .. note:: @@ -274,8 +280,9 @@ The resources information before update: $ kubectl get configmaps NAME DATA AGE - cm-data 1 3h55m - kube-root-ca.crt 1 23h + cm-data 1 32m + cm-data2 1 32m + kube-root-ca.crt 1 20h $ $ kubectl describe configmaps cm-data Name: cm-data @@ -283,6 +290,21 @@ The resources information before update: Labels: Annotations: + Data + ==== + cmKey1.txt: + ---- + configmap data + foo + bar + Events: + $ + $ kubectl describe configmaps cm-data2 + Name: cm-data2 + Namespace: default + Labels: + Annotations: + Data ==== cmKey1.txt: @@ -298,8 +320,9 @@ The resources information before update: $ kubectl get secrets NAME TYPE DATA AGE - default-token-ctq4p kubernetes.io/service-account-token 3 23h - secret-data Opaque 2 3h55m + default-token-w59gg kubernetes.io/service-account-token 3 20h + secret-data Opaque 2 37m + secret-data2 Opaque 2 37m $ $ kubectl describe secrets secret-data Name: secret-data @@ -309,6 +332,19 @@ The resources information before update: Type: Opaque + Data + ==== + password: 15 bytes + secKey1.txt: 15 bytes + $ + $ kubectl describe secrets secret-data2 + Name: secret-data2 + Namespace: default + Labels: + Annotations: + + Type: Opaque + Data ==== password: 15 bytes @@ -319,21 +355,25 @@ The resources information before update: .. code-block:: console $ kubectl get pod -o wide - NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES - env-test 1/1 Running 0 4h28m 10.233.96.4 node2 - vdu1-85dd489b89-w72dr 1/1 Running 0 4h28m 10.233.96.5 node2 - vdu2-mfn78 1/1 Running 0 4h28m 10.233.96.2 node2 - volume-test 1/1 Running 0 4h28m 10.233.96.3 node2 + NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES + daemonset-nv79l 1/1 Running 0 39m 10.233.96.20 node2 + deployment1-85dd489b89-p7m9q 1/1 Running 0 39m 10.233.96.17 node2 + deployment2-5c6b485699-mdx9v 1/1 Running 0 39m 10.233.96.22 node2 + env-test1 1/1 Running 0 39m 10.233.96.21 node2 + env-test2 1/1 Running 0 39m 10.233.96.19 node2 + replicaset-bv6cp 1/1 Running 0 39m 10.233.96.24 node2 + volume-test1 1/1 Running 0 39m 10.233.96.18 node2 + volume-test2 1/1 Running 0 39m 10.233.96.23 node2 $ - $ kubectl describe pod volume-test - Name: volume-test + $ kubectl describe pod volume-test1 + Name: volume-test1 Namespace: default ... Containers: nginx: - Container ID: docker://01273fa7cd595b49d866b755ea6cc2707d90cca70ecb9f5a86c4db3eacad2dde + Container ID: docker://623c652c7ab71d268e18129475d0391b72c88b1a8a778bbdd3d479fad2521bc2 Image: nginx - Image ID: docker-pullable://nginx@sha256:e9712bdfa40c19cc2cee4f06e5b1215138926250165e26fe69822a9ddc525eaf + Image ID: docker-pullable://nginx@sha256:ecc068890de55a75f1a32cc8063e79f90f0b043d70c5fcf28f1713395a4b3d49 ... Volumes: cm-volume: @@ -345,24 +385,46 @@ The resources information before update: SecretName: secret-data Optional: false ... + $ + $ kubectl describe pod volume-test2 + Name: volume-test2 + Namespace: default + ... + Containers: + nginx: + Container ID: docker://74d38aa62097b3a1a80181195ebda3877e3773311d0273fdc3fbb27fa4b9600d + Image: nginx + Image ID: docker-pullable://nginx@sha256:ecc068890de55a75f1a32cc8063e79f90f0b043d70c5fcf28f1713395a4b3d49 + ... + Volumes: + cm-volume: + Type: ConfigMap (a volume populated by a ConfigMap) + Name: cm-data2 + Optional: false + sec-volume: + Type: Secret (a volume populated by a Secret) + SecretName: secret-data2 + Optional: false + ... * Deployment .. code-block:: console $ kubectl get deployments.apps -o wide - NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR - vdu1 1/1 1 1 4h29m nginx nginx app=webserver + NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR + deployment1 1/1 1 1 49m nginx nginx app=webserver + deployment2 1/1 1 1 49m nginx nginx app=webserver $ - $ kubectl describe pod vdu1-85dd489b89-w72dr - Name: vdu1-85dd489b89-w72dr + $ kubectl describe pod deployment1-85dd489b89-p7m9q + Name: deployment1-85dd489b89-p7m9q Namespace: default ... Containers: nginx: - Container ID: docker://5efe65493ac13ff539f9de30db7c624405ff390df8f5f2e23f22fc0f8b6ad68a + Container ID: docker://50ffc03736a03c8d4546bb60bb5815b4c8f6cbbfb7b70da4121a06c5c8d6568a Image: nginx - Image ID: docker-pullable://nginx@sha256:e9712bdfa40c19cc2cee4f06e5b1215138926250165e26fe69822a9ddc525eaf + Image ID: docker-pullable://nginx@sha256:ecc068890de55a75f1a32cc8063e79f90f0b043d70c5fcf28f1713395a4b3d49 ... Environment Variables from: cm-data ConfigMap with prefix 'CM_' Optional: false @@ -371,10 +433,79 @@ The resources information before update: CMENV: Optional: false SECENV: Optional: false ... + $ + $ kubectl describe pod deployment2-5c6b485699-mdx9v + Name: deployment2-5c6b485699-mdx9v + Namespace: default + ... + Containers: + nginx: + Container ID: docker://6d7a8019984c04ab758b962a228f44fb14bfc0f4e1f525548d87a91d17b49f77 + Image: nginx + Image ID: docker-pullable://nginx@sha256:ecc068890de55a75f1a32cc8063e79f90f0b043d70c5fcf28f1713395a4b3d49 + ... + Environment Variables from: + cm-data2 ConfigMap with prefix 'CM_' Optional: false + secret-data2 Secret with prefix 'SEC_' Optional: false + Environment: + CMENV: Optional: false + SECENV: Optional: false + ... + +* DaemonSet + + .. code-block:: console + + $ kubectl get daemonset.apps -o wide + NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR + daemonset 1 1 1 1 1 58m nginx nginx app=nginx + $ + $ kubectl describe pod daemonset-nv79l + Name: daemonset-nv79l + Namespace: default + ... + Containers: + nginx: + Container ID: docker://3f392217d5f22c417fc9da24f4bd27d41e90a2165d10356a44cd1b98b6b899d9 + Image: nginx + Image ID: docker-pullable://nginx@sha256:ecc068890de55a75f1a32cc8063e79f90f0b043d70c5fcf28f1713395a4b3d49 + ... + Environment Variables from: + cm-data ConfigMap with prefix 'CM_' Optional: false + secret-data Secret with prefix 'SEC_' Optional: false + Environment: + CMENV: Optional: false + SECENV: Optional: false + ... + +* ReplicaSet + + .. code-block:: console + + $ kubectl get replicaset.apps -o wide + NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR + deployment1-85dd489b89 1 1 1 62m nginx nginx app=webserver,pod-template-hash=85dd489b89 + deployment2-5c6b485699 1 1 1 62m nginx nginx app=webserver,pod-template-hash=5c6b485699 + replicaset 1 1 1 62m nginx nginx app=webserver + $ + $ kubectl describe pod replicaset-bv6cp + Name: replicaset-bv6cp + Namespace: default + ... + Containers: + nginx: + Container ID: docker://d8e5ea8404a8cd272b54cefac236fdf0c1963a6b0cf03b283e9f57c70fcd4eab + Image: nginx + Image ID: docker-pullable://nginx@sha256:ecc068890de55a75f1a32cc8063e79f90f0b043d70c5fcf28f1713395a4b3d49 + ... Volumes: - default-token-ctq4p: + cm-volume: + Type: ConfigMap (a volume populated by a ConfigMap) + Name: cm-data + Optional: false + sec-volume: Type: Secret (a volume populated by a Secret) - SecretName: default-token-ctq4p + SecretName: secret-data Optional: false ... @@ -410,8 +541,8 @@ Here is an example of updating CNF: .. code-block:: console - $ openstack vnflcm update 9d2bd0d7-4248-445d-a70f-a14cf57d6f96 --I sample_param_file.json - Update vnf:9d2bd0d7-4248-445d-a70f-a14cf57d6f96 + $ openstack vnflcm update f21814f0-3e00-4651-a9ac-ec10f3248c19 --I sample_param_file.json + Update vnf:f21814f0-3e00-4651-a9ac-ec10f3248c19 The resources information after update: @@ -433,6 +564,21 @@ The resources information after update: foo2 bar2 Events: + $ + $ kubectl describe configmaps cm-data2 + Name: cm-data2 + Namespace: default + Labels: + Annotations: + + Data + ==== + cmKey1.txt: + ---- + configmap data + foo + bar + Events: * Secret @@ -450,26 +596,169 @@ The resources information after update: ==== password: 16 bytes secKey1.txt: 18 bytes + $ + $ kubectl describe secrets secret-data2 + Name: secret-data2 + Namespace: default + Labels: + Annotations: + + Type: Opaque + + Data + ==== + password: 15 bytes + secKey1.txt: 15 bytes * Pod .. code-block:: console $ kubectl get pod -o wide - NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES - env-test 1/1 Running 1 5h45m 10.233.96.4 node2 - vdu1-5974f79c95-xs48r 1/1 Running 0 5m17s 10.233.96.7 node2 - vdu2-mfn78 1/1 Running 0 5h45m 10.233.96.2 node2 - volume-test 1/1 Running 1 5h45m 10.233.96.3 node2 - $ kubectl describe pod volume-test - Name: volume-test + NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES + daemonset-gl4kf 1/1 Running 0 38m 10.233.96.27 node2 + deployment1-5974f79c95-5d6x4 1/1 Running 0 38m 10.233.96.25 node2 + deployment2-5c6b485699-mdx9v 1/1 Running 0 114m 10.233.96.22 node2 + env-test1 1/1 Running 1 114m 10.233.96.21 node2 + env-test2 1/1 Running 0 114m 10.233.96.19 node2 + replicaset-xfgmj 1/1 Running 0 38m 10.233.96.26 node2 + volume-test1 1/1 Running 1 114m 10.233.96.18 node2 + volume-test2 1/1 Running 0 114m 10.233.96.23 node2 + + $ + $ kubectl describe pod volume-test1 + Name: volume-test1 Namespace: default ... Containers: nginx: - Container ID: docker://d3b101bff4863eef62c7a89cb07268d236a72c5b47cc46f167a1dbdf7900220f + Container ID: docker://77f1518b617403115163874f1ea65793b92f7c8d22f5364fe5bb299b471decb1 Image: cirros - Image ID: docker-pullable://cirros@sha256:1e695eb2772a2b511ccab70091962d1efb9501fdca804eb1d52d21c0933e7f47 + Image ID: docker-pullable://cirros@sha256:be6f5d1ab1e463e7991ecb29f1e71993d633ff1d190188662085ef641bdcf389 + ... + Volumes: + cm-volume: + Type: ConfigMap (a volume populated by a ConfigMap) + Name: cm-data + Optional: false + sec-volume: + Type: Secret (a volume populated by a Secret) + SecretName: secret-data + Optional: false + ... + $ + $ kubectl describe pod volume-test2 + Name: volume-test2 + Namespace: default + ... + Containers: + nginx: + Container ID: docker://74d38aa62097b3a1a80181195ebda3877e3773311d0273fdc3fbb27fa4b9600d + Image: nginx + Image ID: docker-pullable://nginx@sha256:ecc068890de55a75f1a32cc8063e79f90f0b043d70c5fcf28f1713395a4b3d49 + ... + Volumes: + cm-volume: + Type: ConfigMap (a volume populated by a ConfigMap) + Name: cm-data2 + Optional: false + sec-volume: + Type: Secret (a volume populated by a Secret) + SecretName: secret-data2 + Optional: false + ... + +* Deployment + + .. code-block:: console + + $ kubectl get deployments.apps -o wide + NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR + deployment1 1/1 1 1 4h10m nginx cirros app=webserver + deployment2 1/1 1 1 4h10m nginx nginx app=webserver + $ + $ kubectl describe pod deployment1-5974f79c95-5d6x4 + Name: deployment1-5974f79c95-5d6x4 + Namespace: default + ... + Containers: + nginx: + Container ID: docker://7b8bd5a7da875fea74a0b0d54ad8a6c1e65bf08a823ae864c6bd7f16b494b990 + Image: cirros + Image ID: docker-pullable://cirros@sha256:be6f5d1ab1e463e7991ecb29f1e71993d633ff1d190188662085ef641bdcf389 + ... + Environment Variables from: + cm-data ConfigMap with prefix 'CM_' Optional: false + secret-data Secret with prefix 'SEC_' Optional: false + Environment: + CMENV: Optional: false + SECENV: Optional: false + ... + $ + $ kubectl describe pod deployment2-5c6b485699-mdx9v + Name: deployment2-5c6b485699-mdx9v + Namespace: default + ... + Containers: + nginx: + Container ID: docker://6d7a8019984c04ab758b962a228f44fb14bfc0f4e1f525548d87a91d17b49f77 + Image: nginx + Image ID: docker-pullable://nginx@sha256:ecc068890de55a75f1a32cc8063e79f90f0b043d70c5fcf28f1713395a4b3d49 + ... + Environment Variables from: + cm-data2 ConfigMap with prefix 'CM_' Optional: false + secret-data2 Secret with prefix 'SEC_' Optional: false + Environment: + CMENV: Optional: false + SECENV: Optional: false + ... + +* DaemonSet + + .. code-block:: console + + $ kubectl get daemonset.apps -o wide + NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR + daemonset 1 1 1 1 1 4h14m nginx cirros app=nginx + $ + $ kubectl describe pod daemonset-gl4kf + Name: daemonset-gl4kf + Namespace: default + ... + Containers: + nginx: + Container ID: docker://98712bf43f41fce1983d46cefcfab7ed72f6159f6eb18ab763d9707caf887d8c + Image: cirros + Image ID: docker-pullable://cirros@sha256:be6f5d1ab1e463e7991ecb29f1e71993d633ff1d190188662085ef641bdcf389 + ... + Environment Variables from: + cm-data ConfigMap with prefix 'CM_' Optional: false + secret-data Secret with prefix 'SEC_' Optional: false + Environment: + CMENV: Optional: false + SECENV: Optional: false + ... + +* ReplicaSet + + .. code-block:: console + + $ kubectl get replicaset.apps -o wide + NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR + deployment1-5974f79c95 1 1 1 3h5m nginx cirros app=webserver,pod-template-hash=5974f79c95 + deployment1-85dd489b89 0 0 0 4h20m nginx nginx app=webserver,pod-template-hash=85dd489b89 + deployment2-5c6b485699 1 1 1 4h20m nginx nginx app=webserver,pod-template-hash=5c6b485699 + replicaset 1 1 1 4h20m nginx cirros app=webserver + $ + $ kubectl describe pod replicaset-xfgmj + Name: replicaset-xfgmj + Namespace: default + ... + Containers: + nginx: + Container ID: docker://a9cf17fd465780e5f3e557a1c5d27e0c8ccf5f31a0fd106d9dc891971fed455d + Image: cirros + Image ID: docker-pullable://cirros@sha256:be6f5d1ab1e463e7991ecb29f1e71993d633ff1d190188662085ef641bdcf389 ... Volumes: cm-volume: @@ -482,39 +771,10 @@ The resources information after update: Optional: false ... -* Deployment - - .. code-block:: console - - $ kubectl get deployments.apps -o wide - NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR - vdu1 1/1 1 1 5h50m nginx cirros app=webserver - $ kubectl describe pod vdu1-5974f79c95-xs48r - Name: vdu1-5974f79c95-xs48r - Namespace: default - ... - Containers: - nginx: - Container ID: docker://6cad9f692f839d08b53fae58fe2ab06f576271d15aae8744ac0ce57c34510fe0 - Image: cirros - Image ID: docker-pullable://cirros@sha256:1e695eb2772a2b511ccab70091962d1efb9501fdca804eb1d52d21c0933e7f47 - ... - Environment Variables from: - cm-data ConfigMap with prefix 'CM_' Optional: false - secret-data Secret with prefix 'SEC_' Optional: false - Environment: - CMENV: Optional: false - SECENV: Optional: false - ... - Volumes: - default-token-ctq4p: - Type: Secret (a volume populated by a Secret) - SecretName: default-token-ctq4p - Optional: false - ... - -You can see that the ConfigMap and Secret are updated, as are the images in -the Pod and Deployment. +You can see that only the Pods are restarted whose ConfigMap/Secret or images +are updated. When it comes to Deployments, DaemonSets and ReplicaSets whose +ConfigMap/Secret or images are updated, their pods will be deleted and +recreated. .. _NFV-SOL001 v2.6.1 : https://www.etsi.org/deliver/etsi_gs/NFV-SOL/001_099/001/02.06.01_60/gs_NFV-SOL001v020601p.pdf .. _Set Tacker Configuration : https://docs.openstack.org/tacker/latest/user/mgmt_driver_deploy_k8s_usage_guide.html#set-tacker-configuration diff --git a/releasenotes/notes/improve-function-for-container-update-0da4499cc0e55dcf.yaml b/releasenotes/notes/improve-function-for-container-update-0da4499cc0e55dcf.yaml new file mode 100644 index 000000000..f930c3316 --- /dev/null +++ b/releasenotes/notes/improve-function-for-container-update-0da4499cc0e55dcf.yaml @@ -0,0 +1,9 @@ +--- +features: + - | + In the current implementation, when users invoke update operation of + ConfigMaps and Secrets, all Pods are restarted even if they don't use + those updated ConfigMaps and Secrets. + + Remove this limitation by filtering out resources that use + Configmaps/Secrets and restarting those resources. diff --git a/samples/mgmt_driver/kubernetes/container_update/container_update_mgmt.py b/samples/mgmt_driver/kubernetes/container_update/container_update_mgmt.py index b6d0a1301..ca0f15680 100644 --- a/samples/mgmt_driver/kubernetes/container_update/container_update_mgmt.py +++ b/samples/mgmt_driver/kubernetes/container_update/container_update_mgmt.py @@ -88,13 +88,48 @@ class ContainerUpdateMgmtDriver(vnflcm_abstract_driver. return k8s_objs def _modify_container_img(self, old_containers, new_containers): + flag = False for old_container in old_containers: for new_container in new_containers: if (old_container.name == new_container.name and old_container.image != new_container.image): # Replace the old image with the new image + flag = True old_container.image = new_container.image break + return flag + + def _is_config_updated(self, k8s_resource_info, modify_config_names): + containers = None + volumes = None + k8s_obj_kind = k8s_resource_info.kind + if k8s_obj_kind == 'Pod': + containers = k8s_resource_info.spec.containers + volumes = k8s_resource_info.spec.volumes + elif k8s_obj_kind in ('Deployment', 'ReplicaSet', 'DaemonSet'): + containers = k8s_resource_info.spec.template.spec.containers + volumes = k8s_resource_info.spec.template.spec.volumes + if containers: + for container in containers: + if container.env: + for env in container.env: + if env.value_from.config_map_key_ref and ( + env.value_from.config_map_key_ref.name + in modify_config_names): + return True + if env.value_from.secret_key_ref and ( + env.value_from.secret_key_ref.name + in modify_config_names): + return True + if volumes: + for volume in volumes: + if volume.config_map and ( + volume.config_map.name in modify_config_names): + return True + if volume.secret and ( + volume.secret.secret_name in modify_config_names): + return True + return False def _replace_api(self, k8s_clients, namespace, k8s_obj): # get api @@ -197,6 +232,9 @@ class ContainerUpdateMgmtDriver(vnflcm_abstract_driver. vnf_instance.vim_connection_info) vim_connection_info = objects.VimConnectionInfo.obj_from_primitive( vim_info, context) + + # the name of updated configmap/secret will be in this set + modify_config_names = set() for configmap_secret_path in configmap_secret_paths: # Read the contents of the manifest file and get name and kind configmap_secrets = self._get_kind_and_name(configmap_secret_path, @@ -215,6 +253,8 @@ class ContainerUpdateMgmtDriver(vnflcm_abstract_driver. new_inst_vnf_info.additional_params[ 'lcm-kubernetes-def-files'][ index] = configmap_secret_path + for obj in resource: + modify_config_names.add(obj['name']) break raise exceptions.MgmtDriverOtherError( error_message='The number of resources in the ' @@ -249,7 +289,10 @@ class ContainerUpdateMgmtDriver(vnflcm_abstract_driver. for old_k8s_obj in old_k8s_objs: old_k8s_obj_kind = old_k8s_obj['object'].kind old_k8s_obj_name = old_k8s_obj['object'].metadata.name - if old_k8s_obj_kind in ['Pod', 'Deployment']: + if old_k8s_obj_kind in ('Pod', 'Deployment', + 'ReplicaSet', 'DaemonSet'): + image_modify_flag = False + config_modify_flag = False for new_k8s_obj in new_k8s_objs: # If the old and new k8s_obj have the same kind and name new_k8s_obj_kind = new_k8s_obj['object'].kind @@ -268,7 +311,12 @@ class ContainerUpdateMgmtDriver(vnflcm_abstract_driver. # Assign old_k8s_resource_info to old_k8s_obj['object'] old_k8s_obj['object'] = old_k8s_resource_info - if old_k8s_obj_kind == 'Deployment': + # if config of Pod/Deployment/ReplicaSet/DaemonSet + # is to be updated then set config_modify_flag True + config_modify_flag = self._is_config_updated( + old_k8s_resource_info, modify_config_names) + if old_k8s_obj_kind in ('Deployment', 'ReplicaSet', + 'DaemonSet'): old_containers = (old_k8s_obj['object'].spec .template.spec.containers) new_containers = (new_k8s_obj['object'].spec @@ -279,12 +327,13 @@ class ContainerUpdateMgmtDriver(vnflcm_abstract_driver. new_containers = (new_k8s_obj['object'] .spec.containers) # Replace the old image with the new image - self._modify_container_img(old_containers, - new_containers) + image_modify_flag = self._modify_container_img( + old_containers, new_containers) break - - # Append old_k8s_obj to k8s_pod_objs - k8s_pod_objs.append(old_k8s_obj) + # Append only old_k8s_obj whose image or config would + # be updated to k8s_pod_objs + if image_modify_flag or config_modify_flag: + k8s_pod_objs.append(old_k8s_obj) elif old_k8s_obj_kind in ['ConfigMap', 'Secret']: for new_k8s_obj in new_k8s_objs: # If the old and new k8s_obj have the same kind and name @@ -292,18 +341,36 @@ class ContainerUpdateMgmtDriver(vnflcm_abstract_driver. new_k8s_obj_name = new_k8s_obj['object'].metadata.name if old_k8s_obj_kind == new_k8s_obj_kind and ( old_k8s_obj_name == new_k8s_obj_name): - # Append old_k8s_obj to k8s_pod_objs + # Append new_k8s_obj to k8s_config_objs k8s_config_objs.append(new_k8s_obj) break for k8s_config_obj in k8s_config_objs: # Call the replace API self._replace_api(k8s_clients, namespace, k8s_config_obj) + core_v1_api_client = k8s_clients['v1'] + pods = core_v1_api_client.list_namespaced_pod(namespace=namespace) for k8s_pod_obj in k8s_pod_objs: # Call the replace API self._replace_api(k8s_clients, namespace, k8s_pod_obj) + # delete pod of modified replicaset + # After using the replace_namespaced_replicaset API of k8s, + # the new configuration cannot be applied to the pod created + # by the replicaset, so you need to delete the pod first, and + # then the replicaset will automatically rebuild the pod to make + # the new configuration take effect. + if k8s_pod_obj['object'].kind == 'ReplicaSet': + for pod in pods.items: + match_result = kube_driver.is_match_pod_naming_rule( + 'ReplicaSet', + k8s_pod_obj['object'].metadata.name, + pod.metadata.name) + if match_result: + core_v1_api_client.delete_namespaced_pod( + namespace=namespace, + name=pod.metadata.name, + body=pod) # _replace_wait_k8s - core_v1_api_client = k8s_clients['v1'] self._replace_wait_k8s(kube_driver, k8s_pod_objs, core_v1_api_client, vnf_instance) # Get all pod information under the specified namespace diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Definitions/sample_df_simple.yaml b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Definitions/sample_df_simple.yaml index 2142be980..d0cd134ff 100644 --- a/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Definitions/sample_df_simple.yaml +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Definitions/sample_df_simple.yaml @@ -87,6 +87,43 @@ topology_template: vdu_profile: min_number_of_instances: 1 max_number_of_instances: 1 + + VDU5: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: daemonset-vdu5 + description: kubernetes resource as VDU5 + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 1 + + VDU6: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: deployment2-vdu6 + description: kubernetes resource as VDU6 + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 1 + + VDU7: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: env-test2 + description: kubernetes resource as VDU7 + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 1 + + VDU8: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: volume-test2 + description: kubernetes resource as VDU8 + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 1 + policies: - scaling_aspects: type: tosca.policies.nfv.ScalingAspects diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Files/kubernetes/configmap_3.yaml b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Files/kubernetes/configmap_3.yaml new file mode 100644 index 000000000..8b1ffbfcc --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Files/kubernetes/configmap_3.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-data3 +data: + cmKey1.txt: | + configmap data + foo + bar \ No newline at end of file diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Files/kubernetes/daemonset.yaml b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Files/kubernetes/daemonset.yaml new file mode 100644 index 000000000..000dac234 --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Files/kubernetes/daemonset.yaml @@ -0,0 +1,38 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: daemonset-vdu5 +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: cirros + name: nginx + imagePullPolicy: IfNotPresent + ports: + - containerPort: 80 + protocol: TCP + env: + - name: CMENV + valueFrom: + configMapKeyRef: + name: cm-data + key: cmKey1.txt + - name: SECENV + valueFrom: + secretKeyRef: + name: secret-data + key: password + envFrom: + - prefix: CM_ + configMapRef: + name: cm-data + - prefix: SEC_ + secretRef: + name: secret-data \ No newline at end of file diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Files/kubernetes/deployment_2.yaml b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Files/kubernetes/deployment_2.yaml new file mode 100644 index 000000000..214e2cd91 --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Files/kubernetes/deployment_2.yaml @@ -0,0 +1,39 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: deployment2-vdu6 +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 + env: + - name: CMENV + valueFrom: + configMapKeyRef: + name: cm-data3 + key: cmKey1.txt + - name: SECENV + valueFrom: + secretKeyRef: + name: secret-data3 + key: password + envFrom: + - prefix: CM_ + configMapRef: + name: cm-data3 + - prefix: SEC_ + secretRef: + name: secret-data3 diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Files/kubernetes/pod_env_2.yaml b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Files/kubernetes/pod_env_2.yaml new file mode 100644 index 000000000..9d1f81b78 --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Files/kubernetes/pod_env_2.yaml @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: Pod +metadata: + name: env-test2 +spec: + containers: + - image: nginx + name: nginx + env: + - name: CMENV + valueFrom: + configMapKeyRef: + name: cm-data3 + key: cmKey1.txt + - name: SECENV + valueFrom: + secretKeyRef: + name: secret-data3 + key: password + envFrom: + - prefix: CM_ + configMapRef: + name: cm-data3 + - prefix: SEC_ + secretRef: + name: secret-data3 diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Files/kubernetes/pod_volume.yaml b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Files/kubernetes/pod_volume.yaml index 0cd6d79bc..c0817b13a 100644 --- a/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Files/kubernetes/pod_volume.yaml +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Files/kubernetes/pod_volume.yaml @@ -6,3 +6,23 @@ spec: containers: - image: cirros name: nginx + volumeMounts: + - name: cm-volume + mountPath: /config + - name: sec-volume + mountPath: /etc/secrets + volumes: + - name: cm-volume + configMap: + name: cm-data + defaultMode: 0666 + items: + - key: cmKey1.txt + path: cm/config.txt + - name: sec-volume + secret: + secretName: secret-data + defaultMode: 0600 + items: + - key: secKey1.txt + path: creds/secret.txt \ No newline at end of file diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Files/kubernetes/pod_volume_2.yaml b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Files/kubernetes/pod_volume_2.yaml new file mode 100644 index 000000000..4430dd74a --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Files/kubernetes/pod_volume_2.yaml @@ -0,0 +1,28 @@ +apiVersion: v1 +kind: Pod +metadata: + name: volume-test2 +spec: + containers: + - image: nginx + name: nginx + volumeMounts: + - name: cm-volume + mountPath: /config + - name: sec-volume + mountPath: /etc/secrets + volumes: + - name: cm-volume + configMap: + name: cm-data3 + defaultMode: 0666 + items: + - key: cmKey1.txt + path: cm/config.txt + - name: sec-volume + secret: + secretName: secret-data3 + defaultMode: 0600 + items: + - key: secKey1.txt + path: creds/secret.txt \ No newline at end of file diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Files/kubernetes/secret_3.yaml b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Files/kubernetes/secret_3.yaml new file mode 100644 index 000000000..f446db475 --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/Files/kubernetes/secret_3.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: secret-data3 +stringData: + password: 1mbb1G968fb1CUg + secKey1.txt: | + secret data + baz \ No newline at end of file diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/TOSCA-Metadata/TOSCA.meta b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/TOSCA-Metadata/TOSCA.meta index f75d8b666..b9ab3cd9b 100644 --- a/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/TOSCA-Metadata/TOSCA.meta +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_after/TOSCA-Metadata/TOSCA.meta @@ -8,20 +8,45 @@ Content-Type: application/yaml Algorithm: SHA-256 Hash: 6f34907da12cb5ad82b25d8e7dd6a7dd4219bd0cbad65e678b58b8466be220e0 +Name: Files/kubernetes/configmap_3.yaml +Content-Type: application/yaml +Algorithm: SHA-256 +Hash: 77561abb949dbc3e71cc7cc5311556f37e69e14743fb6dfe44617ad9929ce615 + +Name: Files/kubernetes/daemonset.yaml +Content-Type: application/yaml +Algorithm: SHA-256 +Hash: 5431163fcba979bcad5f77ef956a5a1cc2069ff0f3e13131ef8826fb7e8f039b + Name: Files/kubernetes/deployment.yaml Content-Type: application/yaml Algorithm: SHA-256 Hash: 290debe315bb5b098f73d63049ba850cc5df3723447637bddc1cabe3d0e151d7 +Name: Files/kubernetes/deployment_2.yaml +Content-Type: application/yaml +Algorithm: SHA-256 +Hash: 3c89ba20b8e49a4d24297e0392e2f8774319cbe131bd28dfe80a263c0f0ce6e0 + Name: Files/kubernetes/pod_env.yaml Content-Type: application/yaml Algorithm: SHA-256 Hash: b8674c55cd387fd2ab3d550bc622b314bed151d0afffe4f6bc44a553280d400c +Name: Files/kubernetes/pod_env_2.yaml +Content-Type: application/yaml +Algorithm: SHA-256 +Hash: 2193e9633c750886ad6d19013887ffe550c94c1da0985fbe60ce8663022c67a5 + Name: Files/kubernetes/pod_volume.yaml Content-Type: application/yaml Algorithm: SHA-256 -Hash: e74cd59b3e91ca1a8fb103b13ef15965581639883cc6d8a531f959b4ae89e688 +Hash: 87507e140db298662b6cf3bc905be42b6697a6724d86ca661bbf28e18ae19397 + +Name: Files/kubernetes/pod_volume_2.yaml +Content-Type: application/yaml +Algorithm: SHA-256 +Hash: 5e29e35c849b2b8677efe8d6ec8554d638481bd41b4705856382698d96bcb040 Name: Files/kubernetes/replicaset.yaml Content-Type: application/yaml @@ -33,7 +58,12 @@ Content-Type: application/yaml Algorithm: SHA-256 Hash: f57cbb1822c57e523e5c6d48feea37ee1b1bbd976d720baf8491d47331249e11 +Name: Files/kubernetes/secret_3.yaml +Content-Type: application/yaml +Algorithm: SHA-256 +Hash: 2a1b16ab7e9ee34a23a67a3aa0535311c927f4194b639bcb0a70905578940695 + Name: Scripts/container_update_mgmt.py Content-Type: text/x-python Algorithm: SHA-256 -Hash: 9e272402dd0f6f6b39ffc750590eedef028ce22506eb7436a1a1fcfa76c66423 \ No newline at end of file +Hash: 334316e69326a0aaad58dc339bc3541786f96bbf1345e9770759d9cab60382f9 diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/Definitions/sample_df_simple.yaml b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/Definitions/sample_df_simple.yaml index 2142be980..d0cd134ff 100644 --- a/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/Definitions/sample_df_simple.yaml +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/Definitions/sample_df_simple.yaml @@ -87,6 +87,43 @@ topology_template: vdu_profile: min_number_of_instances: 1 max_number_of_instances: 1 + + VDU5: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: daemonset-vdu5 + description: kubernetes resource as VDU5 + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 1 + + VDU6: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: deployment2-vdu6 + description: kubernetes resource as VDU6 + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 1 + + VDU7: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: env-test2 + description: kubernetes resource as VDU7 + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 1 + + VDU8: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: volume-test2 + description: kubernetes resource as VDU8 + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 1 + policies: - scaling_aspects: type: tosca.policies.nfv.ScalingAspects diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/Files/kubernetes/configmap_3.yaml b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/Files/kubernetes/configmap_3.yaml new file mode 100644 index 000000000..8b1ffbfcc --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/Files/kubernetes/configmap_3.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm-data3 +data: + cmKey1.txt: | + configmap data + foo + bar \ No newline at end of file diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/Files/kubernetes/daemonset.yaml b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/Files/kubernetes/daemonset.yaml new file mode 100644 index 000000000..e466d74aa --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/Files/kubernetes/daemonset.yaml @@ -0,0 +1,38 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: daemonset-vdu5 +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx + name: nginx + imagePullPolicy: IfNotPresent + ports: + - containerPort: 80 + protocol: TCP + env: + - name: CMENV + valueFrom: + configMapKeyRef: + name: cm-data + key: cmKey1.txt + - name: SECENV + valueFrom: + secretKeyRef: + name: secret-data + key: password + envFrom: + - prefix: CM_ + configMapRef: + name: cm-data + - prefix: SEC_ + secretRef: + name: secret-data \ No newline at end of file diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/Files/kubernetes/deployment_2.yaml b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/Files/kubernetes/deployment_2.yaml new file mode 100644 index 000000000..214e2cd91 --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/Files/kubernetes/deployment_2.yaml @@ -0,0 +1,39 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: deployment2-vdu6 +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 + env: + - name: CMENV + valueFrom: + configMapKeyRef: + name: cm-data3 + key: cmKey1.txt + - name: SECENV + valueFrom: + secretKeyRef: + name: secret-data3 + key: password + envFrom: + - prefix: CM_ + configMapRef: + name: cm-data3 + - prefix: SEC_ + secretRef: + name: secret-data3 diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/Files/kubernetes/pod_env_2.yaml b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/Files/kubernetes/pod_env_2.yaml new file mode 100644 index 000000000..9d1f81b78 --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/Files/kubernetes/pod_env_2.yaml @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: Pod +metadata: + name: env-test2 +spec: + containers: + - image: nginx + name: nginx + env: + - name: CMENV + valueFrom: + configMapKeyRef: + name: cm-data3 + key: cmKey1.txt + - name: SECENV + valueFrom: + secretKeyRef: + name: secret-data3 + key: password + envFrom: + - prefix: CM_ + configMapRef: + name: cm-data3 + - prefix: SEC_ + secretRef: + name: secret-data3 diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/Files/kubernetes/pod_volume_2.yaml b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/Files/kubernetes/pod_volume_2.yaml new file mode 100644 index 000000000..4430dd74a --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/Files/kubernetes/pod_volume_2.yaml @@ -0,0 +1,28 @@ +apiVersion: v1 +kind: Pod +metadata: + name: volume-test2 +spec: + containers: + - image: nginx + name: nginx + volumeMounts: + - name: cm-volume + mountPath: /config + - name: sec-volume + mountPath: /etc/secrets + volumes: + - name: cm-volume + configMap: + name: cm-data3 + defaultMode: 0666 + items: + - key: cmKey1.txt + path: cm/config.txt + - name: sec-volume + secret: + secretName: secret-data3 + defaultMode: 0600 + items: + - key: secKey1.txt + path: creds/secret.txt \ No newline at end of file diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/Files/kubernetes/secret_3.yaml b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/Files/kubernetes/secret_3.yaml new file mode 100644 index 000000000..f446db475 --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/Files/kubernetes/secret_3.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: secret-data3 +stringData: + password: 1mbb1G968fb1CUg + secKey1.txt: | + secret data + baz \ No newline at end of file diff --git a/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/TOSCA-Metadata/TOSCA.meta b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/TOSCA-Metadata/TOSCA.meta index 18920480f..a1e5a4827 100644 --- a/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/TOSCA-Metadata/TOSCA.meta +++ b/tacker/tests/etc/samples/etsi/nfv/test_cnf_container_update_before/TOSCA-Metadata/TOSCA.meta @@ -8,21 +8,46 @@ Content-Type: application/yaml Algorithm: SHA-256 Hash: b914022a12c7a0f3a6a7d14013020f1271645ab44b17942a014fdc8ad96f42fe +Name: Files/kubernetes/configmap_3.yaml +Content-Type: application/yaml +Algorithm: SHA-256 +Hash: 77561abb949dbc3e71cc7cc5311556f37e69e14743fb6dfe44617ad9929ce615 + +Name: Files/kubernetes/daemonset.yaml +Content-Type: application/yaml +Algorithm: SHA-256 +Hash: 289386c71936b758022646248bfd3af90e87e42e6bbf203a6e32cd70905806e6 + Name: Files/kubernetes/deployment.yaml Content-Type: application/yaml Algorithm: SHA-256 Hash: 03b61e9646925ddf414489212736b7d799710b26dc70f96641c50e699f0a1d5f +Name: Files/kubernetes/deployment_2.yaml +Content-Type: application/yaml +Algorithm: SHA-256 +Hash: 3c89ba20b8e49a4d24297e0392e2f8774319cbe131bd28dfe80a263c0f0ce6e0 + Name: Files/kubernetes/pod_env.yaml Content-Type: application/yaml Algorithm: SHA-256 Hash: 2e69400cf742fd88cb9ba5abd0b83ba9dd12f46f36fa615d5b93e07af47a2b5d +Name: Files/kubernetes/pod_env_2.yaml +Content-Type: application/yaml +Algorithm: SHA-256 +Hash: 2193e9633c750886ad6d19013887ffe550c94c1da0985fbe60ce8663022c67a5 + Name: Files/kubernetes/pod_volume.yaml Content-Type: application/yaml Algorithm: SHA-256 Hash: 93bd20b9c2111115131a96769b710e09001248ba9c3d3f33e1d616d0b9546728 +Name: Files/kubernetes/pod_volume_2.yaml +Content-Type: application/yaml +Algorithm: SHA-256 +Hash: 5e29e35c849b2b8677efe8d6ec8554d638481bd41b4705856382698d96bcb040 + Name: Files/kubernetes/replicaset.yaml Content-Type: application/yaml Algorithm: SHA-256 @@ -33,7 +58,12 @@ Content-Type: application/yaml Algorithm: SHA-256 Hash: 8c170000410e72c1b81784061928cde26d1f9ea027fbece4da34ced08da8c4b4 +Name: Files/kubernetes/secret_3.yaml +Content-Type: application/yaml +Algorithm: SHA-256 +Hash: 2a1b16ab7e9ee34a23a67a3aa0535311c927f4194b639bcb0a70905578940695 + Name: Scripts/container_update_mgmt.py Content-Type: text/x-python Algorithm: SHA-256 -Hash: 9e272402dd0f6f6b39ffc750590eedef028ce22506eb7436a1a1fcfa76c66423 \ No newline at end of file +Hash: 334316e69326a0aaad58dc339bc3541786f96bbf1345e9770759d9cab60382f9 diff --git a/tacker/tests/functional/sol_kubernetes/vnflcm/test_kubernetes_container_update.py b/tacker/tests/functional/sol_kubernetes/vnflcm/test_kubernetes_container_update.py index f0a6d0685..3cf5f3d39 100644 --- a/tacker/tests/functional/sol_kubernetes/vnflcm/test_kubernetes_container_update.py +++ b/tacker/tests/functional/sol_kubernetes/vnflcm/test_kubernetes_container_update.py @@ -48,7 +48,14 @@ class VnfLcmKubernetesContainerUpdate(vnflcm_base.BaseVnfLcmKubernetesTest): "Files/kubernetes/pod_env.yaml", "Files/kubernetes/pod_volume.yaml", "Files/kubernetes/replicaset.yaml", - "Files/kubernetes/secret_1.yaml"] + "Files/kubernetes/secret_1.yaml", + "Files/kubernetes/configmap_3.yaml", + "Files/kubernetes/pod_env_2.yaml", + "Files/kubernetes/pod_volume_2.yaml", + "Files/kubernetes/daemonset.yaml", + "Files/kubernetes/deployment_2.yaml", + "Files/kubernetes/secret_3.yaml", + ] additional_param = { "lcm-kubernetes-def-files": files, "namespace": "default"} @@ -59,7 +66,7 @@ class VnfLcmKubernetesContainerUpdate(vnflcm_base.BaseVnfLcmKubernetesTest): vnf_instance_description, additional_param) before_vnfc_rscs = self._get_vnfc_resource_info(vnf_instance) - self.assertEqual(4, len(before_vnfc_rscs)) + self.assertEqual(8, len(before_vnfc_rscs)) # modify vnf_instance_name = "modify_vnf_after" @@ -76,14 +83,17 @@ class VnfLcmKubernetesContainerUpdate(vnflcm_base.BaseVnfLcmKubernetesTest): vnf_instance_after, after_vnfc_rscs = self._modify_vnf_instance( vnf_instance['id'], modify_request_body) - self.assertEqual(4, len(after_vnfc_rscs)) + self.assertEqual(8, len(after_vnfc_rscs)) for after_vnfc_rsc in after_vnfc_rscs: for before_vnfc_rsc in before_vnfc_rscs: after_resource = after_vnfc_rsc['computeResource'] before_resource = before_vnfc_rsc['computeResource'] if after_vnfc_rsc['id'] == before_vnfc_rsc['id']: - if after_resource['vimLevelResourceType'] == 'Deployment': + if (after_resource['vimLevelResourceType'] in + ('Deployment', 'ReplicaSet', 'DaemonSet') + and after_vnfc_rsc['vduId'] in + ('VDU1', 'VDU2', 'VDU5')): # check stored pod name is changed (Deployment) self.assertNotEqual(before_resource['resourceId'], after_resource['resourceId']) diff --git a/tacker/tests/unit/vnfm/mgmt_drivers/fakes.py b/tacker/tests/unit/vnfm/mgmt_drivers/fakes.py index ebb34a505..c11afd50a 100644 --- a/tacker/tests/unit/vnfm/mgmt_drivers/fakes.py +++ b/tacker/tests/unit/vnfm/mgmt_drivers/fakes.py @@ -24,7 +24,6 @@ from tacker.tests import uuidsentinel def get_vnf_instance_object( instantiation_state=fields.VnfInstanceState.NOT_INSTANTIATED): - inst_vnf_info = get_vnf_instantiated_info() vnf_instance = objects.VnfInstance( @@ -93,6 +92,313 @@ def fake_pod(): ) +def fake_pod_container_config_changed(): + return client.V1Pod( + api_version='v1', + kind='Pod', + metadata=client.V1ObjectMeta( + name='volume-test', + namespace='default' + ), + spec=client.V1PodSpec( + containers=[ + client.V1Container( + image="cirros", + name="nginx", + env=[ + client.V1EnvVar( + name='param0', + value_from=client.V1EnvVarSource( + config_map_key_ref=client. + V1ConfigMapKeySelector( + key='param0', + name='cm-data' + ) + ) + ), + client.V1EnvVar( + name='param1', + value_from=client.V1EnvVarSource( + secret_key_ref=client. + V1SecretKeySelector( + key='password', + name='secret-data' + ) + ) + ) + ], + ) + ] + ), + status=client.V1PodStatus( + phase='Running', + ) + ) + + +def fake_pod_volume_config_changed(): + return client.V1Pod( + api_version='v1', + kind='Pod', + metadata=client.V1ObjectMeta( + name='volume-test', + namespace='default' + ), + spec=client.V1PodSpec( + containers=[ + client.V1Container( + image="cirros", + name="nginx", + volume_mounts=[ + client.V1VolumeMount( + name='cm-volume', + mount_path='/config' + ), + client.V1VolumeMount( + name='sec-volume', + mount_path='/etc/secrets' + ), + ] + ) + ], + volumes=[ + client.V1Volume( + name='cm-volume', + config_map=client.V1ConfigMapVolumeSource( + name='cm-data' + ), + ), + client.V1Volume( + name='sec-volume', + secret=client.V1SecretVolumeSource( + secret_name='secret-data' + ) + ) + ] + ), + status=client.V1PodStatus( + phase='Running', + ) + ) + + +def fake_pod_image_changed(): + return client.V1Pod( + api_version='v1', + kind='Pod', + metadata=client.V1ObjectMeta( + name='volume-test', + namespace='default' + ), + spec=client.V1PodSpec( + containers=[ + client.V1Container( + image="nginx-old", + name="nginx", + ) + ] + ), + status=client.V1PodStatus( + phase='Running', + ) + ) + + +def fake_replicaset_container_config_changed(): + return client.V1ReplicaSet( + api_version='apps/v1', + kind='ReplicaSet', + metadata=client.V1ObjectMeta( + name='vdu2', + namespace='default' + ), + spec=client.V1ReplicaSetSpec( + selector=client.V1LabelSelector( + match_labels={'app': 'webserver'} + ), + template=client.V1PodTemplateSpec( + metadata=client.V1ObjectMeta( + labels={'app': 'webserver', + 'scaling_name': 'SP1'} + ), + spec=client.V1PodSpec( + containers=[ + client.V1Container( + env=[ + client.V1EnvVar( + name='param0', + value_from=client.V1EnvVarSource( + config_map_key_ref=client. + V1ConfigMapKeySelector( + key='param0', + name='cm-data' + ) + ) + ), + client.V1EnvVar( + name='param1', + value_from=client.V1EnvVarSource( + secret_key_ref=client. + V1SecretKeySelector( + key='password', + name='secret-data' + ) + ) + ) + ], + image='celebdor/kuryr-demo', + image_pull_policy='IfNotPresent', + name='nginx', + ports=[ + client.V1ContainerPort( + container_port=8080 + ) + ], + resources=client.V1ResourceRequirements( + limits={ + 'cpu': '500m', 'memory': '512M' + }, + requests={ + 'cpu': '500m', 'memory': '512M' + } + ), + volume_mounts=[ + client.V1VolumeMount( + name='curry-claim-volume', + mount_path='/data' + ) + ] + ) + ], + termination_grace_period_seconds=0 + ) + ) + ), + status=client.V1PodStatus( + phase='Running', + ) + ) + + +def fake_replicaset_volume_config_changed(): + return client.V1ReplicaSet( + api_version='apps/v1', + kind='ReplicaSet', + metadata=client.V1ObjectMeta( + name='vdu2', + namespace='default' + ), + spec=client.V1ReplicaSetSpec( + selector=client.V1LabelSelector( + match_labels={'app': 'webserver'} + ), + template=client.V1PodTemplateSpec( + metadata=client.V1ObjectMeta( + labels={'app': 'webserver', + 'scaling_name': 'SP1'} + ), + spec=client.V1PodSpec( + containers=[ + client.V1Container( + image='celebdor/kuryr-demo', + image_pull_policy='IfNotPresent', + name='nginx', + ports=[ + client.V1ContainerPort( + container_port=8080 + ) + ], + resources=client.V1ResourceRequirements( + limits={ + 'cpu': '500m', 'memory': '512M' + }, + requests={ + 'cpu': '500m', 'memory': '512M' + } + ), + volume_mounts=[ + client.V1VolumeMount( + name='curry-claim-volume', + mount_path='/data' + ) + ] + ) + ], + volumes=[ + client.V1Volume( + name='curry-claim-volume', + persistent_volume_claim=client. + V1PersistentVolumeClaimVolumeSource( + claim_name='curry-pv-claim' + ), + config_map=client.V1ConfigMapVolumeSource( + default_mode=438, + name='cm-data' + + ), + secret=client.V1SecretVolumeSource( + secret_name='secret-data' + ) + ) + ], + termination_grace_period_seconds=0 + ) + ) + ), + status=client.V1PodStatus( + phase='Running', + ) + ) + + +def fake_replicaset_image_changed(): + return client.V1ReplicaSet( + api_version='apps/v1', + kind='ReplicaSet', + metadata=client.V1ObjectMeta( + name='vdu2', + namespace='default' + ), + spec=client.V1ReplicaSetSpec( + selector=client.V1LabelSelector( + match_labels={'app': 'webserver'} + ), + template=client.V1PodTemplateSpec( + metadata=client.V1ObjectMeta( + labels={'app': 'webserver', + 'scaling_name': 'SP1'} + ), + spec=client.V1PodSpec( + containers=[ + client.V1Container( + image='celebdor/kuryr-demo-old', + image_pull_policy='IfNotPresent', + name='nginx', + ports=[ + client.V1ContainerPort( + container_port=8080 + ) + ], + resources=client.V1ResourceRequirements( + limits={ + 'cpu': '500m', 'memory': '512M' + }, + requests={ + 'cpu': '500m', 'memory': '512M' + } + ), + ) + ], + termination_grace_period_seconds=0 + ) + ) + ), + status=client.V1PodStatus( + phase='Running', + ) + ) + + def fake_list_pod(): return client.V1PodList( items=[ diff --git a/tacker/tests/unit/vnfm/mgmt_drivers/test_container_update_mgmt.py b/tacker/tests/unit/vnfm/mgmt_drivers/test_container_update_mgmt.py index 7dcc1f785..24e19eb46 100644 --- a/tacker/tests/unit/vnfm/mgmt_drivers/test_container_update_mgmt.py +++ b/tacker/tests/unit/vnfm/mgmt_drivers/test_container_update_mgmt.py @@ -15,6 +15,8 @@ import os +from oslo_config import cfg + from kubernetes import client from samples.mgmt_driver.kubernetes.container_update import ( container_update_mgmt as mgmt_driver) @@ -39,6 +41,7 @@ class TestContainerUpdate(base.TestCase): self.context = context.get_admin_context() self.cntr_update_mgmt = mgmt_driver.ContainerUpdateMgmtDriver() self.vnf_instance = mgmt_fakes.get_vnf_instance_object() + cfg.CONF.kubernetes_vim.stack_retry_wait = 0 self.modify_vnf_request = None self._mock_vim_client() self._stub_get_vim() @@ -108,8 +111,6 @@ class TestContainerUpdate(base.TestCase): {'namespace': 'default', 'object': mgmt_fakes.fake_pod()} ] kube_driver = Kubernetes() - kube_driver.STACK_RETRIES = 1 - kube_driver.STACK_RETRY_WAIT = 5 mock_list_pod.return_value = mgmt_fakes.fake_list_pod() self.assertRaises( exceptions.MgmtDriverOtherError, @@ -137,8 +138,10 @@ class TestContainerUpdate(base.TestCase): @mock.patch.object(client.CoreV1Api, 'replace_namespaced_config_map') @mock.patch.object(client.CoreV1Api, 'replace_namespaced_pod') @mock.patch.object(client.CoreV1Api, 'read_namespaced_pod') + @mock.patch.object(client.AppsV1Api, 'read_namespaced_replica_set') def test_container_update_modify_information_end( - self, mock_read_pod, mock_replace_pod, mock_replace_config_map, + self, mock_read_replica_set, + mock_read_pod, mock_replace_pod, mock_replace_config_map, mock_replace_secret, mock_list_pod, mock_vnfd_dict, mock_save): mock_read_pod.return_value = mgmt_fakes.fake_pod() mock_list_pod.return_value = client.V1PodList(items=[ @@ -154,3 +157,132 @@ class TestContainerUpdate(base.TestCase): self.cntr_update_mgmt.modify_information_end( self.context, self.vnf_instance, self.modify_vnf_request, **kwargs) self.assertEqual(1, mock_save.call_count) + + @mock.patch('tacker.objects.vnf_instance.VnfInstance.save') + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch.object(client.CoreV1Api, 'list_namespaced_pod') + @mock.patch.object(client.CoreV1Api, 'replace_namespaced_secret') + @mock.patch.object(client.CoreV1Api, 'replace_namespaced_config_map') + @mock.patch.object(client.CoreV1Api, 'replace_namespaced_pod') + @mock.patch.object(client.CoreV1Api, 'read_namespaced_pod') + @mock.patch.object(client.AppsV1Api, 'read_namespaced_replica_set') + @mock.patch.object(client.AppsV1Api, 'replace_namespaced_replica_set') + def test_container_update_modify_information_end_container_config_changed( + self, mock_replace_replica_set, mock_read_replicaset, + mock_read_pod, mock_replace_pod, mock_replace_config_map, + mock_replace_secret, mock_list_pod, mock_vnfd_dict, mock_save, + ): + mock_read_replicaset.return_value = (mgmt_fakes. + fake_replicaset_container_config_changed()) + mock_read_pod.return_value = (mgmt_fakes. + fake_pod_container_config_changed()) + mock_list_pod.return_value = client.V1PodList(items=[ + mgmt_fakes.get_fake_pod_info(kind='Pod', name='vdu1')]) + mock_vnfd_dict.return_value = fakes.vnfd_dict_cnf() + kwargs = { + 'old_vnf_package_path': self.yaml_path_before, + 'configmap_secret_paths': [ + "Files/kubernetes/configmap_2.yaml", + "Files/kubernetes/secret_2.yaml" + ] + } + self.cntr_update_mgmt.modify_information_end( + self.context, self.vnf_instance, self.modify_vnf_request, **kwargs) + self.assertEqual(1, mock_save.call_count) + + @mock.patch('tacker.objects.vnf_instance.VnfInstance.save') + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch.object(client.CoreV1Api, 'list_namespaced_pod') + @mock.patch.object(client.CoreV1Api, 'replace_namespaced_secret') + @mock.patch.object(client.CoreV1Api, 'replace_namespaced_config_map') + @mock.patch.object(client.CoreV1Api, 'replace_namespaced_pod') + @mock.patch.object(client.CoreV1Api, 'read_namespaced_pod') + @mock.patch.object(client.AppsV1Api, 'read_namespaced_replica_set') + @mock.patch.object(client.AppsV1Api, 'replace_namespaced_replica_set') + def test_container_update_modify_information_end_volume_config_changed( + self, mock_replace_replica_set, mock_read_replicaset, + mock_read_pod, mock_replace_pod, mock_replace_config_map, + mock_replace_secret, mock_list_pod, mock_vnfd_dict, mock_save, + ): + mock_read_replicaset.return_value = (mgmt_fakes. + fake_replicaset_volume_config_changed()) + mock_read_pod.return_value = (mgmt_fakes. + fake_pod_volume_config_changed()) + mock_list_pod.return_value = client.V1PodList(items=[ + mgmt_fakes.get_fake_pod_info(kind='Pod', name='vdu1')]) + mock_vnfd_dict.return_value = fakes.vnfd_dict_cnf() + kwargs = { + 'old_vnf_package_path': self.yaml_path_before, + 'configmap_secret_paths': [ + "Files/kubernetes/configmap_2.yaml", + "Files/kubernetes/secret_2.yaml" + ] + } + self.cntr_update_mgmt.modify_information_end( + self.context, self.vnf_instance, self.modify_vnf_request, **kwargs) + self.assertEqual(1, mock_save.call_count) + + @mock.patch('tacker.objects.vnf_instance.VnfInstance.save') + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch.object(client.CoreV1Api, 'list_namespaced_pod') + @mock.patch.object(client.CoreV1Api, 'replace_namespaced_secret') + @mock.patch.object(client.CoreV1Api, 'replace_namespaced_config_map') + @mock.patch.object(client.CoreV1Api, 'replace_namespaced_pod') + @mock.patch.object(client.CoreV1Api, 'read_namespaced_pod') + @mock.patch.object(client.AppsV1Api, 'read_namespaced_replica_set') + @mock.patch.object(client.AppsV1Api, 'replace_namespaced_replica_set') + def test_container_update_modify_information_end_image_changed( + self, mock_replace_replica_set, mock_read_replicaset, + mock_read_pod, mock_replace_pod, mock_replace_config_map, + mock_replace_secret, mock_list_pod, mock_vnfd_dict, mock_save, + ): + mock_read_replicaset.return_value = (mgmt_fakes. + fake_replicaset_image_changed()) + mock_read_pod.return_value = mgmt_fakes.fake_pod_image_changed() + mock_list_pod.return_value = client.V1PodList(items=[ + mgmt_fakes.get_fake_pod_info(kind='Pod', name='vdu1')]) + mock_vnfd_dict.return_value = fakes.vnfd_dict_cnf() + kwargs = { + 'old_vnf_package_path': self.yaml_path_before, + 'configmap_secret_paths': [ + "Files/kubernetes/configmap_2.yaml", + "Files/kubernetes/secret_2.yaml" + ] + } + self.cntr_update_mgmt.modify_information_end( + self.context, self.vnf_instance, self.modify_vnf_request, **kwargs) + self.assertEqual(1, mock_save.call_count) + + @mock.patch('tacker.objects.vnf_instance.VnfInstance.save') + @mock.patch('tacker.vnflcm.utils._get_vnfd_dict') + @mock.patch.object(client.CoreV1Api, 'list_namespaced_pod') + @mock.patch.object(client.CoreV1Api, 'replace_namespaced_secret') + @mock.patch.object(client.CoreV1Api, 'replace_namespaced_config_map') + @mock.patch.object(client.CoreV1Api, 'replace_namespaced_pod') + @mock.patch.object(client.CoreV1Api, 'read_namespaced_pod') + @mock.patch.object(client.AppsV1Api, 'read_namespaced_replica_set') + @mock.patch.object(client.AppsV1Api, 'replace_namespaced_replica_set') + @mock.patch.object(client.CoreV1Api, 'delete_namespaced_pod') + def test_container_update_modify_information_end_replicasetpod_deleted( + self, mock_delete_namespaced_pod, + mock_replace_replica_set, mock_read_replicaset, + mock_read_pod, mock_replace_pod, mock_replace_config_map, + mock_replace_secret, mock_list_pod, mock_vnfd_dict, mock_save, + ): + mock_read_replicaset.return_value = (mgmt_fakes. + fake_replicaset_image_changed()) + mock_read_pod.return_value = mgmt_fakes.fake_pod() + mock_list_pod.return_value = client.V1PodList(items=[ + mgmt_fakes.get_fake_pod_info(kind='Pod', + name='vdu2-rldmg')]) + mock_vnfd_dict.return_value = fakes.vnfd_dict_cnf() + kwargs = { + 'old_vnf_package_path': self.yaml_path_before, + 'configmap_secret_paths': [ + "Files/kubernetes/configmap_2.yaml", + "Files/kubernetes/secret_2.yaml" + ] + } + self.cntr_update_mgmt.modify_information_end( + self.context, self.vnf_instance, self.modify_vnf_request, **kwargs) + self.assertEqual(1, mock_save.call_count)