diff --git a/tacker/tests/etc/samples/etsi/nfv/test_create_vnf_instance_and_instantiate_and_terminate_cnf_resources/Files/kubernetes/statefulset_fail.yaml b/tacker/tests/etc/samples/etsi/nfv/test_create_vnf_instance_and_instantiate_and_terminate_cnf_resources/Files/kubernetes/statefulset_fail.yaml new file mode 100644 index 000000000..dc109a9d0 --- /dev/null +++ b/tacker/tests/etc/samples/etsi/nfv/test_create_vnf_instance_and_instantiate_and_terminate_cnf_resources/Files/kubernetes/statefulset_fail.yaml @@ -0,0 +1,36 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: vdu2-fail + namespace: default +spec: + selector: + matchLabels: + app: nginx + serviceName: "nginx" + replicas: 2 + template: + metadata: + labels: + app: nginx + spec: + terminationGracePeriodSeconds: 10 + containers: + - name: nginx + image: k8s.gcr.io/nginx-slim:0.8 + ports: + - containerPort: 80 + name: web + volumeMounts: + - name: www + mountPath: /usr/share/nginx/html + volumeClaimTemplates: + - metadata: + name: www + spec: + accessModes: + - ReadWriteOnce + storageClassName: "curry-sc-local-fail" + resources: + requests: + storage: 1Gi diff --git a/tacker/tests/etc/samples/etsi/nfv/test_create_vnf_instance_and_instantiate_and_terminate_cnf_resources/TOSCA-Metadata/TOSCA.meta b/tacker/tests/etc/samples/etsi/nfv/test_create_vnf_instance_and_instantiate_and_terminate_cnf_resources/TOSCA-Metadata/TOSCA.meta index bdeb12777..afa3cd08c 100644 --- a/tacker/tests/etc/samples/etsi/nfv/test_create_vnf_instance_and_instantiate_and_terminate_cnf_resources/TOSCA-Metadata/TOSCA.meta +++ b/tacker/tests/etc/samples/etsi/nfv/test_create_vnf_instance_and_instantiate_and_terminate_cnf_resources/TOSCA-Metadata/TOSCA.meta @@ -136,4 +136,9 @@ Hash: ef937e9c90c1cb6093092ba2043c11e353d572736b04f798a49b785049fec552 Name: Files/kubernetes/token-review.yaml Content-Type: test-data Algorithm: SHA-256 -Hash: 468d9d53a3125c5850c6473d324c94f00b91a1e3536d1a62c7c7eb80fd7aa6d2 \ No newline at end of file +Hash: 468d9d53a3125c5850c6473d324c94f00b91a1e3536d1a62c7c7eb80fd7aa6d2 + +Name: Files/kubernetes/statefulset_fail.yaml +Content-Type: test-data +Algorithm: SHA-256 +Hash: 71a99017964b8ce1dfbbade92f3cdf42f1e5b774c6e7edb7aa83c5eee42e5d5e diff --git a/tacker/tests/functional/sol_kubernetes/vnflcm/test_kubernetes.py b/tacker/tests/functional/sol_kubernetes/vnflcm/test_kubernetes.py index b4e3f5f0a..b1d869d95 100644 --- a/tacker/tests/functional/sol_kubernetes/vnflcm/test_kubernetes.py +++ b/tacker/tests/functional/sol_kubernetes/vnflcm/test_kubernetes.py @@ -20,8 +20,16 @@ import unittest from oslo_serialization import jsonutils from oslo_utils import uuidutils +from sqlalchemy import desc +from sqlalchemy.orm import joinedload +from tacker.common import exceptions +from tacker import context +from tacker.db import api as db_api +from tacker.db.db_sqlalchemy import api +from tacker.db.db_sqlalchemy import models from tacker.objects import fields +from tacker.objects import vnf_lcm_op_occs from tacker.tests.functional import base from tacker.tests import utils @@ -112,6 +120,8 @@ class VnfLcmTest(base.BaseTackerTest): def setUp(self): super(VnfLcmTest, self).setUp() self.base_url = "/vnflcm/v1/vnf_instances" + self.base_vnf_lcm_op_occs_url = "/vnflcm/v1/vnf_lcm_op_occs" + self.context = context.get_admin_context() vim_list = self.client.list_vims() if not vim_list: @@ -1045,3 +1055,92 @@ class VnfLcmTest(base.BaseTackerTest): self._terminate_vnf_instance(vnf_instance['id'], terminate_req_body) self._delete_vnf_instance(vnf_instance['id']) + + @db_api.context_manager.reader + def _vnf_notify_get_by_id(self, context, vnf_instance_id, + columns_to_join=None): + query = api.model_query( + context, models.VnfLcmOpOccs, + read_deleted="no", project_only=True).filter_by( + vnf_instance_id=vnf_instance_id).order_by( + desc("created_at")) + + if columns_to_join: + for column in columns_to_join: + query = query.options(joinedload(column)) + + db_vnflcm_op_occ = query.first() + + if not db_vnflcm_op_occ: + raise exceptions.VnfInstanceNotFound(id=vnf_instance_id) + + vnflcm_op_occ = vnf_lcm_op_occs.VnfLcmOpOcc.obj_from_db_obj( + context, db_vnflcm_op_occ) + return vnflcm_op_occ + + def _wait_vnflcm_op_occs( + self, context, vnf_instance_id, + operation_state='COMPLETED'): + timeout = VNF_INSTANTIATE_TIMEOUT + start_time = int(time.time()) + while True: + vnflcm_op_occ = self._vnf_notify_get_by_id( + context, vnf_instance_id) + + if vnflcm_op_occ.operation_state == operation_state: + break + + if ((int(time.time()) - start_time) > timeout): + raise Exception("Failed to wait instantiate instance") + + time.sleep(RETRY_WAIT_TIME) + + def _instantiate_vnf_instance_wait_fail(self, id, request_body): + url = os.path.join(self.base_url, id, "instantiate") + resp, body = self.http_client.do_request( + url, "POST", body=jsonutils.dumps(request_body)) + self.assertEqual(202, resp.status_code) + # wait vnflcm_op_occs.operation_state become FAILED_TEMP + self._wait_vnflcm_op_occs(self.context, id, "FAILED_TEMP") + + def _rollback_vnf_instance(self, vnf_lcm_op_occ_id): + url = os.path.join( + self.base_vnf_lcm_op_occs_url, vnf_lcm_op_occ_id, "rollback") + # generate body + resp, body = self.http_client.do_request(url, "POST") + self.assertEqual(202, resp.status_code) + + def test_rollback_cnf_after_instantiate_fail(self): + vnf_instance_name = "vnf_rollback_cnf_after_instantiate_fail" + vnf_instance_description = "vnf rollback cnf after instantiate fail" + resp, vnf_instance = self._create_vnf_instance( + self.vnfd_id_resource, + vnf_instance_name=vnf_instance_name, + vnf_instance_description=vnf_instance_description) + + self.assertIsNotNone(vnf_instance['id']) + self.assertEqual(201, resp.status_code) + + additional_param = { + "lcm-kubernetes-def-files": [ + "Files/kubernetes/statefulset_fail.yaml", + ] + } + request_body = self._instantiate_vnf_instance_request( + "simple", vim_id=self.vim_id, additional_param=additional_param) + + self._instantiate_vnf_instance_wait_fail( + vnf_instance['id'], request_body) + + # get vnflcm_op_occ id for rollback + vnflcm_op_occ = self._vnf_notify_get_by_id( + self.context, vnf_instance['id']) + vnf_lcm_op_occ_id = vnflcm_op_occ.id + + # rollback operation + self._rollback_vnf_instance(vnf_lcm_op_occ_id) + # wait vnflcm_op_occs.operation_state become ROLLED_BACK + self._wait_vnflcm_op_occs( + self.context, vnf_instance['id'], "ROLLED_BACK") + + self._delete_vnf_instance(vnf_instance['id']) diff --git a/tacker/vnflcm/vnflcm_driver.py b/tacker/vnflcm/vnflcm_driver.py index 028e59b26..df2da368e 100644 --- a/tacker/vnflcm/vnflcm_driver.py +++ b/tacker/vnflcm/vnflcm_driver.py @@ -1600,11 +1600,13 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver): access_info = vim_connection_info.access_info self._vnf_manager.invoke(vim_connection_info.vim_type, 'delete', plugin=self, context=context, - vnf_id=instance_id, auth_attr=access_info) + vnf_id=instance_id, auth_attr=access_info, + vnf_instance=vnf_instance) self._vnf_manager.invoke(vim_connection_info.vim_type, 'delete_wait', plugin=self, context=context, - vnf_id=instance_id, auth_attr=access_info) + vnf_id=instance_id, auth_attr=access_info, + vnf_instance=vnf_instance) vnf_lcm_op_occs.error_point = EP.PRE_VIM_CONTROL diff --git a/tacker/vnfm/infra_drivers/kubernetes/kubernetes_driver.py b/tacker/vnfm/infra_drivers/kubernetes/kubernetes_driver.py index f08855718..338ab6dad 100644 --- a/tacker/vnfm/infra_drivers/kubernetes/kubernetes_driver.py +++ b/tacker/vnfm/infra_drivers/kubernetes/kubernetes_driver.py @@ -33,6 +33,7 @@ from tacker.common import log from tacker.common import utils from tacker.extensions import vnfm from tacker import objects +from tacker.objects.fields import ErrorPoint as EP from tacker.objects import vnf_package as vnf_package_obj from tacker.objects import vnf_package_vnfd as vnfd_obj from tacker.objects import vnf_resources as vnf_resource_obj @@ -1511,6 +1512,7 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, k8s_objs = transformer.\ get_k8s_objs_from_yaml(target_k8s_files, vnf_package_path) k8s_objs = transformer.deploy_k8s(k8s_objs) + vnfd_dict['current_error_point'] = EP.POST_VIM_CONTROL k8s_objs = self.create_wait_k8s( k8s_objs, k8s_client_dict, vnf_instance) for k8s_obj in k8s_objs: