DDMI/Connect It to UD/UCMDB product integration - Hardware.xml normalization in Asset Manager

Hello expefrts. I have a client going from DDMi/ConnectIt to UD/UCMDB. This is about the fourth project I have done something similar to this on. Everything in the push to AM adapters seems to be going smoothly, except we did notice that we have some duplicatgion of hardware models. I have seen this issue in past engagements also. Looking at the Hardware.xml mapping and comparing it to the Software.xml mapping, I notice that the software references the InventModel table. That does not exist in the Hardware mapping. I think in the past what I have done to solve this was to copy and past the normalization code into Hardware.xml, tweak it as needed and it worked fine. Does this sound like a feasible approach? I can't recall exactly if that was the solution so any help is greatly appreciated. Thanks.
  • Verified Answer

    The Invent Model table is only used for mapping software to a normalized final model in the amModel table. For Hardware what you will want to do is review pushMappingAMComputer.xml and decide how best to enter your models so that they reconcile with what is in the amModel table in HPAM. For instance, whether to use the toSmart() method on model names which will capitalize the first letter of each word (i.e. ProLiant DL360 G2 will change to Proliant Dl360 G2). I also switched the order for populating the variable vModelName to Root['discovered_model'] first and then Root['node_model'] if empty.

     

    Do some clean up of your amModel table and move associated records from the duplicate models to the model you want going forward then delete the duplicate model. I use a calculated field called Portfolio Count in the amModel table to see how many portfolio records are associated to each model.

    (SELECT Sum(fQty) FROM amPortfolio WHERE lModelId = amModel.lModelId)

    I remove any models that have zero portfolio records.

     

     

    I also move models so that they are in a logical hierarchy and have a parent model based on the type of device.

     

    Creating this structure then enables me to use the model name and model parent as the reconciliation key and link the model by reference to the node.

    am-push-mapping.xml:

        <am-mapping ci-type="amModel" primary-key="lModelId" operation-type="insert_else_reference" merge-allowed="true" parallel-push-allowed="true">
            <reconciliation>
                <reconciliation-keys>
                    <reconciliation-key>Name</reconciliation-key>
                    <reconciliation-key>lParentId</reconciliation-key>
                </reconciliation-keys>
            </reconciliation>
            <reference-attribute ci-name="amBrand" datatype="STRING" name="lBrandId" reference-direction="child"/>
            <reference-attribute ci-name="amNature" datatype="STRING" name="lNatureId" reference-direction="child"/>
            <reference-attribute ci-name="amModel-Parent" datatype="STRING" name="lParentId" reference-direction="child"/>
            <action-on-delete>
                <ignore/>
            </action-on-delete>
        </am-mapping>

     

    To get the correct model parent I created a dynamic lookup table in pushMappingAMComputer.xml

                <dynamic_mapping name="ParentBarCodeByModelName" keys-unique="true">
                    <map_property property-name="AQLQuery" datatype="STRING"
                                  property-value="SELECT Lower(Name), Parent.BarCode FROM amModel WHERE Nature.Code IN ('CPU','CPUVM')"/>                              
                </dynamic_mapping>

    I then created a custom method in AMPushFunctions.groovy

     

        public static String getMyModelParentBarCode(boolean iIsComputerAVM, def dynamicMapHolder, String modelName, nodeRole) {
            if(iIsComputerAVM){
                return MODEL_VM_AC50;
            }
            else{     
                def modelParentBarCodeMap = dynamicMapHolder.getMap("ParentBarCodeByModelName");
                if(isNull(modelParentBarCodeMap)){
                    throw new MessageOnlyPushMappingException("Model parent map is missing.", WARNING_MAPPING_CI_ERROR_ID);
                }
                else if(isNull(modelParentBarCodeMap.get(modelName))){
                    //throw new MessageOnlyPushMappingException("Asset Manager has no parent model for model name [" modelName "].", WARNING_MAPPING_CI_ERROR_ID);
                    if(fIsEmpty(nodeRole)){
                        return 'UNKCHASSIS';
                    } else {
                        if(nodeRole.contains('server') && !nodeRole.contains('desktop')){
                            return SERVER_CODE;
                        } else if(nodeRole.contains('desktop') && !nodeRole.contains('server')){
                            return MODEL_WORKSTATION_AC50;
                        }
                    }
                    //Unknown model and unknown node role
                    return 'UNKCHASSIS';
                }
                return modelParentBarCodeMap.get(modelName);
            }
        }

    I then call that custom method in pushMappingAMComputer.xml

     

                        <target_ci_type name="amModel">
                            <target_mapping name="CPUType" datatype="STRING" value="vCpuSpecifier"/>
                            <target_mapping name="Name" datatype="STRING" ignore-on-null="false" value="vModelName"/>
                            <target_ci_type name="amBrand">
                                <target_mapping name="Name" datatype="STRING" value="AMPushFunctions.getBrandName(Root['discovered_vendor'],Root['vendor'])"/>
                            </target_ci_type>
                            <target_ci_type name="amNature">
                                <target_mapping name="Code" datatype="STRING" value="vNatureCode"/>
                            </target_ci_type>
                            <target_ci_type name="amModel-Parent">
                                <target_mapping name="BarCode" datatype="STRING" ignore-on-null="false" value="AMPushFunctions.getMyModelParentBarCode(iIsComputerAVM, DynamicMapHolder, vModelName.toLowerCase(), Root['node_role'])"/>
                            </target_ci_type>
                            <before-mapping>Logger.debug('before')</before-mapping>
                            <after-mapping>Logger.debug('vModelName:' vModelName)</after-mapping>
                        </target_ci_type>

     

    Since the model is linked by reference I don't have to worry about the model names getting duplicated or changing case.