support fail operation task of v2 API
This patch implements fail operation task defined in ETSI NFV-SOL003 v3.3.1 5.4.16. Fail operation is changed the state to "FAILED" when the retry or rollback operation unsuccessful. Functional tests will be provided with another patch. Implements: blueprint support-nfv-solv3-error-handling Change-Id: I3a64acde4cfdfeef18959a80a3a86b3c7f1023dd
This commit is contained in:
parent
d3b8083d35
commit
94dbcea96a
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
Add the Version "2.0.0" of Fail operation API
|
||||
based on ETSI NFV specifications.
|
|
@ -168,6 +168,15 @@ rules = [
|
|||
'path': VNF_LCM_OP_OCCS_ID_PATH + '/rollback'}
|
||||
]
|
||||
),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=POLICY_NAME.format('lcm_op_occ_fail'),
|
||||
check_str=RULE_ANY,
|
||||
description="Fail VnfLcmOpOcc.",
|
||||
operations=[
|
||||
{'method': 'POST',
|
||||
'path': VNF_LCM_OP_OCCS_ID_PATH + '/fail'}
|
||||
]
|
||||
),
|
||||
# NOTE: 'DELETE' is not defined in the specification. It is for test
|
||||
# use since it is convenient to be able to delete under development.
|
||||
# It is available when config parameter
|
||||
|
|
|
@ -47,6 +47,7 @@ class VnflcmAPIRouterV2(sol_wsgi.SolAPIRouter):
|
|||
("/vnf_lcm_op_occs", {"GET": "lcm_op_occ_list"}),
|
||||
("/vnf_lcm_op_occs/{id}/retry", {"POST": "lcm_op_occ_retry"}),
|
||||
("/vnf_lcm_op_occs/{id}/rollback", {"POST": "lcm_op_occ_rollback"}),
|
||||
("/vnf_lcm_op_occs/{id}/fail", {"POST": "lcm_op_occ_fail"}),
|
||||
# NOTE: 'DELETE' is not defined in the specification. It is for test
|
||||
# use since it is convenient to be able to delete under development.
|
||||
# It is available when config parameter
|
||||
|
|
|
@ -55,13 +55,14 @@ def make_lcmocc_links(lcmocc, endpoint):
|
|||
links.vnfInstance = objects.Link(
|
||||
href=inst_utils.inst_href(lcmocc.vnfInstanceId, endpoint))
|
||||
links.retry = objects.Link(
|
||||
href=lcmocc_task_href(lcmocc.vnfInstanceId, 'retry', endpoint))
|
||||
href=lcmocc_task_href(lcmocc.id, 'retry', endpoint))
|
||||
links.rollback = objects.Link(
|
||||
href=lcmocc_task_href(lcmocc.vnfInstanceId, 'rollback', endpoint))
|
||||
href=lcmocc_task_href(lcmocc.id, 'rollback', endpoint))
|
||||
links.fail = objects.Link(
|
||||
href=lcmocc_task_href(lcmocc.id, 'fail', endpoint))
|
||||
# TODO(oda-g): add when implemented
|
||||
# links.grant
|
||||
# links.cancel
|
||||
# links.fail
|
||||
# links.vnfSnapshot
|
||||
|
||||
return links
|
||||
|
|
|
@ -359,6 +359,35 @@ class VnfLcmControllerV2(sol_wsgi.SolAPIController):
|
|||
|
||||
return sol_wsgi.SolResponse(202, None)
|
||||
|
||||
def lcm_op_occ_fail(self, request, id):
|
||||
context = request.context
|
||||
lcmocc = lcmocc_utils.get_lcmocc(context, id)
|
||||
|
||||
return self._lcm_op_occ_fail(context, lcmocc)
|
||||
|
||||
@coordinate.lock_vnf_instance('{lcmocc.vnfInstanceId}')
|
||||
def _lcm_op_occ_fail(self, context, lcmocc):
|
||||
if lcmocc.operationState != v2fields.LcmOperationStateType.FAILED_TEMP:
|
||||
raise sol_ex.LcmOpOccNotFailedTemp(lcmocc_id=lcmocc.id)
|
||||
|
||||
inst = inst_utils.get_inst(context, lcmocc.vnfInstanceId)
|
||||
grant_req, grant = lcmocc_utils.get_grant_req_and_grant(context,
|
||||
lcmocc)
|
||||
|
||||
lcmocc.operationState = v2fields.LcmOperationStateType.FAILED
|
||||
with context.session.begin(subtransactions=True):
|
||||
lcmocc.update(context)
|
||||
grant_req.delete(context)
|
||||
grant.delete(context)
|
||||
|
||||
# send notification FAILED
|
||||
self.nfvo_client.send_lcmocc_notification(context, lcmocc, inst,
|
||||
self.endpoint)
|
||||
|
||||
resp_body = self._lcmocc_view.detail(lcmocc)
|
||||
|
||||
return sol_wsgi.SolResponse(200, resp_body)
|
||||
|
||||
def lcm_op_occ_delete(self, request, id):
|
||||
# not allowed to delete on the specification
|
||||
if not CONF.v2_vnfm.test_enable_lcm_op_occ_delete:
|
||||
|
|
|
@ -98,6 +98,11 @@ class Client(object):
|
|||
path = self.path + '/' + id + '/rollback'
|
||||
resp, body = self.client.do_request(path, "POST", version="2.0.0")
|
||||
|
||||
def fail(self, id):
|
||||
path = self.path + '/' + id + '/fail'
|
||||
resp, body = self.client.do_request(path, "POST", version="2.0.0")
|
||||
self.print(resp, body)
|
||||
|
||||
|
||||
def usage():
|
||||
print("usage: cli resource action [arg...]")
|
||||
|
@ -116,6 +121,7 @@ def usage():
|
|||
print(" lcmocc delete {id}")
|
||||
print(" lcmocc retry {id}")
|
||||
print(" lcmocc rollback {id}")
|
||||
print(" lcmocc fail {id}")
|
||||
os._exit(1)
|
||||
|
||||
|
||||
|
@ -139,7 +145,8 @@ if __name__ == '__main__':
|
|||
usage()
|
||||
client = Client("/vnflcm/v2/subscriptions")
|
||||
elif resource == "lcmocc":
|
||||
if action not in ["list", "show", "delete", "retry", "rollback"]:
|
||||
if action not in ["list", "show", "delete", "retry", "rollback",
|
||||
"fail"]:
|
||||
usage()
|
||||
client = Client("/vnflcm/v2/vnf_lcm_op_occs")
|
||||
else:
|
||||
|
@ -180,3 +187,7 @@ if __name__ == '__main__':
|
|||
if len(sys.argv) != 4:
|
||||
usage()
|
||||
client.rollback(sys.argv[3])
|
||||
elif action == "fail":
|
||||
if len(sys.argv) != 4:
|
||||
usage()
|
||||
client.fail(sys.argv[3])
|
||||
|
|
|
@ -21,6 +21,7 @@ from oslo_utils import uuidutils
|
|||
from tacker import context
|
||||
from tacker.sol_refactored.api import api_version
|
||||
from tacker.sol_refactored.common import exceptions as sol_ex
|
||||
from tacker.sol_refactored.common import lcm_op_occ_utils as lcmocc_utils
|
||||
from tacker.sol_refactored.controller import vnflcm_v2
|
||||
from tacker.sol_refactored.nfvo import nfvo_client
|
||||
from tacker.sol_refactored import objects
|
||||
|
@ -39,7 +40,7 @@ class TestVnflcmV2(db_base.SqlTestCase):
|
|||
self.request = mock.Mock()
|
||||
self.request.context = self.context
|
||||
|
||||
def _create_inst_and_lcmocc(self, inst_state, op_state):
|
||||
def _set_inst_and_lcmocc(self, inst_state, op_state):
|
||||
inst = objects.VnfInstanceV2(
|
||||
# required fields
|
||||
id=uuidutils.generate_uuid(),
|
||||
|
@ -62,7 +63,13 @@ class TestVnflcmV2(db_base.SqlTestCase):
|
|||
operation=fields.LcmOperationType.INSTANTIATE,
|
||||
isAutomaticInvocation=False,
|
||||
isCancelPending=False,
|
||||
operationParams=req)
|
||||
operationParams=req
|
||||
)
|
||||
|
||||
return inst, lcmocc
|
||||
|
||||
def _create_inst_and_lcmocc(self, inst_state, op_state):
|
||||
inst, lcmocc = self._set_inst_and_lcmocc(inst_state, op_state)
|
||||
|
||||
inst.create(self.context)
|
||||
lcmocc.create(self.context)
|
||||
|
@ -191,3 +198,64 @@ class TestVnflcmV2(db_base.SqlTestCase):
|
|||
self.assertRaises(sol_ex.LcmOpOccNotFailedTemp,
|
||||
self.controller.lcm_op_occ_rollback, request=self.request,
|
||||
id=lcmocc_id)
|
||||
|
||||
def test_fail_not_failed_temp(self):
|
||||
_, lcmocc_id = self._create_inst_and_lcmocc('INSTANTIATED',
|
||||
fields.LcmOperationStateType.COMPLETED)
|
||||
|
||||
self.assertRaises(sol_ex.LcmOpOccNotFailedTemp,
|
||||
self.controller.lcm_op_occ_fail, request=self.request,
|
||||
id=lcmocc_id)
|
||||
|
||||
def _prepare_db_for_fail(self):
|
||||
inst, lcmocc = self._set_inst_and_lcmocc('NOT_INSTANTIATED',
|
||||
fields.LcmOperationStateType.FAILED_TEMP)
|
||||
|
||||
inst.create(self.context)
|
||||
lcmocc.create(self.context)
|
||||
|
||||
grant_req = objects.GrantRequestV1(
|
||||
# required fields
|
||||
vnfInstanceId=lcmocc.vnfInstanceId,
|
||||
vnfLcmOpOccId=lcmocc.id,
|
||||
vnfdId=uuidutils.generate_uuid(),
|
||||
operation=lcmocc.operation,
|
||||
isAutomaticInvocation=lcmocc.isAutomaticInvocation
|
||||
)
|
||||
|
||||
grant = objects.GrantV1(
|
||||
# required fields
|
||||
id=uuidutils.generate_uuid(),
|
||||
vnfInstanceId=lcmocc.vnfInstanceId,
|
||||
vnfLcmOpOccId=lcmocc.id
|
||||
)
|
||||
|
||||
grant_req.create(self.context)
|
||||
grant.create(self.context)
|
||||
lcmocc.grantId = grant.id
|
||||
lcmocc.update(self.context)
|
||||
|
||||
return lcmocc
|
||||
|
||||
@mock.patch.object(nfvo_client.NfvoClient, 'send_lcmocc_notification')
|
||||
def test_lcm_op_occ_fail(self, mocked_send_lcmocc_notification):
|
||||
# prepare
|
||||
lcmocc = self._prepare_db_for_fail()
|
||||
|
||||
op_state = []
|
||||
|
||||
def _store_state(context, lcmocc, inst, endpoint):
|
||||
op_state.append(lcmocc.operationState)
|
||||
|
||||
mocked_send_lcmocc_notification.side_effect = _store_state
|
||||
|
||||
# run lcm_op_occ_fail
|
||||
self.controller.lcm_op_occ_fail(self.request, lcmocc.id)
|
||||
|
||||
# check operationstate
|
||||
self.assertEqual(1, mocked_send_lcmocc_notification.call_count)
|
||||
self.assertEqual(fields.LcmOperationStateType.FAILED, op_state[0])
|
||||
|
||||
# check grant_req and grant are deleted
|
||||
self.assertRaises(sol_ex.GrantRequestOrGrantNotFound,
|
||||
lcmocc_utils.get_grant_req_and_grant, self.context, lcmocc)
|
||||
|
|
Loading…
Reference in New Issue