in src/extensions/update_manifest_handlers/steps_handler/src/steps_handler.cpp [80:273]
ADUC_Result PrepareStepsWorkflowDataObject(ADUC_WorkflowHandle handle)
{
ADUC_Result result;
result.ResultCode = ADUC_Result_Failure;
result.ExtendedResultCode = 0;
ADUC_WorkflowHandle childHandle = nullptr;
auto stepCount = static_cast<size_t>(workflow_get_instructions_steps_count(handle));
char* workFolder = workflow_get_workfolder(handle);
size_t childWorkflowCount = workflow_get_children_count(handle);
int workflowLevel = workflow_get_level(handle);
// Child workflow should be either 0 (resuming install phase after agent restarted),
// or equal to fileCount (already created children during download phase)
if (childWorkflowCount != stepCount)
{
// Remove existing child workflow handle(s)
while (workflow_get_children_count(handle) > 0)
{
ADUC_WorkflowHandle child = workflow_remove_child(handle, 0);
workflow_free(child);
}
Log_Debug("Creating workflow for %lu step(s). Parent's level: %d", stepCount, workflowLevel);
for (size_t i = 0; i < stepCount; i++)
{
STRING_HANDLE childId = nullptr;
childHandle = nullptr;
ADUC_FileEntity entity;
memset(&entity, 0, sizeof(entity));
if (workflow_is_inline_step(handle, i))
{
const char* selectedComponents = workflow_peek_selected_components(handle);
Log_Debug(
"Creating workflow for level#%d step#%d.\nSelected components:\n=====\n%s\n=====\n",
workflowLevel,
i,
selectedComponents);
// Create child workflow using inline step data.
result = workflow_create_from_inline_step(handle, i, &childHandle);
if (IsAducResultCodeSuccess(result.ResultCode))
{
workflow_set_step_index(childHandle, i);
// Inherit parent's selected components.
workflow_set_selected_components(childHandle, workflow_peek_selected_components(handle));
}
}
else
{
// Download detached update manifest file.
if (!workflow_get_step_detached_manifest_file(handle, i, &entity))
{
result.ResultCode = ADUC_Result_Failure;
result.ExtendedResultCode = ADUC_ERC_STEPS_HANDLER_GET_FILE_ENTITY_FAILURE;
Log_Error(
"Cannot get a detached Update manifest file entity for level#%d step#%d", workflowLevel, i);
goto done;
}
Log_Info(
"Downloading a detached Update manifest file for level#%d step#%d (file id:%s).",
workflowLevel,
i,
entity.FileId);
try
{
result = ExtensionManager::Download(
&entity, handle, &Default_ExtensionManager_Download_Options, nullptr);
}
catch (...)
{
Log_Error(
"Exception occurred while downloading a detached Update Manifest file for level#%d step#%lu (file id:%s).",
workflowLevel,
i,
entity.FileId);
result.ResultCode = ADUC_Result_Failure;
result.ExtendedResultCode = ADUC_ERC_STEPS_HANDLER_DOWNLOAD_FAILURE_UNKNOWNEXCEPTION;
}
std::stringstream childManifestFile;
childManifestFile << workFolder << "/" << entity.TargetFilename;
ADUC_FileEntity_Uninit(&entity);
// For 'microsoft/steps:1' implementation, abort download task as soon as an error occurs.
if (IsAducResultCodeFailure(result.ResultCode))
{
Log_Error(
"An error occurred while downloading manifest file for step#%lu (erc:%d)",
i,
result.ExtendedResultCode);
goto done;
}
// Create child workflow from file.
result = workflow_init_from_file(childManifestFile.str().c_str(), false, &childHandle);
if (IsAducResultCodeSuccess(result.ResultCode))
{
workflow_set_step_index(childHandle, i);
// If no component enumerator is registered, assume that this reference update is for the host device.
// Don't set selected components in the workflow data.
if (ExtensionManager::IsComponentsEnumeratorRegistered())
{
// Select components based on the first pair of compatibility properties.
ADUC::StringUtils::cstr_wrapper compatibilityString{
workflow_get_update_manifest_compatibility(childHandle, 0)
};
JSON_Value* compsValue = nullptr;
if (compatibilityString.get() == nullptr)
{
Log_Error("Cannot get compatibility info for components-update #%lu", i);
result.ResultCode = ADUC_Result_Failure;
result.ExtendedResultCode = ADUC_ERC_STEPS_HANDLER_GET_REF_STEP_COMPATIBILITY_FAILED;
goto done;
}
std::string output;
result = ExtensionManager::SelectComponents(compatibilityString.get(), output);
if (IsAducResultCodeFailure(result.ResultCode))
{
Log_Error("Cannot select components for components-update #%lu", i);
goto done;
}
compsValue = json_parse_string(output.c_str());
json_value_free(compsValue);
if (!workflow_set_selected_components(childHandle, output.c_str()))
{
result.ResultCode = ADUC_Result_Failure;
result.ExtendedResultCode = ADUC_ERC_STEPS_HANDLER_SET_SELECTED_COMPONENTS_FAILURE;
}
Log_Debug(
"Set child handle's selected components: %s",
workflow_peek_selected_components(childHandle));
}
}
}
if (IsAducResultCodeFailure(result.ResultCode))
{
Log_Error("ERROR: failed to create workflow for level:%d step#%d.", workflowLevel, i);
goto done;
}
else
{
childId = STRING_construct_sprintf("%lu", i);
workflow_set_id(childHandle, STRING_c_str(childId));
STRING_delete(childId);
childId = nullptr;
#if _ADU_DEBUG
char* childManifest = workflow_get_serialized_update_manifest(childHandle, true);
Log_Debug(
"##########\n# Successfully created workflow object for child#%s\n# Handle:0x%x\n# Manifest:\n%s\n",
workflow_peek_id(childHandle),
childHandle,
childManifest);
workflow_free_string(childManifest);
#endif
}
if (!workflow_insert_child(handle, -1, childHandle))
{
result.ResultCode = ADUC_Result_Failure;
result.ExtendedResultCode = ADUC_ERC_STEPS_HANDLER_CHILD_WORKFLOW_INSERT_FAILED;
goto done;
}
}
}
result = { ADUC_Result_Success };
done:
workflow_free_string(workFolder);
if (IsAducResultCodeFailure(result.ResultCode))
{
workflow_free(childHandle);
}
return result;
}