Merge "Fix cnf rollback after instantiation failure"

This commit is contained in:
Zuul 2021-09-15 10:36:48 +00:00 committed by Gerrit Code Review
commit 28df9a4eae
5 changed files with 147 additions and 3 deletions

View File

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

View File

@ -136,4 +136,9 @@ Hash: ef937e9c90c1cb6093092ba2043c11e353d572736b04f798a49b785049fec552
Name: Files/kubernetes/token-review.yaml Name: Files/kubernetes/token-review.yaml
Content-Type: test-data Content-Type: test-data
Algorithm: SHA-256 Algorithm: SHA-256
Hash: 468d9d53a3125c5850c6473d324c94f00b91a1e3536d1a62c7c7eb80fd7aa6d2 Hash: 468d9d53a3125c5850c6473d324c94f00b91a1e3536d1a62c7c7eb80fd7aa6d2
Name: Files/kubernetes/statefulset_fail.yaml
Content-Type: test-data
Algorithm: SHA-256
Hash: 71a99017964b8ce1dfbbade92f3cdf42f1e5b774c6e7edb7aa83c5eee42e5d5e

View File

@ -20,8 +20,16 @@ import unittest
from oslo_serialization import jsonutils from oslo_serialization import jsonutils
from oslo_utils import uuidutils 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 fields
from tacker.objects import vnf_lcm_op_occs
from tacker.tests.functional import base from tacker.tests.functional import base
from tacker.tests import utils from tacker.tests import utils
@ -112,6 +120,8 @@ class VnfLcmTest(base.BaseTackerTest):
def setUp(self): def setUp(self):
super(VnfLcmTest, self).setUp() super(VnfLcmTest, self).setUp()
self.base_url = "/vnflcm/v1/vnf_instances" 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() vim_list = self.client.list_vims()
if not vim_list: if not vim_list:
@ -1045,3 +1055,92 @@ class VnfLcmTest(base.BaseTackerTest):
self._terminate_vnf_instance(vnf_instance['id'], terminate_req_body) self._terminate_vnf_instance(vnf_instance['id'], terminate_req_body)
self._delete_vnf_instance(vnf_instance['id']) 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'])

View File

@ -1600,11 +1600,13 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver):
access_info = vim_connection_info.access_info access_info = vim_connection_info.access_info
self._vnf_manager.invoke(vim_connection_info.vim_type, self._vnf_manager.invoke(vim_connection_info.vim_type,
'delete', plugin=self, context=context, '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, self._vnf_manager.invoke(vim_connection_info.vim_type,
'delete_wait', plugin=self, context=context, '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 vnf_lcm_op_occs.error_point = EP.PRE_VIM_CONTROL

View File

@ -33,6 +33,7 @@ from tacker.common import log
from tacker.common import utils from tacker.common import utils
from tacker.extensions import vnfm from tacker.extensions import vnfm
from tacker import objects 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 as vnf_package_obj
from tacker.objects import vnf_package_vnfd as vnfd_obj from tacker.objects import vnf_package_vnfd as vnfd_obj
from tacker.objects import vnf_resources as vnf_resource_obj from tacker.objects import vnf_resources as vnf_resource_obj
@ -1511,6 +1512,7 @@ class Kubernetes(abstract_driver.VnfAbstractDriver,
k8s_objs = transformer.\ 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)
k8s_objs = transformer.deploy_k8s(k8s_objs) k8s_objs = transformer.deploy_k8s(k8s_objs)
vnfd_dict['current_error_point'] = EP.POST_VIM_CONTROL
k8s_objs = self.create_wait_k8s( k8s_objs = self.create_wait_k8s(
k8s_objs, k8s_client_dict, vnf_instance) k8s_objs, k8s_client_dict, vnf_instance)
for k8s_obj in k8s_objs: for k8s_obj in k8s_objs: