ADUC_Result SWUpdateHandler_PerformAction()

in src/extensions/step_handlers/swupdate_handler_v2/src/swupdate_handler_v2.cpp [137:306]


ADUC_Result SWUpdateHandler_PerformAction(
    const std::string& action,
    const tagADUC_WorkflowData* workflowData,
    bool prepareArgsOnly,
    std::string& scriptFilePath,
    std::vector<std::string>& args,
    std::vector<std::string>& commandLineArgs,
    std::string& scriptOutput)
{
    Log_Info("Action (%s) begin", action.c_str());
    ADUC_Result result = { ADUC_GeneralResult_Failure };
    const ADUC_ConfigInfo* config = nullptr;

    int exitCode = 0;
    commandLineArgs.clear();

    if (workflowData == nullptr || workflowData->WorkflowHandle == nullptr)
    {
        result.ExtendedResultCode = ADUC_ERC_SWUPDATE_HANDLER_INSTALL_ERROR_NULL_WORKFLOW;
        return result;
    }

    const char* apiVer = workflow_peek_update_manifest_handler_properties_string(
        workflowData->WorkflowHandle, HANDLER_PROPERTIES_API_VERSION);

    char* workFolder = ADUC_WorkflowData_GetWorkFolder(workflowData);
    std::string scriptWorkfolder = workFolder;
    std::string scriptResultFile = scriptWorkfolder + "/" + "aduc_result.json";
    JSON_Value* actionResultValue = nullptr;
    std::vector<std::string> aduShellArgs;

    config = ADUC_ConfigInfo_GetInstance();
    if (config == nullptr)
    {
        result.ExtendedResultCode = ADUC_ERC_SWUPDATE_HANDLER_PERFORM_ACTION_FAILED_TO_GET_CONFIG_INSTANCE;
        goto done;
    }

    aduShellArgs.emplace_back(adushconst::config_folder_opt);
    aduShellArgs.emplace_back(config->configFolder);
    aduShellArgs.emplace_back(adushconst::update_type_opt);
    aduShellArgs.emplace_back(adushconst::update_type_microsoft_script);
    aduShellArgs.emplace_back(adushconst::update_action_opt);
    aduShellArgs.emplace_back(adushconst::update_action_execute);

    result = SWUpdateHandlerImpl::PrepareCommandArguments(
        workflowData->WorkflowHandle, scriptResultFile, scriptWorkfolder, scriptFilePath, args);
    if (IsAducResultCodeFailure(result.ResultCode))
    {
        goto done;
    }

    // If any install-item reported that the update is already installed on the
    // selected component, we will skip the 'apply' phase, and then skip the
    // remaining install-item(s).
    // Also, don't continue if WorkflowHandle is NULL in the ADUInterface_Connected->HandleStartupWorkflowData flow.
    if (result.ResultCode == ADUC_Result_Install_Skipped_UpdateAlreadyInstalled
        || workflowData->WorkflowHandle == nullptr)
    {
        goto done;
    }

    aduShellArgs.emplace_back(adushconst::target_data_opt);
    aduShellArgs.emplace_back(scriptFilePath);
    commandLineArgs.emplace_back(scriptFilePath);

    // Prepare arguments based on specified api version.
    if (apiVer == nullptr || strcmp(apiVer, "1.0") == 0)
    {
        std::string backcompatAction = "--action-" + action;
        aduShellArgs.emplace_back(adushconst::target_options_opt);
        aduShellArgs.emplace_back(backcompatAction.c_str());
        commandLineArgs.emplace_back(backcompatAction.c_str());
    }
    else if (strcmp(apiVer, "1.1") == 0)
    {
        aduShellArgs.emplace_back(adushconst::target_options_opt);
        aduShellArgs.emplace_back(HANDLER_ARG_ACTION);
        commandLineArgs.emplace_back(HANDLER_ARG_ACTION);

        aduShellArgs.emplace_back(adushconst::target_options_opt);
        aduShellArgs.emplace_back(action.c_str());
        commandLineArgs.emplace_back(action.c_str());
    }

    for (const auto& a : args)
    {
        aduShellArgs.emplace_back(adushconst::target_options_opt);
        aduShellArgs.emplace_back(a);
        commandLineArgs.emplace_back(a);
    }

    if (prepareArgsOnly)
    {
        std::stringstream ss;

        for (const auto& a : aduShellArgs)
        {
            if (a[0] != '-')
            {
                ss << " \"" << a << "\"";
            }
            else
            {
                ss << " " << a;
            }
        }
        scriptOutput = ss.str();

        Log_Debug("Prepare Only! adu-shell Command:\n\n %s", scriptOutput.c_str());
        result.ResultCode = ADUC_Result_Success;
        result.ExtendedResultCode = 0;
        goto done;
    }

    exitCode = ADUC_LaunchChildProcess(config->aduShellFilePath, aduShellArgs, scriptOutput);
    if (exitCode != 0)
    {
        int extendedCode = ADUC_ERC_SWUPDATE_HANDLER_CHILD_FAILURE_PROCESS_EXITCODE(exitCode);
        Log_Error("Install failed, extendedResultCode:0x%X (exitCode:%d)", extendedCode, exitCode);
        result.ResultCode = ADUC_Result_Failure;
        result.ExtendedResultCode = extendedCode;
    }

    if (!scriptOutput.empty())
    {
        Log_Info("%s\n", scriptOutput.c_str());
    }

    // Parse result file.
    actionResultValue = json_parse_file(scriptResultFile.c_str());

    if (actionResultValue == nullptr)
    {
        result.ResultCode = ADUC_Result_Failure;
        result.ExtendedResultCode = ADUC_ERC_SWUPDATE_HANDLER_INSTALL_FAILURE_PARSE_RESULT_FILE;
        workflow_set_result_details(
            workflowData->WorkflowHandle,
            "The install script doesn't create a result file '%s'.",
            scriptResultFile.c_str());
        goto done;
    }
    else
    {
        JSON_Object* actionResultObject = json_object(actionResultValue);
        result.ResultCode = (ADUC_Result_t)json_object_get_number(actionResultObject, "resultCode");
        result.ExtendedResultCode = (ADUC_Result_t)json_object_get_number(actionResultObject, "extendedResultCode");
        const char* details = json_object_get_string(actionResultObject, "resultDetails");
        workflow_set_result_details(workflowData->WorkflowHandle, details);
    }

    Log_Info(
        "Action (%s) done - returning rc:%d, erc:0x%X, rd:%s",
        action.c_str(),
        result.ResultCode,
        result.ExtendedResultCode,
        workflow_peek_result_details(workflowData->WorkflowHandle));

done:
    ADUC_ConfigInfo_ReleaseInstance(config);
    if (IsAducResultCodeFailure(result.ResultCode))
    {
        workflow_set_result(workflowData->WorkflowHandle, result);
        workflow_set_state(workflowData->WorkflowHandle, ADUCITF_State_Failed);
    }

    json_value_free(actionResultValue);
    workflow_free_string(workFolder);
    return result;
}