From: Gulsum Atici Date: Mon, 24 Apr 2023 11:54:20 +0000 (+0300) Subject: OSMENG-994 Determine the content for Activity errors X-Git-Url: https://osm.etsi.org/gitweb/?a=commitdiff_plain;h=refs%2Fchanges%2F62%2F13262%2F12;p=osm%2FLCM.git OSMENG-994 Determine the content for Activity errors Change-Id: Id86f1fa5a5adadac333842d81d9ba4f2dff69d8f Signed-off-by: Gulsum Atici --- diff --git a/osm_lcm/temporal/lcm_workflows.py b/osm_lcm/temporal/lcm_workflows.py index 9ab8e5d..9ee94d8 100644 --- a/osm_lcm/temporal/lcm_workflows.py +++ b/osm_lcm/temporal/lcm_workflows.py @@ -18,6 +18,9 @@ import logging import traceback from abc import ABC, abstractmethod from datetime import timedelta +from temporalio import workflow +from temporalio.common import RetryPolicy +from temporalio.exceptions import ActivityError, ChildWorkflowError from osm_common.dataclasses.temporal_dataclasses import ( LcmOperationState, @@ -29,9 +32,6 @@ from osm_common.temporal_constants import ( ACTIVITY_UPDATE_LCM_OPERATION_STATE, WORKFLOW_NSLCM_NO_OP, ) -from temporalio import workflow -from temporalio.common import RetryPolicy -from temporalio.exceptions import ActivityError class LcmOperationWorkflow(ABC): @@ -73,23 +73,37 @@ class LcmOperationWorkflow(ABC): await self.update_operation_state(LcmOperationState.PROCESSING) try: await self.workflow(input=input) + except ActivityError as e: - # TODO: Deteremine the best content for Activity Errors OSM-994 - self.logger.exception(e) + err_details = str(e.cause.with_traceback(e.__traceback__)) + self.logger.error(err_details) await self.update_operation_state( LcmOperationState.FAILED, error_message=str(e.cause.message), - detailed_status=str(e.cause.with_traceback(e.__traceback__)), + detailed_status=err_details, ) raise e + + except ChildWorkflowError as e: + err_details = str(e.cause.cause.cause.with_traceback(e.cause.__traceback__)) + self.logger.error(err_details) + await self.update_operation_state( + LcmOperationState.FAILED, + error_message=str(e.cause.cause.message), + detailed_status=err_details, + ) + raise e + except Exception as e: - self.logger.exception(e) - self.update_operation_state( + err_details = str(traceback.format_exc()) + self.logger.error(err_details) + await self.update_operation_state( LcmOperationState.FAILED, error_message=str(e), - detailed_status=traceback.format_exc(), + detailed_status=err_details, ) raise e + await self.update_operation_state(LcmOperationState.COMPLETED) async def update_operation_state( diff --git a/osm_lcm/temporal/ns_workflows.py b/osm_lcm/temporal/ns_workflows.py index 9a4e0ee..343a9c9 100644 --- a/osm_lcm/temporal/ns_workflows.py +++ b/osm_lcm/temporal/ns_workflows.py @@ -15,6 +15,10 @@ # limitations under the License. import asyncio +from temporalio import workflow +from temporalio.converter import value_to_type +from temporalio.exceptions import ActivityError, ChildWorkflowError +import traceback from osm_common.dataclasses.temporal_dataclasses import ( GetVnfRecordIdsInput, @@ -32,10 +36,6 @@ from osm_common.temporal_constants import ( WORKFLOW_NS_INSTANTIATE, WORKFLOW_VNF_INSTANTIATE, ) -from temporalio import workflow -from temporalio.converter import value_to_type -from temporalio.exceptions import ActivityError - from osm_lcm.temporal.lcm_workflows import LcmOperationWorkflow @@ -88,16 +88,23 @@ class NsInstantiateWorkflow(LcmOperationWorkflow): ) except ActivityError as e: - await self.update_ns_state(ns_uuid, NsState.INSTANTIATED, e.cause.message) - self.logger.error( - f"{WORKFLOW_NS_INSTANTIATE} failed with {str(e.cause.message)}" - ) + err_details = str(e.cause.with_traceback(e.__traceback__)) + await self.update_ns_state(ns_uuid, NsState.INSTANTIATED, err_details) + self.logger.error(f"{WORKFLOW_NS_INSTANTIATE} failed with {err_details}") + raise e + + except ChildWorkflowError as e: + err_details = str(e.cause.cause.cause.with_traceback(e.cause.__traceback__)) + await self.update_ns_state(ns_uuid, NsState.INSTANTIATED, err_details) + self.logger.error(f"{WORKFLOW_NS_INSTANTIATE} failed with {err_details}") raise e except Exception as e: - await self.update_ns_state(ns_uuid, NsState.INSTANTIATED, str(e)) - self.logger.error(f"{WORKFLOW_NS_INSTANTIATE} failed with {str(e)}") + err_details = str(traceback.format_exc()) + await self.update_ns_state(ns_uuid, NsState.INSTANTIATED, err_details) + self.logger.error(f"{WORKFLOW_NS_INSTANTIATE} failed with {err_details}") raise e + await self.update_ns_state(ns_uuid, NsState.INSTANTIATED, "Done") @staticmethod diff --git a/osm_lcm/temporal/vdu_workflows.py b/osm_lcm/temporal/vdu_workflows.py index edb1235..0c91e99 100644 --- a/osm_lcm/temporal/vdu_workflows.py +++ b/osm_lcm/temporal/vdu_workflows.py @@ -18,6 +18,8 @@ from datetime import timedelta import logging from temporalio import workflow from temporalio.common import RetryPolicy +from temporalio.exceptions import ActivityError +import traceback from osm_common.dataclasses.temporal_dataclasses import ( VduInstantiateInput, @@ -75,6 +77,12 @@ class VduInstantiateWorkflow: self.logger.info(f"VDU `{input.charm_info.app_name}` is ready") + except ActivityError as e: + err_details = str(e.cause.with_traceback(e.__traceback__)) + self.logger.error(f"{WORKFLOW_VDU_INSTANTIATE} failed with {err_details}") + raise e + except Exception as e: - self.logger.error(f"{WORKFLOW_VDU_INSTANTIATE} failed with {str(e)}") + err_details = str(traceback.format_exc()) + self.logger.error(f"{WORKFLOW_VDU_INSTANTIATE} failed with {err_details}") raise e diff --git a/osm_lcm/temporal/vim_workflows.py b/osm_lcm/temporal/vim_workflows.py index 33ab565..b549072 100644 --- a/osm_lcm/temporal/vim_workflows.py +++ b/osm_lcm/temporal/vim_workflows.py @@ -19,6 +19,7 @@ import logging from temporalio import workflow from temporalio.common import RetryPolicy from temporalio.exceptions import ActivityError +import traceback from osm_common.dataclasses.temporal_dataclasses import ( DeleteVimInput, @@ -44,13 +45,14 @@ _SANDBOXED = False retry_policy = RetryPolicy(maximum_attempts=3) default_schedule_to_close_timeout = timedelta(minutes=10) -workflow.logger = logging.getLogger("lcm.temporal.vim_workflows") - @workflow.defn(name=WORKFLOW_VIM_CREATE, sandboxed=_SANDBOXED) class VimCreateWorkflow: """Updates VIM account state by validating the VIM connectivity.""" + def __init__(self): + self.logger = logging.getLogger(f"lcm.wfl.{self.__class__.__name__}") + @workflow.run async def run(self, input: VimOperationInput) -> None: vim_state = UpdateVimStateInput(input.vim_uuid, VimState.ENABLED, "Done") @@ -68,45 +70,55 @@ class VimCreateWorkflow: ) except ActivityError as e: + error_details = str(e.cause.with_traceback(e.__traceback__)) vim_state = UpdateVimStateInput( - input.vim_uuid, VimState.ERROR, e.cause.message + input.vim_uuid, VimState.ERROR, str(e.cause.message) ) op_state = UpdateVimOperationStateInput( - input.vim_uuid, input.op_id, VimOperationState.FAILED, e.cause.message - ) - - workflow.logger.error( - f"{WORKFLOW_VIM_CREATE} failed with {str(e.cause.message)}" + input.vim_uuid, + input.op_id, + VimOperationState.FAILED, + error_details, ) + await self.update_states(op_state, vim_state) + self.logger.error(f"{WORKFLOW_VIM_CREATE} failed with {error_details}") raise e except Exception as e: + error_details = str(traceback.format_exc()) vim_state = UpdateVimStateInput(input.vim_uuid, VimState.ERROR, str(e)) op_state = UpdateVimOperationStateInput( - input.vim_uuid, input.op_id, VimOperationState.FAILED, str(e) + input.vim_uuid, + input.op_id, + VimOperationState.FAILED, + error_details, ) - - workflow.logger.error(f"{WORKFLOW_VIM_CREATE} failed with {str(e)}") + await self.update_states(op_state, vim_state) + self.logger.error(f"{WORKFLOW_VIM_CREATE} failed with {error_details}") raise e - finally: - await workflow.execute_activity( - activity=ACTIVITY_UPDATE_VIM_STATE, - arg=vim_state, - activity_id=f"{ACTIVITY_UPDATE_VIM_STATE}-{input.vim_uuid}", - task_queue=LCM_TASK_QUEUE, - schedule_to_close_timeout=default_schedule_to_close_timeout, - retry_policy=retry_policy, - ) + async def update_states( + self, + op_state: UpdateVimOperationStateInput, + vim_state: UpdateVimStateInput, + ): + await workflow.execute_activity( + activity=ACTIVITY_UPDATE_VIM_STATE, + arg=vim_state, + activity_id=f"{ACTIVITY_UPDATE_VIM_STATE}-{vim_state.vim_uuid}", + task_queue=LCM_TASK_QUEUE, + schedule_to_close_timeout=default_schedule_to_close_timeout, + retry_policy=retry_policy, + ) - await workflow.execute_activity( - activity=ACTIVITY_UPDATE_VIM_OPERATION_STATE, - arg=op_state, - activity_id=f"{ACTIVITY_UPDATE_VIM_OPERATION_STATE}-{input.vim_uuid}", - task_queue=LCM_TASK_QUEUE, - schedule_to_close_timeout=default_schedule_to_close_timeout, - retry_policy=retry_policy, - ) + await workflow.execute_activity( + activity=ACTIVITY_UPDATE_VIM_OPERATION_STATE, + arg=op_state, + activity_id=f"{ACTIVITY_UPDATE_VIM_OPERATION_STATE}-{op_state.vim_uuid}", + task_queue=LCM_TASK_QUEUE, + schedule_to_close_timeout=default_schedule_to_close_timeout, + retry_policy=retry_policy, + ) @workflow.defn(name=WORKFLOW_VIM_UPDATE, sandboxed=_SANDBOXED) diff --git a/osm_lcm/temporal/vnf_activities.py b/osm_lcm/temporal/vnf_activities.py index 98fc86c..85de719 100644 --- a/osm_lcm/temporal/vnf_activities.py +++ b/osm_lcm/temporal/vnf_activities.py @@ -134,10 +134,10 @@ class VnfDbActivity: activity, the operation is idempotent. """ - update_vnf_state = {"vnfState": vnf_state_input.state} + update_vnf_state = {"vnfState": vnf_state_input.state.name} self.db.set_one("vnfrs", {"_id": vnf_state_input.vnfr_uuid}, update_vnf_state) self.logger.debug( - f"VNF {vnf_state_input.vnfr_uuid} state is updated to {vnf_state_input.state}." + f"VNF {vnf_state_input.vnfr_uuid} state is updated to {vnf_state_input.state.name}." ) @activity.defn(name=ACTIVITY_CHANGE_VNF_INSTANTIATION_STATE) @@ -165,7 +165,7 @@ class VnfDbActivity: """ update_vnf_instantiation_state = { - "instantiationState": vnf_instantiation_state_input.state + "instantiationState": vnf_instantiation_state_input.state.name } self.db.set_one( "vnfrs", @@ -173,7 +173,7 @@ class VnfDbActivity: update_vnf_instantiation_state, ) self.logger.debug( - f"VNF {vnf_instantiation_state_input.vnfr_uuid} state is updated to {vnf_instantiation_state_input.state}." + f"VNF {vnf_instantiation_state_input.vnfr_uuid} state is updated to {vnf_instantiation_state_input.state.name}." ) @activity.defn(name=ACTIVITY_SET_VNF_MODEL) diff --git a/osm_lcm/temporal/vnf_workflows.py b/osm_lcm/temporal/vnf_workflows.py index d2d6d71..ffdd403 100644 --- a/osm_lcm/temporal/vnf_workflows.py +++ b/osm_lcm/temporal/vnf_workflows.py @@ -19,18 +19,21 @@ import logging from temporalio import workflow from temporalio.converter import value_to_type from temporalio.common import RetryPolicy +from temporalio.exceptions import ActivityError, ChildWorkflowError +import traceback from osm_common.dataclasses.temporal_dataclasses import ( - VnfInstantiationState, - VnfState, - VnfInstantiateInput, - VduInstantiateInput, ChangeVnfInstantiationStateInput, ChangeVnfStateInput, GetTaskQueueInput, GetTaskQueueOutput, GetVnfDetailsInput, GetVnfDetailsOutput, + VduComputeConstraints, + VduInstantiateInput, + VnfInstantiateInput, + VnfInstantiationState, + VnfState, ) from osm_common.temporal_constants import ( @@ -123,12 +126,31 @@ class VnfInstantiateWorkflow: ), ) + except ActivityError as e: + err_details = str(e.cause.with_traceback(e.__traceback__)) + await self.update_states( + vnf_instantiation_state=vnf_instantiation_state, + vnf_state=vnf_state, + ) + self.logger.error(f"{WORKFLOW_VNF_INSTANTIATE} failed with {err_details}") + raise e + + except ChildWorkflowError as e: + err_details = str(e.cause.cause.with_traceback(e.cause.__traceback__)) + await self.update_states( + vnf_instantiation_state=vnf_instantiation_state, + vnf_state=vnf_state, + ) + self.logger.error(f"{WORKFLOW_VNF_INSTANTIATE} failed with {err_details}") + raise e + except Exception as e: - workflow.logger.error(f"{WORKFLOW_VNF_INSTANTIATE} failed with {str(e)}") + err_details = str(traceback.format_exc()) await self.update_states( vnf_instantiation_state=vnf_instantiation_state, vnf_state=vnf_state, ) + self.logger.error(f"{WORKFLOW_VNF_INSTANTIATE} failed with {err_details}") raise e @staticmethod @@ -186,7 +208,10 @@ class VnfInstantiateWorkflow: vim_id = vnfr.get("vim-account-id") sw_image_descs = vnfd.get("sw-image-desc") vdu_info = CharmInfoUtils.get_charm_info(vdu, sw_image_descs) - vdu_instantiate_input = VduInstantiateInput(vim_id, model_name, vdu_info, None) + compute_constraints = VduComputeConstraints(cores=0, mem=0) + vdu_instantiate_input = VduInstantiateInput( + vim_id, model_name, vdu_info, compute_constraints, "cloud" + ) vdu_instantiate_workflow_id = ( vdu_instantiate_input.model_name + "-" @@ -227,6 +252,12 @@ class VnfPrepareWorkflow: schedule_to_close_timeout=default_schedule_to_close_timeout, retry_policy=retry_policy, ) + except ActivityError as e: + err_details = str(e.cause.with_traceback(e.__traceback__)) + self.logger.error(f"{WORKFLOW_VNF_PREPARE} failed with {err_details}") + raise e + except Exception as e: - self.logger.error(f"{WORKFLOW_VNF_PREPARE} failed with {str(e)}") + err_details = str(traceback.format_exc()) + self.logger.error(f"{WORKFLOW_VNF_PREPARE} failed with {err_details}") raise e diff --git a/osm_lcm/tests/test_juju_paas_activities.py b/osm_lcm/tests/test_juju_paas_activities.py index 1aee12b..d104d07 100644 --- a/osm_lcm/tests/test_juju_paas_activities.py +++ b/osm_lcm/tests/test_juju_paas_activities.py @@ -257,9 +257,9 @@ class TestDeployCharm(TestJujuPaasActivitiesBase): channel = "latest" entity_url = "ch:my-charm" charm_info = CharmInfo(app_name, channel, entity_url) - constraints = VduComputeConstraints(1, 2, "") + constraints = VduComputeConstraints(1, 2) vdu_instantiate_input = VduInstantiateInput( - vim_content["_id"], namespace, charm_info, constraints + vim_content["_id"], namespace, charm_info, constraints, cloud="" ) async def test_deploy_charm_nominal_case(self): diff --git a/osm_lcm/tests/test_vdu_workflow.py b/osm_lcm/tests/test_vdu_workflow.py index c5b2adc..15b30f6 100644 --- a/osm_lcm/tests/test_vdu_workflow.py +++ b/osm_lcm/tests/test_vdu_workflow.py @@ -63,10 +63,10 @@ class TestVduWorkflows(asynctest.TestCase): channel = "latest" entity_url = "ch:my-charm" cloud = "microk8s" - constraints = VduComputeConstraints(mem=1, cores=1, cloud=cloud) + constraints = VduComputeConstraints(mem=1, cores=1) charm_info = CharmInfo(app_name, channel, entity_url) vdu_instantiate_input = VduInstantiateInput( - vim_id, namespace, charm_info, constraints + vim_id, namespace, charm_info, constraints, cloud ) worflow_id = namespace + "-" + app_name diff --git a/osm_lcm/tests/test_vnf_workflows.py b/osm_lcm/tests/test_vnf_workflows.py index 912f5d0..6fd97d8 100644 --- a/osm_lcm/tests/test_vnf_workflows.py +++ b/osm_lcm/tests/test_vnf_workflows.py @@ -483,7 +483,8 @@ class TestVnfInstantiateWorkflow(asynctest.TestCase): charm_info=CharmInfo( app_name="my-app", channel="latest", entity_url="my-url" ), - constraints=VduComputeConstraints(cores=1, mem=1, cloud=cloud), + constraints=VduComputeConstraints(cores=1, mem=1), + cloud=cloud, ), "vdu_instantiate_workflow_id", ) diff --git a/tox.ini b/tox.ini index 1cb2253..0b5b8f7 100644 --- a/tox.ini +++ b/tox.ini @@ -67,7 +67,7 @@ deps = {[testenv]deps} -r{toxinidir}/requirements-test.txt pylint commands = - pylint -E osm_lcm --extension-pkg-whitelist=pydantic # issue with pydantic (https://github.com/pydantic/pydantic/issues/1961) + pylint -E osm_lcm --extension-pkg-whitelist=pydantic --disable=E1101 # issue with pydantic (https://github.com/pydantic/pydantic/issues/1961) #######################################################################################