ADUC_Result AptHandlerImpl::Download()

in src/extensions/step_handlers/apt_handler/src/apt_handler.cpp [139:295]


ADUC_Result AptHandlerImpl::Download(const ADUC_WorkflowData* workflowData)
{
    ADUC_Result result = { .ResultCode = ADUC_Result_Failure, .ExtendedResultCode = 0 };
    std::stringstream aptManifestFilename;
    std::unique_ptr<AptContent> aptContent{ nullptr };
    ADUC_WorkflowHandle handle = workflowData->WorkflowHandle;
    const ADUC_ConfigInfo* config = nullptr;
    size_t fileCount = 0;
    char* installedCriteria = nullptr;

    if (workflow_is_cancel_requested(handle))
    {
        return this->Cancel(workflowData);
    }

    // For 'microsoft/apt:1', we're expecting 1 payload file.
    fileCount = workflow_get_update_files_count(handle);
    if (fileCount != 1)
    {
        Log_Error("APT packages expecting one file. (%d)", fileCount);
        return ADUC_Result{ .ResultCode = ADUC_Result_Failure,
                            .ExtendedResultCode = ADUC_ERC_APT_HANDLER_PACKAGE_PREPARE_FAILURE_WRONG_FILECOUNT };
    }

    char* workFolder = workflow_get_workfolder(handle);

    ADUC_FileEntity fileEntity;
    memset(&fileEntity, 0, sizeof(fileEntity));

    if (!workflow_get_update_file(handle, 0, &fileEntity))
    {
        result = { .ResultCode = ADUC_Result_Failure,
                   .ExtendedResultCode = ADUC_ERC_APT_HANDLER_GET_FILEENTITY_FAILURE };
        goto done;
    }

    installedCriteria = workflow_get_installed_criteria(handle);
    if (IsNullOrEmpty(installedCriteria))
    {
        workflow_set_result_details(handle, "Property 'installedCriteria' in handlerProperties is missing or empty.");
        result = { .ResultCode = ADUC_Result_Failure,
                   .ExtendedResultCode = ADUC_ERC_APT_HANDLER_MISSING_INSTALLED_CRITERIA };
        goto done;
    }

    // Let's get the config instance before downloading the APT manifest file
    // because this is less expensive.
    config = ADUC_ConfigInfo_GetInstance();
    if (config == NULL)
    {
        Log_Error("Failed to get config instance.");
        result = { ADUC_Result_Failure, ADUC_ERC_APT_HANDLER_DOWNLOAD_FAILED_TO_GET_CONFIG_INSTANCE };
        goto done;
    }

    aptManifestFilename << workFolder << "/" << fileEntity.TargetFilename;

    // Download the APT manifest file.
    result = ExtensionManager::Download(
        &fileEntity, workflowData->WorkflowHandle, &Default_ExtensionManager_Download_Options, nullptr);

    if (IsAducResultCodeFailure(result.ResultCode))
    {
        goto done;
    }

    result = ParseContent(aptManifestFilename.str(), aptContent);
    if (IsAducResultCodeFailure(result.ResultCode))
    {
        goto done;
    }

    {
        std::string aptOutput;
        int aptExitCode = -1;

        // Perform apt-get update to fetch latest packages catalog.
        // We'll log warning if failed, but will try to download specified packages.
        try
        {
            // Perform apt-get update.
            const std::vector<std::string> args = {
                adushconst::config_folder_opt, config->configFolder,
                adushconst::update_type_opt,   adushconst::update_type_microsoft_apt,
                adushconst::update_action_opt, adushconst::update_action_initialize
            };

            aptExitCode = ADUC_LaunchChildProcess(config->aduShellFilePath, args, aptOutput);

            if (!aptOutput.empty())
            {
                Log_Info(aptOutput.c_str());
            }
        }
        catch (const std::exception& de)
        {
            Log_Error("Exception occurred while processing apt-get update.\n%s", de.what());
            aptExitCode = -1;
        }

        if (aptExitCode != 0)
        {
            Log_Error("APT update failed. (Exit code: %d)", aptExitCode);
        }

        // Download packages.
        result = { ADUC_Result_Download_Success };
        try
        {
            std::vector<std::string> args = { adushconst::config_folder_opt, config->configFolder,
                                              adushconst::update_type_opt,   adushconst::update_type_microsoft_apt,
                                              adushconst::update_action_opt, adushconst::update_action_download };

            // For microsoft/apt, target-data is a list of packages.
            std::stringstream data;
            data << "'";
            for (const std::string& package : aptContent->Packages)
            {
                data << package << " ";
            }
            data << "'";

            args.emplace_back(adushconst::target_data_opt);
            args.emplace_back(data.str());

            aptExitCode = ADUC_LaunchChildProcess(config->aduShellFilePath, args, aptOutput);

            if (!aptOutput.empty())
            {
                Log_Info("\n\nadu-shell logs\n================\n\n%s", aptOutput.c_str());
            }
        }
        catch (const std::exception& de)
        {
            Log_Error("Exception occurred during download. %s", de.what());
            aptExitCode = -1;
        }

        if (aptExitCode != 0)
        {
            result.ResultCode = ADUC_Result_Failure;
            result.ExtendedResultCode = ADUC_ERC_APT_HANDLER_PACKAGE_DOWNLOAD_FAILURE;
            Log_Error("APT packages download failed. (Exit code: %d)", aptExitCode);
            goto done;
        }
    }

    result = { .ResultCode = ADUC_Result_Download_Success, .ExtendedResultCode = 0 };

done:
    ADUC_ConfigInfo_ReleaseInstance(config);
    workflow_free_string(installedCriteria);
    workflow_free_string(workFolder);
    ADUC_FileEntity_Uninit(&fileEntity);

    return result;
}