aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleg Mitsura <oleg.mitsura@amdocs.com>2020-07-13 13:38:10 -0400
committerOleg Mitsura <oleg.mitsura@amdocs.com>2020-07-14 15:53:34 -0400
commitb7b1d5264cd4c9e8b4ff94dbab1392b47bf8ebeb (patch)
treef0b4f7826f34e5cbfd93d72af981b6d8d685bde6
parenteab2ad65a153a22ebc48ecc1d1a6a4db3ef367f5 (diff)
cmd-exec payload should be payload, not err msg.
Issue-ID: CCSDK-2549 fixes: 1. CMD-exec returns payload as JSON object. There was some regression where we overwrite returned JSON with errMsg. 2. adds 100ms delta to executionTimeout, as was in our downstream version (want to guarantee that we get grpc timeout exception on BP side rather than coroutine w/o waiting extra) 3. setNodeOutputErrors should not have ability to set execution status to success. rev1. initial import rev2. reworked the calls to setNodeOutputErrors: addError was brought out of it as we can set the node execution error based on prepare.env or execution. rev3. did not mean to add BlueprintRuntimeService change Signed-off-by: Oleg Mitsura <oleg.mitsura@amdocs.com> Change-Id: I6d509df5ae51598f33ab9f0ea53806d653cf79c0 (cherry picked from commit c48e0797fd577ec10b7c8978c19b02f6a84a3950)
-rw-r--r--ms/blueprintsprocessor/functions/python-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/python/executor/ComponentRemotePythonExecutor.kt114
1 files changed, 78 insertions, 36 deletions
diff --git a/ms/blueprintsprocessor/functions/python-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/python/executor/ComponentRemotePythonExecutor.kt b/ms/blueprintsprocessor/functions/python-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/python/executor/ComponentRemotePythonExecutor.kt
index d66e8b374..e707e5315 100644
--- a/ms/blueprintsprocessor/functions/python-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/python/executor/ComponentRemotePythonExecutor.kt
+++ b/ms/blueprintsprocessor/functions/python-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/python/executor/ComponentRemotePythonExecutor.kt
@@ -62,18 +62,23 @@ open class ComponentRemotePythonExecutor(private val remoteScriptExecutionServic
const val INPUT_ENV_PREPARE_TIMEOUT = "env-prepare-timeout"
const val INPUT_EXECUTE_TIMEOUT = "execution-timeout"
+ const val STEP_PREPARE_ENV = "prepare-env"
+ const val STEP_EXEC_CMD = "execute-command"
const val ATTRIBUTE_EXEC_CMD_STATUS = "status"
const val ATTRIBUTE_PREPARE_ENV_LOG = "prepare-environment-logs"
const val ATTRIBUTE_EXEC_CMD_LOG = "execute-command-logs"
const val ATTRIBUTE_RESPONSE_DATA = "response-data"
const val DEFAULT_ENV_PREPARE_TIMEOUT_IN_SEC = 120
const val DEFAULT_EXECUTE_TIMEOUT_IN_SEC = 180
+ const val TIMEOUT_DELTA = 100L
}
override suspend fun processNB(executionRequest: ExecutionServiceInput) {
log.debug("Processing : $operationInputs")
+ val isLogResponseEnabled = false
+
val bluePrintContext = bluePrintRuntimeService.bluePrintContext()
val blueprintName = bluePrintContext.name()
val blueprintVersion = bluePrintContext.version()
@@ -114,6 +119,9 @@ open class ComponentRemotePythonExecutor(private val remoteScriptExecutionServic
val executionTimeout = getOptionalOperationInput(INPUT_EXECUTE_TIMEOUT)?.asInt()
?: DEFAULT_EXECUTE_TIMEOUT_IN_SEC
+ // component level timeout should be => env_prep_timeout + execution_timeout
+ val timeout = implementation.timeout
+
var scriptCommand = command.replace(pythonScript.name, pythonScript.absolutePath)
if (args != null && args.isNotEmpty()) {
scriptCommand = scriptCommand.plus(" ").plus(args)
@@ -142,32 +150,39 @@ open class ComponentRemotePythonExecutor(private val remoteScriptExecutionServic
)
val prepareEnvOutput = remoteScriptExecutionService.prepareEnv(prepareEnvInput)
log.info("$ATTRIBUTE_PREPARE_ENV_LOG - ${prepareEnvOutput.response}")
- val logs = prepareEnvOutput.response
- val logsEnv = logs.toString().asJsonPrimitive()
- setAttribute(ATTRIBUTE_PREPARE_ENV_LOG, logsEnv)
+ val logs = JacksonUtils.jsonNodeFromObject(prepareEnvOutput.response)
+ setAttribute(ATTRIBUTE_PREPARE_ENV_LOG, logs)
+ // there are no artifacts for env. prepare, but we reuse it for err_log...
if (prepareEnvOutput.status != StatusType.SUCCESS) {
- setAttribute(ATTRIBUTE_EXEC_CMD_LOG, "N/A".asJsonPrimitive())
- setNodeOutputErrors(prepareEnvOutput.status.name, logsEnv)
+ setNodeOutputErrors(STEP_PREPARE_ENV, "".asJsonPrimitive(), prepareEnvOutput.payload, isLogResponseEnabled)
+ addError(StatusType.FAILURE.name, STEP_PREPARE_ENV, logs.toString())
} else {
- setNodeOutputProperties(prepareEnvOutput.status.name.asJsonPrimitive(), logsEnv, "".asJsonPrimitive())
+ setNodeOutputProperties(prepareEnvOutput.status, STEP_PREPARE_ENV, logs, prepareEnvOutput.payload, isLogResponseEnabled)
}
} else {
// set env preparation log to empty...
setAttribute(ATTRIBUTE_PREPARE_ENV_LOG, "".asJsonPrimitive())
}
+ // in cases where the exception is caught in BP side due to timeout, we do not have `err_msg` returned by cmd-exec (inside `payload`),
+ // hence `artifact` field will be empty
} catch (grpcEx: io.grpc.StatusRuntimeException) {
- val grpcErrMsg = "Command failed during env. preparation... timeout($envPrepTimeout) requestId ($processId)."
+ val componentLevelWarningMsg = if (timeout < envPrepTimeout) "Note: component-level timeout ($timeout) is shorter than env-prepare timeout ($envPrepTimeout). " else ""
+ val grpcErrMsg = "Command failed during env. preparation... timeout($envPrepTimeout) requestId ($processId).$componentLevelWarningMsg grpcError: (${grpcEx.cause?.message})"
+ // no execution log in case of timeout (as cmd-exec side hasn't finished to transfer output)
+ // set prepare-env-log to the error msg, and cmd-exec-log to empty
setAttribute(ATTRIBUTE_PREPARE_ENV_LOG, grpcErrMsg.asJsonPrimitive())
- setNodeOutputErrors(status = grpcErrMsg, message = "${grpcEx.status}".asJsonPrimitive())
+ setNodeOutputErrors(STEP_PREPARE_ENV, "".asJsonPrimitive(), "".asJsonPrimitive(), isLogResponseEnabled)
+ addError(StatusType.FAILURE.name, STEP_PREPARE_ENV, grpcErrMsg)
log.error(grpcErrMsg, grpcEx)
addError(grpcErrMsg)
} catch (e: Exception) {
- val timeoutErrMsg = "Command executor failed during env. preparation.. timeout($envPrepTimeout) requestId ($processId)."
- setAttribute(ATTRIBUTE_PREPARE_ENV_LOG, e.message.asJsonPrimitive())
- setNodeOutputErrors(status = timeoutErrMsg, message = "${e.message}".asJsonPrimitive())
- log.error("Failed to process on remote executor requestId ($processId)", e)
- addError(timeoutErrMsg)
+ val catchallErrMsg = "Command executor failed during env. preparation.. catch-all case. timeout($envPrepTimeout) requestId ($processId). exception msg: ${e.message}"
+ // no environment prepare log from executor in case of timeout (as cmd-exec side hasn't finished to transfer output), set it to error msg. Execution logs is empty.
+ setAttribute(ATTRIBUTE_PREPARE_ENV_LOG, catchallErrMsg.asJsonPrimitive())
+ setNodeOutputErrors(STEP_PREPARE_ENV, "".asJsonPrimitive(), "".asJsonPrimitive(), isLogResponseEnabled)
+ addError(StatusType.FAILURE.name, STEP_PREPARE_ENV, catchallErrMsg)
+ log.error(catchallErrMsg, e)
}
// if Env preparation was successful, then proceed with command execution in this Env
if (bluePrintRuntimeService.getBluePrintError().errors.isEmpty()) {
@@ -186,7 +201,7 @@ open class ComponentRemotePythonExecutor(private val remoteScriptExecutionServic
remoteScriptExecutionService.executeCommand(remoteExecutionInput)
}
- val remoteExecutionOutput = withTimeout(implementation.timeout * 1000L) {
+ val remoteExecutionOutput = withTimeout(executionTimeout * 1000L + TIMEOUT_DELTA) {
remoteExecutionOutputDeferred.await()
}
@@ -194,22 +209,31 @@ open class ComponentRemotePythonExecutor(private val remoteScriptExecutionServic
"Error: Request-id $processId did not return a restul from remote command execution."
}
val logs = JacksonUtils.jsonNodeFromObject(remoteExecutionOutput.response)
+ val returnedPayload = remoteExecutionOutput.payload
+ // In case of execution, `payload` (dictionary from Python execution) is preserved in `remoteExecutionOutput.payload`;
+ // It would contain `err_msg` key. It is valid to return it.
if (remoteExecutionOutput.status != StatusType.SUCCESS) {
- setNodeOutputErrors(remoteExecutionOutput.status.name, logs, remoteExecutionOutput.payload)
+ setNodeOutputErrors(STEP_EXEC_CMD, logs, returnedPayload, isLogResponseEnabled)
+ addError(StatusType.FAILURE.name, STEP_EXEC_CMD, logs.toString())
} else {
- setNodeOutputProperties(remoteExecutionOutput.status.name.asJsonPrimitive(), logs,
- remoteExecutionOutput.payload)
- }
+ setNodeOutputProperties(remoteExecutionOutput.status, STEP_EXEC_CMD, logs, returnedPayload, isLogResponseEnabled)
+ } // In timeout exception cases, we don't have payload, hence `payload` is empty value.
} catch (timeoutEx: TimeoutCancellationException) {
- val timeoutErrMsg = "Command executor timed out executing after $executionTimeout seconds requestId ($processId)"
- setNodeOutputErrors(status = timeoutErrMsg, message = "".asJsonPrimitive())
+ val componentLevelWarningMsg = if (timeout < executionTimeout) "Note: component-level timeout ($timeout) is shorter than execution timeout ($executionTimeout). " else ""
+ val timeoutErrMsg = "Command executor execution timeout. DetailedMessage: (${timeoutEx.message}) requestId ($processId). $componentLevelWarningMsg"
+ setNodeOutputErrors(STEP_EXEC_CMD, timeoutErrMsg.asJsonPrimitive(), logging = isLogResponseEnabled)
+ addError(StatusType.FAILURE.name, STEP_EXEC_CMD, timeoutErrMsg)
log.error(timeoutErrMsg, timeoutEx)
} catch (grpcEx: io.grpc.StatusRuntimeException) {
- val timeoutErrMsg = "Command executor timed out executing after $executionTimeout seconds requestId ($processId)"
- setNodeOutputErrors(status = timeoutErrMsg, message = "".asJsonPrimitive())
- log.error("Command executor time out during GRPC call", grpcEx)
+ val timeoutErrMsg = "Command executor timed out executing after $executionTimeout seconds requestId ($processId) grpcErr: ${grpcEx.status}"
+ setNodeOutputErrors(STEP_EXEC_CMD, timeoutErrMsg.asJsonPrimitive(), logging = isLogResponseEnabled)
+ addError(StatusType.FAILURE.name, STEP_EXEC_CMD, timeoutErrMsg)
+ log.error(timeoutErrMsg, grpcEx)
} catch (e: Exception) {
- log.error("Failed to process on remote executor requestId ($processId)", e)
+ val catchAllErrMsg = "Command executor failed during process catch-all case requestId ($processId) timeout($envPrepTimeout) exception msg: ${e.message}"
+ setNodeOutputErrors(STEP_PREPARE_ENV, catchAllErrMsg.asJsonPrimitive(), logging = isLogResponseEnabled)
+ addError(StatusType.FAILURE.name, STEP_EXEC_CMD, catchAllErrMsg)
+ log.error(catchAllErrMsg, e)
}
}
log.debug("Trying to close GRPC channel. request ($processId)")
@@ -234,25 +258,43 @@ open class ComponentRemotePythonExecutor(private val remoteScriptExecutionServic
/**
* Utility function to set the output properties of the executor node
*/
- private fun setNodeOutputProperties(status: JsonNode, message: JsonNode, artifacts: JsonNode) {
- setAttribute(ATTRIBUTE_EXEC_CMD_STATUS, status)
- log.info("Executor status : $status")
+ private fun setNodeOutputProperties(
+ status: StatusType,
+ step: String,
+ executionLogs: JsonNode,
+ artifacts: JsonNode,
+ logging: Boolean = true
+ ) {
+
+ setAttribute(ATTRIBUTE_EXEC_CMD_STATUS, status.name.asJsonPrimitive())
+ setAttribute(ATTRIBUTE_EXEC_CMD_LOG, executionLogs)
setAttribute(ATTRIBUTE_RESPONSE_DATA, artifacts)
- log.info("Executor artifacts: $artifacts")
- setAttribute(ATTRIBUTE_EXEC_CMD_LOG, message)
- log.info("Executor message : $message")
+
+ if (logging) {
+ log.info("Executor status : $step : $status")
+ log.info("Executor logs : $step : $executionLogs")
+ log.info("Executor artifacts: $step : $artifacts")
+ }
}
/**
* Utility function to set the output properties and errors of the executor node, in cas of errors
*/
- private fun setNodeOutputErrors(status: String, message: JsonNode, artifacts: JsonNode = "".asJsonPrimitive()) {
+ private fun setNodeOutputErrors(
+ step: String,
+ executionLogs: JsonNode = "N/A".asJsonPrimitive(),
+ artifacts: JsonNode = "N/A".asJsonPrimitive(),
+ logging: Boolean = true
+ ) {
+ val status = StatusType.FAILURE.name
setAttribute(ATTRIBUTE_EXEC_CMD_STATUS, status.asJsonPrimitive())
- log.info("Executor status : $status")
- setAttribute(ATTRIBUTE_EXEC_CMD_LOG, message)
- log.info("Executor message : $message")
+ setAttribute(ATTRIBUTE_EXEC_CMD_LOG, executionLogs)
setAttribute(ATTRIBUTE_RESPONSE_DATA, artifacts)
- log.info("Executor artifacts: $artifacts")
- addError(status, ATTRIBUTE_EXEC_CMD_LOG, message.toString())
+
+ if (logging) {
+ log.info("Executor status : $step : $status")
+ log.info("Executor logs : $step : $executionLogs")
+ log.info("Executor artifacts: $step : $artifacts")
+ }
}
}