MI_Result ProcessPartialConfigurations()

in LCM/dsc/engine/ConfigurationManager/LocalConfigManagerHelper.c [2352:2646]


MI_Result ProcessPartialConfigurations(
        _In_ LCMProviderContext *lcmContext,
        _In_ ModuleManager *moduleManager,
        _In_ MI_Uint32 flags,
        _Inout_ MI_Uint32 *resultStatus,
        _In_ MI_Result(*ConfigurationProcessor)
        (
        _In_ LCMProviderContext *lcmContext,
        _In_ ModuleManager *moduleManager,
        _In_ MI_Uint32 flags,
        _In_ MI_Instance * documentIns,
        _In_ MI_InstanceA *resourceInstances,
        _In_ MI_Instance *metaConfigInstance,
        _Inout_ MI_Uint32 *resultStatus,
        _Outptr_result_maybenull_ MI_Instance **cimErrorDetails
        ),
        _In_ MI_Instance *metaConfigInstance,
        _In_ MI_InstanceA* resourceInstances,
        _Outptr_result_maybenull_ MI_Instance **cimErrorDetails)
{
        MI_Result r = MI_RESULT_OK;
        MI_Uint32 result_Flags;
        MI_Boolean hashInited = MI_FALSE;
        int hashResult;
        const size_t NUM_LISTS = 32;
        HashMap partialConfigDocumentInMap;
        PartialConfigBucket *bucket = NULL;
        PartialConfigBucket searchBucket;
        MI_Instance **tempInstance = NULL;
        MI_Uint32 xCount = 0;
        MI_InstanceA partialConfigIns = { 0 };
        MI_InstanceA partialConfigDocumentIns = { 0 };
        ExecutionOrderContainer executionContainer = { 0 };
        MI_InstanceA partialConfigResourceInstances = { 0 };
        MSFT_PartialConfiguration *partialConfigIn = NULL;
        MI_Boolean flagAtleastOnePartialWasSet = MI_FALSE;
        MI_Boolean flagPartialConfigFailedToApply = MI_FALSE;
        MI_Char expandedPartialConfigName[MAX_PATH];
        size_t concatResult;
        MI_Value value;
        MI_Value valueId;

        hashResult = HashMap_Init(&partialConfigDocumentInMap, NUM_LISTS, PartialConfigHash, PartialConfigEqual, PartialConfigRelease);
        if (hashResult != 0)
        {
                EH_Fail();
        }
        hashInited = MI_TRUE;

        // build a list of resourceInstance and documentIns
        r = DSC_MI_Instance_GetElement(metaConfigInstance, MSFT_DSCMetaConfiguration_PartialConfigurations, &value, NULL, &result_Flags, NULL);
        if (r != MI_RESULT_OK || (result_Flags & MI_FLAG_NULL) != 0)
        {
                // todo: add proper error message
                EH_Fail_(GetCimMIError(r, cimErrorDetails, ID_MODMAN_VALIDATE_DOCINS));
        }

        tempInstance = (MI_Instance **) DSC_malloc(value.instancea.size * sizeof(MI_Instance*), NitsHere());
        if (tempInstance == NULL)
        {
                EH_Fail_(GetCimMIError(MI_RESULT_SERVER_LIMITS_EXCEEDED, cimErrorDetails, ID_LCMHELPER_MEMORY_ERROR));
        }

        for (xCount = 0; xCount < value.instancea.size; xCount++)
        {
                tempInstance[xCount] = value.instancea.data[xCount];
                bucket = (PartialConfigBucket*) DSC_malloc(sizeof(PartialConfigBucket), NitsHere());
                if (bucket == NULL)
                {
                        EH_Fail_(GetCimMIError(MI_RESULT_SERVER_LIMITS_EXCEEDED, cimErrorDetails, ID_LCMHELPER_MEMORY_ERROR));
                }

                r = DSC_MI_Instance_GetElement(tempInstance[xCount], MSFT_DSCMetaConfiguration_ResourceId, &valueId, NULL, &result_Flags, NULL);
                if (r != MI_RESULT_OK || (result_Flags & MI_FLAG_NULL) != 0)
                {
                        // todo: add proper error message
                        EH_Fail_(GetCimMIError(r, cimErrorDetails, ID_MODMAN_VALIDATE_DOCINS));
                }

                bucket->key = valueId.string;
                bucket->partialConfig = tempInstance[xCount];
                bucket->size = 0;
                bucket->count = 0;

                r = HashMap_Insert(&partialConfigDocumentInMap, (HashBucket*) bucket);
                EH_CheckResult(r);
        }

        partialConfigIns.data = tempInstance;
        partialConfigIns.size = value.instancea.size;

        r = ResolveDependency(&partialConfigIns, &executionContainer, cimErrorDetails);
        EH_CheckResult(r);

        r = GetArrayInstancesFromSingleMof(moduleManager, 0, GetPartialConfigBaseDocumentInstanceFileName(), &partialConfigDocumentIns, cimErrorDetails, MI_TRUE);
        EH_CheckResult(r);

        //insert partialConfiguration document into the hashmap 
        for (xCount = 0; xCount < partialConfigDocumentIns.size; xCount++)
        {
                r = DSC_MI_Instance_GetElement(partialConfigDocumentIns.data[xCount], MI_T("Name"), &value, NULL, &result_Flags, NULL);
                if (r != MI_RESULT_OK || (result_Flags & MI_FLAG_NULL) != 0)
                {
                        // todo: add proper error message
                        EH_Fail_(GetCimMIError(r, cimErrorDetails, ID_MODMAN_VALIDATE_DOCINS));
                }

                concatResult = Stprintf(expandedPartialConfigName, MAX_PATH, MI_T("%T%T"), MI_T("[PartialConfiguration]"), value.string);
                if (concatResult == -1)
                {
                        // todo: add proper error message
                        EH_Fail_(GetCimMIError(MI_RESULT_SERVER_LIMITS_EXCEEDED, cimErrorDetails, ID_LCMHELPER_MEMORY_ERROR));
                }

                searchBucket.key = expandedPartialConfigName;
                bucket = (PartialConfigBucket*) HashMap_Find(&partialConfigDocumentInMap, (const HashBucket*) &searchBucket);
                if (bucket == NULL)
                {
                        // todo: add proper error message
                        EH_Fail_(GetCimMIError(MI_RESULT_SERVER_LIMITS_EXCEEDED, cimErrorDetails, ID_LCMHELPER_MEMORY_ERROR));
                }
                bucket->documentIns = partialConfigDocumentIns.data[xCount];
        }

        //count each partial configuration resource instances, save in hashmap->size
        for (xCount = 0; xCount < resourceInstances->size; xCount++)
        {
                r = DSC_MI_Instance_GetElement(resourceInstances->data[xCount], OMI_BaseResource_ConfigurationName, &value, NULL, &result_Flags, NULL);
                if (r != MI_RESULT_OK || (result_Flags & MI_FLAG_NULL) != 0)
                {
                        // todo: add proper error message
                        EH_Fail_(GetCimMIError(r, cimErrorDetails, ID_MODMAN_VALIDATE_DOCINS));
                }

                concatResult = Stprintf(expandedPartialConfigName, MAX_PATH, MI_T("%T%T"), MI_T("[PartialConfiguration]"), value.string);
                if (concatResult == -1)
                {
                        // todo: add proper error message
                        EH_Fail_(GetCimMIError(MI_RESULT_SERVER_LIMITS_EXCEEDED, cimErrorDetails, ID_LCMHELPER_MEMORY_ERROR));
                }
                searchBucket.key = expandedPartialConfigName;
                bucket = (PartialConfigBucket*) HashMap_Find(&partialConfigDocumentInMap, (const HashBucket*) &searchBucket);
                if (bucket == NULL)
                {
                        // todo: add proper error message
                        EH_Fail_(GetCimMIError(MI_RESULT_SERVER_LIMITS_EXCEEDED, cimErrorDetails, ID_LCMHELPER_MEMORY_ERROR));
                }
                bucket->size++;
        }

        //collect each partial configuration resource instances into hashmap
        for (xCount = 0; xCount < resourceInstances->size; xCount++)
        {
                r = DSC_MI_Instance_GetElement(resourceInstances->data[xCount], OMI_BaseResource_ConfigurationName, &value, NULL, &result_Flags, NULL);
                if (r != MI_RESULT_OK || (result_Flags & MI_FLAG_NULL) != 0)
                {
                        // todo: add proper error message
                        EH_Fail_(GetCimMIError(r, cimErrorDetails, ID_MODMAN_VALIDATE_DOCINS));
                }

                concatResult = Stprintf(expandedPartialConfigName, MAX_PATH, MI_T("%T%T"), MI_T("[PartialConfiguration]"), value.string);
                if (concatResult == -1)
                {
                        // todo: add proper error message
                        EH_Fail_(GetCimMIError(MI_RESULT_SERVER_LIMITS_EXCEEDED, cimErrorDetails, ID_LCMHELPER_MEMORY_ERROR));
                }

                searchBucket.key = expandedPartialConfigName;
                bucket = (PartialConfigBucket*) HashMap_Find(&partialConfigDocumentInMap, (const HashBucket*) &searchBucket);
                if (bucket == NULL)
                {
                        // todo: add proper error message
                        EH_Fail_(GetCimMIError(MI_RESULT_SERVER_LIMITS_EXCEEDED, cimErrorDetails, ID_LCMHELPER_MEMORY_ERROR));
                }

                if (bucket->count == 0 && bucket->size > 0)
                {
                        bucket->resourceInstances = (MI_Instance **) DSC_malloc(bucket->size * sizeof(MI_Instance*), NitsHere());
                        if (bucket->resourceInstances == NULL)
                        {
                                EH_Fail_(GetCimMIError(MI_RESULT_SERVER_LIMITS_EXCEEDED, cimErrorDetails, ID_LCMHELPER_MEMORY_ERROR));
                        }
                }
                bucket->resourceInstances[bucket->count++] = resourceInstances->data[xCount];
        }

        for (xCount = 0; xCount < executionContainer.executionListSize; xCount++)
        {
                partialConfigIn = (MSFT_PartialConfiguration*) partialConfigIns.data[executionContainer.ExecutionList[xCount].resourceIndex];
                searchBucket.key = (MI_Char*) partialConfigIn->ResourceId.value;
                bucket = (PartialConfigBucket*) HashMap_Find(&partialConfigDocumentInMap, (const HashBucket*) &searchBucket);
                if (bucket == NULL)
                {
                        // todo: add proper error message
                        EH_Fail_(GetCimMIError(MI_RESULT_SERVER_LIMITS_EXCEEDED, cimErrorDetails, ID_LCMHELPER_MEMORY_ERROR));
                }
                partialConfigResourceInstances.data = bucket->resourceInstances;
                partialConfigResourceInstances.size = bucket->size;

                if (bucket->count > 0)
                {
                        MI_Boolean dependsExist;
                        r = DependPartialConfigExist(bucket->partialConfig, &partialConfigDocumentInMap, &dependsExist, cimErrorDetails);
                        EH_CheckResult(r);

                        if (dependsExist)
                        {
                            DSC_EventWriteLCMApplyingPartial(searchBucket.key);
                                r = ConfigurationProcessor(lcmContext, moduleManager, flags, bucket->documentIns, &partialConfigResourceInstances, (MI_Instance*) metaConfigInstance, resultStatus, cimErrorDetails);
                                DSC_free(partialConfigResourceInstances.data);
                                if (r != MI_RESULT_OK)
                                {
                                        //Get the message and print a warning
                                        r = DSC_MI_Instance_GetElement(*cimErrorDetails, MSFT_WMIERROR_MESSAGE, &value, NULL, NULL, NULL);
                                        if (value.string != NULL)
                                        {
                                                DSC_WriteWarning2Param((MI_Context*) lcmContext->context, ID_LCMHELPER_APPLYPARTIALCONFIG_FAILED_WITHERROR, searchBucket.key, value.string);
                                        }
                                        if (*cimErrorDetails != NULL)
                                        {
                                            MI_Instance_Delete(*cimErrorDetails);
                                            *cimErrorDetails = NULL;//Clear error details
                                        }
                                        flagPartialConfigFailedToApply = MI_TRUE;
                                        r = MI_RESULT_OK;
                                }
                                else
                                {
                                        //Check the flag where atleast one was set.
                                        flagAtleastOnePartialWasSet = MI_TRUE;

                                        if (!(flags & LCM_EXECUTE_TESTONLY) && (DSC_RESTART_SYSTEM_FLAG & *resultStatus))
                                        {
                                                //Log the message here; log different message depends on the value of RebootNodeIfNeeded(winblue:366265)
                                                MI_Value configModeValue;

                                                r = DSC_MI_Instance_GetElement(metaConfigInstance, MSFT_DSCMetaConfiguration_RebootNodeIfNeeded, &configModeValue, NULL, NULL, NULL);
                                                if (r != MI_RESULT_OK)
                                                {
                                                        return r;
                                                }

                                                //telling user that reboot is scheduled
                                                if (configModeValue.boolean == MI_TRUE)
                                                {
                                                        LCM_BuildMessage(lcmContext, ID_LCM_WRITEMESSAGE_REBOOT, EMPTY_STRING, MI_WRITEMESSAGE_CHANNEL_VERBOSE);
                                                }
                                                //telling user that manual reboot is needed
                                                else
                                                {
                                                        LCM_BuildMessage(lcmContext, ID_LCM_WRITEMESSAGE_REBOOTMANUALLY, EMPTY_STRING, MI_WRITEMESSAGE_CHANNEL_VERBOSE);
                                                }
                                                
                                                // this is the result from ApplyConfigGroup which requires reboot, we know it is ok in the Else clause
                                                return MI_RESULT_OK;
                                        }
                                }
                        }
                        else
                        {
                                //Only a warning that the dependent configuration was not available.
                                DSC_WriteWarning1Param((MI_Context*) lcmContext->context, ID_LCMHELPER_DEPENDSONFILEDOESNTEXIST_MESSAGE, searchBucket.key);
                                flagPartialConfigFailedToApply = MI_TRUE;
                        }
                }
                EH_CheckResult(r);
        }
        if (!flagAtleastOnePartialWasSet)
        {
                if (flagPartialConfigFailedToApply)
                {
                        EH_CheckResult(r = GetCimMIError(MI_RESULT_NOT_FOUND, cimErrorDetails, ID_PARTIALCONFIG_FAILEDPARTIALCONFIGS));
                }
                else
                {
                        EH_CheckResult(r = GetCimMIError(MI_RESULT_NOT_FOUND, cimErrorDetails, ID_PARTIALCONFIG_NOPARTIALCONFIGPRESENT));
                }
        }

EH_UNWIND;
        CleanUpInstanceCache(&partialConfigDocumentIns);
        if (tempInstance != NULL)
        {
            DSC_free(tempInstance);
        }

        if (hashInited)
        {
                HashMap_Destroy(&partialConfigDocumentInMap);
        }
        FreeExecutionOrderContainer(&executionContainer);

        return r;

}