void OrchestratorUpdateCallback()

in src/agent/adu_core_interface/src/adu_core_interface.c [329:460]


void OrchestratorUpdateCallback(
    ADUC_ClientHandle clientHandle,
    JSON_Value* propertyValue,
    int propertyVersion,
    ADUC_PnPComponentClient_PropertyUpdate_Context* sourceContext,
    void* context)
{
    UNREFERENCED_PARAMETER(clientHandle);

    ADUC_Result tmpResult = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 };
    ADUC_WorkflowData* workflowData = (ADUC_WorkflowData*)context;

    STRING_HANDLE jsonToSend = NULL;
    char* ackString = NULL;
    JSON_Object* signatureObj = NULL;

    ADUCITF_UpdateAction updateAction = ADUCITF_UpdateAction_Undefined;
    char* workflowId = NULL;
    char* rootKeyPkgUrl = NULL;
    STRING_HANDLE rootKeyPackageFilePath = NULL;
    char* workFolder = NULL;

    // Reads out the json string so we can Log Out what we've got.
    // The value will be parsed and handled in ADUC_Workflow_HandlePropertyUpdate.
    char* jsonString = json_serialize_to_string(propertyValue);
    if (jsonString == NULL)
    {
        Log_Error(
            "OrchestratorUpdateCallback failed to convert property JSON value to string, property version (%d)",
            propertyVersion);
        goto done;
    }

    // To reduce TWIN size, remove UpdateManifestSignature and fileUrls before ACK.
    signatureObj = json_value_get_object(propertyValue);
    if (signatureObj != NULL)
    {
        json_object_set_null(signatureObj, "updateManifestSignature");
        json_object_set_null(signatureObj, "fileUrls");
        ackString = json_serialize_to_string(propertyValue);
    }

    Log_Debug("Update Action info string (%s), property version (%d)", ackString, propertyVersion);

    tmpResult = workflow_parse_peek_unprotected_workflow_properties(
        json_object(propertyValue), &updateAction, &rootKeyPkgUrl, &workflowId);
    if (IsAducResultCodeFailure(tmpResult.ResultCode))
    {
        Log_Error("Parse failed for unprotected properties, erc: 0x%08x", tmpResult.ExtendedResultCode);
        // Note, cannot report failure here since workflowId from unprotected properties is needed for that.
        goto done;
    }

    // If there is no deployment for the device group or the device connected
    // within an interval before the update was deployed, then a C2D message
    // with update action of cancel and an internal workflowId of
    // "nodeployment" will be sent.
    //
    // It is an indicator that no deployment exists for the device group or
    // that a new deployment has been deployed recently and should be flowing
    // down the pipe soon.
    //
    // Instead of processing a cancel, just ignore this and wait for normal
    // cancellation to occur once a "process deployment" action flows down.
    if (updateAction == ADUCITF_UpdateAction_Cancel && (0 == strcmp(workflowId, "nodeployment")))
    {
        Log_Info("Received deployment delay period NOOP cancel. Will wait for update deployment to be pushed...");
        goto done;
    }

    if (updateAction == ADUCITF_UpdateAction_ProcessDeployment && !IsNullOrEmpty(workflowId))
    {
        Log_Debug("Processing deployment %s ...", workflowId);

        // Ensure update to latest rootkey pkg, which is required for validating the update metadata.
        workFolder = workflow_get_root_sandbox_dir(workflowData->WorkflowHandle);
        if (workFolder == NULL)
        {
            Log_Error("workflow_get_root_sandbox_dir failed");
            goto done;
        }

        tmpResult = RootKeyWorkflow_UpdateRootKeys(workflowId, workFolder, rootKeyPkgUrl);
        if (IsAducResultCodeFailure(tmpResult.ResultCode))
        {
            Log_Error("Update Rootkey failed, 0x%08x. Deployment cannot proceed.", tmpResult.ExtendedResultCode);
            goto done;
        }
    }

    ADUC_Workflow_HandlePropertyUpdate(workflowData, (const unsigned char*)jsonString, sourceContext->forceUpdate);
    free(jsonString);
    jsonString = ackString;

    // ACK the request.
    jsonToSend = PnP_CreateReportedPropertyWithStatus(
        g_aduPnPComponentName,
        g_aduPnPComponentServicePropertyName,
        jsonString,
        PNP_STATUS_SUCCESS,
        "", // Description for this acknowledgement.
        propertyVersion);

    if (jsonToSend == NULL)
    {
        Log_Error("Unable to build reported property ACK response.");
        goto done;
    }

    if (!ADUC_D2C_Message_SendAsync(
            ADUC_D2C_Message_Type_Device_Update_ACK,
            &g_iotHubClientHandleForADUComponent,
            STRING_c_str(jsonToSend),
            NULL /* responseCallback */,
            OnUpdateResultD2CMessageCompleted,
            NULL /* statusChangedCallback */,
            NULL /* userData */))
    {
        Log_Error("Unable to send update result.");
        goto done;
    }

done:
    STRING_delete(rootKeyPackageFilePath);
    workflow_free_string(rootKeyPkgUrl);
    workflow_free_string(workflowId);
    workflow_free_string(workFolder);
    STRING_delete(jsonToSend);
    free(jsonString);

    Log_Info("OrchestratorPropertyUpdateCallback ended");
}