static ClRcT clAmsEntityLocate(ClAmsEntityT *pEntity)
{
    ClRcT rc = CL_OK;
    register ClInt32T i;

    for(i = CL_AMS_ENTITY_TYPE_ENTITY + 1;  i < CL_AMS_ENTITY_TYPE_MAX + 1; ++i)
    {
        ClAmsEntityConfigT *pEntityConfig = NULL;
        pEntity->type = (ClAmsEntityTypeT) i;
        rc = clAmsMgmtEntityGetConfig(gClAmsEntityTriggerMgmtHandle,
                                      pEntity,
                                      &pEntityConfig);
        if(rc != CL_OK)
        {
            if(pEntityConfig)
                clHeapFree(pEntityConfig);

            continue;
        }
        memcpy(pEntity, pEntityConfig, sizeof(*pEntity));
        clHeapFree(pEntityConfig);
        return CL_OK;
    }
    return CL_AMS_RC(CL_ERR_NOT_EXIST);

}
static ClRcT clAmsMgmtOIConfigAttributeSet(ClAmsMgmtHandleT handle,
                                           ClCorTxnSessionIdT *pSession, 
                                           ClCorMOIdT *pMoId, 
                                           ClAmsEntityT *pEntity, 
                                           ClRcT (*pClAmsMgmtOIConfigAttributesGet)
                                           (ClAmsEntityConfigT*, ClCorAttributeValueListPtrT ))
{
    ClCorObjectHandleT objHandle = 0;
    ClRcT rc = CL_OK;
    ClCorAttributeValueListT attrList = {0};
    ClAmsEntityConfigT *pEntityConfig = NULL;

    if(!handle || !pSession || !pMoId || !pEntity || !pClAmsMgmtOIConfigAttributesGet)
        return CL_AMS_RC(CL_ERR_INVALID_PARAMETER);

    rc = clAmsMgmtEntityGetConfig(handle, pEntity, &pEntityConfig);
    if(rc != CL_OK || !pEntityConfig) 
    {
        clLogError("AMF", "MGMT", "Entity [%s] config get returned [%#x]",
                   pEntity->name.value, rc);
        return rc;
    }
    rc = clCorMoIdToObjectHandleGet(pMoId, &objHandle);
    if(rc != CL_OK) 
    {
        goto out_free;
    }
    rc = (*pClAmsMgmtOIConfigAttributesGet)(pEntityConfig, &attrList);
    if(rc != CL_OK)
    {
        goto out_free;
    }
    rc = clAmsMgmtOIAttributeSet(pEntity, pSession, objHandle, &attrList);

    out_free:
    if(pEntityConfig)
        clHeapFree(pEntityConfig);
    if(objHandle)
        clCorObjectHandleFree(&objHandle);
    if(attrList.pAttributeValue)
        clHeapFree(attrList.pAttributeValue);

    return rc;
}
ClRcT clAmfNodeSet(ClAmsMgmtHandleT mgmtHandle, const ClProvTxnDataT *pProvTxnData)
{
    ClAmsEntityT entity = {0};
    ClRcT rc = CL_OK;

    if(!mgmtHandle)
        return CL_OK;

    if(!pProvTxnData || !pProvTxnData->pProvData || !pProvTxnData->pMoId)
        return CL_AMS_RC(CL_ERR_INVALID_PARAMETER);

    entity.type = CL_AMS_ENTITY_TYPE_NODE;
    rc = clAmsMgmtOIGet(pProvTxnData->pMoId, &entity);
    if(rc != CL_OK)
    {
        SaNameT moidName = {0};
        if(clCorMoIdToMoIdNameGet(pProvTxnData->pMoId, &moidName) == CL_OK)
            clLogError("OI", "READ", "AMF entity not found for moid [%.*s]",
                       moidName.length, moidName.value);
        return rc;
    }

    switch (pProvTxnData->attrId)
    {
        case SAAMFNODETABLE_SAAMFNODEADMINSTATETRIGGER:
        {
            ClAmsNodeConfigT *pNodeConfig = NULL;
            ClInt32T adminState = *(ClInt32T *)pProvTxnData->pProvData;

            rc = clAmsMgmtEntityGetConfig(mgmtHandle, &entity, 
                                          (ClAmsEntityConfigT**)&pNodeConfig);
            if (rc != CL_OK)
            {
                clLogError("OI", "WRITE", "Node [%s] config returned [%#x]",
                           entity.name.value, rc);
                return rc;
            }
            if (pProvTxnData->size != (ClUint32T)sizeof(pNodeConfig->adminState))
            {
                clLogError("OI", "WRITE", "Read size [%d] doesnt match expected size [%d]",
                           pProvTxnData->size, (ClUint32T)pNodeConfig->adminState);
                clHeapFree(pNodeConfig);
                return CL_AMS_RC(CL_ERR_INVALID_PARAMETER);
            }

            switch (adminState)
            {
                case SAAMFNODEADMINSTATETRIGGER_STABLE:
                {
                    return CL_OK;
                }
         
                case SAAMFNODEADMINSTATETRIGGER_UNLOCKINSTANTIATION:
                case SAAMFNODEADMINSTATETRIGGER_LOCK:
                {
                    rc = clAmsMgmtEntityLockAssignment(mgmtHandle, &entity);
                    break;
                }
                case SAAMFNODEADMINSTATETRIGGER_UNLOCK:
                {
                    if(clAmsMgmtEntityLockAssignment(mgmtHandle, &entity) == CL_OK)
                        sleep(1);
                    rc = clAmsMgmtEntityUnlock(mgmtHandle, &entity);
                    break;
                }
                case SAAMFNODEADMINSTATETRIGGER_LOCKINSTANTIATION:
                {
                    /*
                     * Careful. If snmp subagent is running on only 1 node
                     * and is not redundant, then the snmp query would timeout
                     * as it would take down the subagent as well.
                     */
                    if(clAmsMgmtEntityLockAssignment(mgmtHandle, &entity) == CL_OK)
                        sleep(1);
                    rc = clAmsMgmtEntityLockInstantiation(mgmtHandle, &entity);
                    break;
                }
            }
 
            clHeapFree(pNodeConfig);
            break;
        }
        case SAAMFNODETABLE_SAAMFNODEAUTOREPAIROPTION:
        {
            break;
        }
        case SAAMFNODETABLE_SAAMFNODECLMNODE:
        {
            break;
        }
        case SAAMFNODETABLE_SAAMFNODENAME:
        {
            break;
        }
        case SAAMFNODETABLE_SAAMFNODEREPAIR:
        {
            break;
        }
        case SAAMFNODETABLE_SAAMFNODESUFAILOVERPROB:
        {
            break;
        }
        default:
        {
            break;
        }
    }

    return rc;
}
/**
 * This function is called to perform a get operation on the transient attribute
 * which is owned by the primary object implementer (OI). As the COR doesn't have
 * the latest value of the transient attribute, it is obtained from the OI. This
 * function is called in the OI's context which it can use to fill the latest
 * value of the runtime or transient attribute.
 *
 * The pThis is pointer to the provisioning class.
 * The txnHandle is used to identify the jobs which are part of same bundle request.
 * For single request this field is of not much significance, but for a multiple job
 * request, this feild is used to identify all the jobs which are part of same
 * bundle request sent by COR.
 *
 * The pProvTxnData contains the information about the attribute jobs. It contains 
 * the MOId of the managed resource, the attribute identifier, its type (array or 
 * simple), its basic type (data type), index (in case it is array attriubte), 
 * size and the pointer (allocated by the library) to the memory on which the 
 * data can be copied.
 *
 * For a request containing only single job, this function is called only once. But
 * for a multiple job request, this is called for all the attributes one at a time.
 *
 * ** Note : This function is being deprecated, if clProvObjectRead() callback is filled 
 * in the constructor, then that callback function will be called instead of this 
 * to group read all the requests.
 */ 
ClRcT clamfMgmtSAAMFSITABLEProvRead(CL_OM_PROV_CLASS* pThis, ClHandleT txnHandle, ClProvTxnDataT* pProvTxnData)
{
    ClRcT rc = CL_OK;

    /*
     * ---BEGIN_APPLICATION_CODE---
     */

    ClAmsEntityT entity = {0};
    clprintf(CL_LOG_SEV_INFO, "Inside the function %s", __FUNCTION__);
    if(!gClAmsMgmtHandle)
        return CL_AMS_RC(CL_ERR_NOT_INITIALIZED);
    if(!pProvTxnData || !pProvTxnData->pProvData || !pProvTxnData->pMoId)
        return CL_AMS_RC(CL_ERR_INVALID_PARAMETER);
    entity.type = CL_AMS_ENTITY_TYPE_SI;
    rc = clAmsMgmtOIGet(pProvTxnData->pMoId, &entity);
    if(rc != CL_OK)
    {
        ClNameT moidName = {0};
        if(clCorMoIdToMoIdNameGet(pProvTxnData->pMoId, &moidName) == CL_OK)
            clLogError("OI", "READ", "AMF entity not found for moid [%.*s]",
                    moidName.length, moidName.value);
        return rc;
    }

    switch(pProvTxnData->attrId)
    {
        case SAAMFSITABLE_SAAMFSIADMINSTATE:
            {
                ClAmsSIConfigT *pSIConfig = NULL;
                rc = clAmsMgmtEntityGetConfig(gClAmsMgmtHandle, &entity, (ClAmsEntityConfigT**)&pSIConfig);
                if(rc != CL_OK)
                {
                    clLogError("OI", "READ", "SI [%s] config get returned [%#x]",
                            entity.name.value, rc);
                    return rc;
                }
                if(pProvTxnData->size != (ClUint32T)sizeof(pSIConfig->adminState))
                {
                    clLogError("OI", "READ", "Read size [%d] doesnt match expected size [%d]",
                            pProvTxnData->size, (ClUint32T)sizeof(pSIConfig->adminState));
                    clHeapFree(pSIConfig);
                    return CL_AMS_RC(CL_ERR_INVALID_PARAMETER);
                }
                memcpy(pProvTxnData->pProvData, &pSIConfig->adminState, pProvTxnData->size);
                clHeapFree(pSIConfig);
            }
            break;

        case SAAMFSITABLE_SAAMFSINUMCURRACTIVEASSIGNMENTS:
        case SAAMFSITABLE_SAAMFSINUMCURRSTANDBYASSIGNMENTS:
            {
                ClAmsSIStatusT *pSIStatus = NULL;
                rc = clAmsMgmtEntityGetStatus(gClAmsMgmtHandle, &entity, (ClAmsEntityStatusT**)&pSIStatus);
                if(rc != CL_OK)
                {
                    clLogError("OI", "READ", "SI [%s] status returned [%#x]", entity.name.value, rc);
                    return rc;
                }
                if(pProvTxnData->size != (ClUint32T)sizeof(pSIStatus->numActiveAssignments))
                {
                    clLogError("OI", "READ", "Read size [%d] doesnt match expected size [%d]",
                            pProvTxnData->size, (ClUint32T)sizeof(pSIStatus->numActiveAssignments));
                    clHeapFree(pSIStatus);
                    return CL_AMS_RC(CL_ERR_INVALID_PARAMETER);
                }
                if(pProvTxnData->attrId == SAAMFSITABLE_SAAMFSINUMCURRACTIVEASSIGNMENTS)
                    memcpy(pProvTxnData->pProvData, &pSIStatus->numActiveAssignments, pProvTxnData->size);
                else
                    memcpy(pProvTxnData->pProvData, &pSIStatus->numStandbyAssignments, pProvTxnData->size);
                clHeapFree(pSIStatus);
            }
            break;

        default:
            return CL_AMS_RC(CL_ERR_NOT_SUPPORTED);
    }

    /*
     * ---END_APPLICATION_CODE---
     */

    return rc;
}
// Start this app container running on these nodes (1+N redundancy).  This will
// start a SAF-aware process on each node specified.
// Create SU and Comp
void acExtend(const char* appCnt, const char* nodeName, const char* compName,SafConfig* cfg)
{
  ClRcT rc;
  ClAmsEntityConfigT  sg;
  ClAmsEntityConfigT  comp;
  ClAmsEntityConfigT su;
  ClUint64T           changeMask = 0;
  
  ClAmsSGConfigT      sgConfig;
  ClAmsEntityConfigT* pEntityConfig = NULL;

  if (ccbHandle==CL_HANDLE_INVALID_VALUE) initHandles();
  initEntity(&sg,appCnt,CL_AMS_ENTITY_TYPE_SG);
  
    
  if ((rc = clAmsMgmtEntityGetConfig(mgmtHandle,&sg,&pEntityConfig)) != CL_OK)
    {
      checkError("Get SG configuration", rc);
    }

  memcpy(&sgConfig, pEntityConfig, sizeof(sgConfig));
  clHeapFree(pEntityConfig);

  //Fix bug: recovery policy
  if (cfg && cfg->compRestartCountMax > 0 && cfg->compRestartDuration > 0)
    {
      sgConfig.compRestartCountMax = cfg->compRestartCountMax;
      sgConfig.compRestartDuration = cfg->compRestartDuration;
      changeMask |= SG_CONFIG_COMP_RESTART_DURATION | SG_CONFIG_COMP_RESTART_COUNT_MAX;
      if ((rc = clAmsMgmtCCBEntitySetConfig(ccbHandle,&sgConfig.entity,changeMask) ) != CL_OK)
        {
          checkError("Set SG config", rc);
        }
    }
  
  // Create SU and component per node
  if (1)
    {
      initEntity(&su,compName,CL_AMS_ENTITY_TYPE_SU);
      if ((rc = clAmsMgmtCCBEntityCreate(ccbHandle,&su)) != CL_OK)
        {
          checkError("Create SU", rc);
        }
      
      initEntity(&comp,compName,CL_AMS_ENTITY_TYPE_COMP);
      if ((rc = clAmsMgmtCCBEntityCreate(ccbHandle,&comp)) != CL_OK)
        {
          checkError("Create Comp", rc);
        }     
      
    }
  
  if ((rc = clAmsMgmtCCBCommit(ccbHandle)) != CL_OK)
    {
      checkError("Commit creation of SU and Component", rc);
    }

  SaNameT            supportedCSIType;

  saNameSet(&supportedCSIType, CSI_TYPE_APP);
  supportedCSIType.length += 1;

  // Configure components
  if (1)
    {
      ClAmsCompConfigT   compConfig;
      ClUint64T          bitMask = 0;
      
      if ((rc = clAmsMgmtEntityGetConfig(mgmtHandle,&comp,&pEntityConfig)) != CL_OK)
        {
          checkError("Retrieve component config", rc);
        }
      memcpy(&compConfig, pEntityConfig, sizeof(compConfig));
      clHeapFree(pEntityConfig);

      bitMask |= COMP_CONFIG_CAPABILITY_MODEL | COMP_CONFIG_TIMEOUTS;

      compConfig.capabilityModel = CL_AMS_COMP_CAP_X_ACTIVE_OR_Y_STANDBY;
      compConfig.timeouts.instantiate = 30000;
      compConfig.timeouts.terminate = 30000;
      compConfig.timeouts.cleanup = 30000;
      compConfig.timeouts.quiescingComplete = 30000;
      compConfig.timeouts.csiSet = 30000;
      compConfig.timeouts.csiRemove = 30000;
      compConfig.timeouts.instantiateDelay = 1000;
      if (!strncmp(nodeName, "sc", 2))
        {    	  
      	  if (cfg && cfg->compRestartCountMax == 0)
      	  {
      		  bitMask |= COMP_CONFIG_IS_RESTARTABLE | COMP_CONFIG_RECOVERY_ON_TIMEOUT;
      		  compConfig.isRestartable = false;
      		  compConfig.recoveryOnTimeout = CL_AMS_RECOVERY_NODE_FAILOVER;	     
      	  }    		
      	  else
      	  {    			      	 
      		  bitMask  |= COMP_CONFIG_RECOVERY_ON_TIMEOUT;
      		  compConfig.recoveryOnTimeout = CL_AMS_RECOVERY_NO_RECOMMENDATION;	      	 
      	  }
        }
        else
        {
      	  if (cfg && cfg->compRestartCountMax == 0)
      	  {
      		  bitMask |= COMP_CONFIG_IS_RESTARTABLE | COMP_CONFIG_RECOVERY_ON_TIMEOUT;
      		  compConfig.isRestartable = false;
      		  compConfig.recoveryOnTimeout = CL_AMS_RECOVERY_COMP_FAILOVER;	     
      	  }    		
      	  else
      	  {    			      	 
      		  bitMask  |= COMP_CONFIG_RECOVERY_ON_TIMEOUT;
      		  compConfig.recoveryOnTimeout = CL_AMS_RECOVERY_NO_RECOMMENDATION;	      	 
      	  }
        }

      if ((rc = clAmsMgmtCCBEntitySetConfig(ccbHandle,&compConfig.entity,bitMask) ) != CL_OK)
        {
        checkError("Set component config", rc);
        }
      
      bitMask = COMP_CONFIG_INSTANTIATE_COMMAND;
      if (cfg&&cfg->binName)
        {
        snprintf(compConfig.instantiateCommand, sizeof(compConfig.instantiateCommand), cfg->binName);
        }
      else
        {
        snprintf(compConfig.instantiateCommand, sizeof(compConfig.instantiateCommand), APP_CNT_CMD);
        }
            
      if ((rc = clAmsMgmtCCBEntitySetConfig(ccbHandle,&compConfig.entity,bitMask) ) != CL_OK)
        {
        checkError("Set component instantiate command", rc);          
        }      
    }  

  if ((rc = clAmsMgmtCCBCommit(ccbHandle)) != CL_OK)
    {
      checkError("Commit configure of components", rc);
    }

    // Configure components
  if (1)
    {
      ClAmsCompConfigT   compConfig;
      ClUint64T          bitMask = 0;
      

      if ((rc = clAmsMgmtEntityGetConfig(mgmtHandle,&comp,&pEntityConfig)) != CL_OK)
        {
          checkError("Retrieve component config", rc);
        }
      memcpy(&compConfig, pEntityConfig, sizeof(compConfig));
      clHeapFree(pEntityConfig);

      bitMask |= COMP_CONFIG_SUPPORTED_CSI_TYPE | COMP_CONFIG_NUM_MAX_ACTIVE_CSIS | COMP_CONFIG_NUM_MAX_STANDBY_CSIS;

      if(compConfig.pSupportedCSITypes)
        clHeapFree(compConfig.pSupportedCSITypes);
            
      compConfig.numSupportedCSITypes = 1;
      compConfig.pSupportedCSITypes   = &supportedCSIType;
      compConfig.numMaxActiveCSIs     = 10000;
      compConfig.numMaxStandbyCSIs    = 10000;
      
      if ((rc = clAmsMgmtCCBEntitySetConfig(ccbHandle,&compConfig.entity,bitMask) ) != CL_OK)
        {
          checkError("Setting supported CSI types", rc);
        }            
    }  

  if ((rc = clAmsMgmtCCBCommit(ccbHandle)) != CL_OK)
    {
      checkError("Configuring components supported CSI type", rc);
    }

  
  // Configure SUs
  if (1)
    {
      ClUint64T bitMask = 0;
      ClAmsSUConfigT suConfig;

      if ((rc = clAmsMgmtEntityGetConfig(mgmtHandle,&su,&pEntityConfig)) != CL_OK)
        {
          checkError("Get SU", rc);
        }
      
      memcpy(&suConfig, pEntityConfig, sizeof(suConfig));
      clHeapFree(pEntityConfig);

      bitMask |= SU_CONFIG_NUM_COMPONENTS |  SU_CONFIG_ADMIN_STATE;
      // set number of components (processes) per SU to 1
      suConfig.numComponents = 1;
      //suConfig.adminState = CL_AMS_ADMIN_STATE_UNLOCKED;
      suConfig.adminState = CL_AMS_ADMIN_STATE_LOCKED_I;      

      if ((rc = clAmsMgmtCCBEntitySetConfig(ccbHandle,&suConfig.entity,bitMask)) != CL_OK)
        {
           checkError("Configure SU", rc);
         
        }
      // attach the comp to the su
      if ((rc = clAmsMgmtCCBSetSUCompList(ccbHandle,&su,&comp)) != CL_OK)
        {
          checkError("Link COMP to SU", rc);          
        }      
    }

  if ((rc = clAmsMgmtCCBCommit(ccbHandle)) != CL_OK)
    {
      checkError("Commit SU configuration", rc);          
    }

  
  // Add the SU to SG's and Node's list
  if (1)
    {
      ClAmsEntityConfigT node;
      initEntity(&node,nodeName,CL_AMS_ENTITY_TYPE_NODE);

      if ((rc = clAmsMgmtCCBSetSGSUList(ccbHandle,&sg,&su)) != CL_OK)
        {
          checkError("Add SU to SG", rc);
        }

      if ((rc = clAmsMgmtCCBSetNodeSUList(ccbHandle,&node,&su)) != CL_OK)
        {
          checkError("Add SU to Node", rc);
        }

      /*
      if ((rc = clAmsMgmtCCBCommit(ccbHandle) ) != CL_OK)
        {
          checkError("Committing addition of SU to node and SG", rc);
        }
      */

      if ((rc = clAmsMgmtCCBCommit(ccbHandle) ) != CL_OK)
        {
          checkError("Committing addition of SU to node and SG", rc);
        }  
    }

  // Now that all is configured, start them up
  entityStart(su);
}
static void initHandles(void)
{
    ClRcT rc;
    rc = clAmsMgmtInitialize(&mgmtHandle, NULL, &amfApiVersion);
    if(rc != CL_OK)
    {
        checkError("AMS mgmt handle init",rc);
    }    
    if ((rc = clAmsMgmtCCBInitialize(mgmtHandle, &ccbHandle)) != CL_OK)
    {
        checkError("AMS mgmt config change handle init",rc);
    }

    //  Create the CSI type by creating an unused CSI.
    
    ClAmsEntityConfigT csi;
    memset(&csi,0,sizeof(csi));
    saNameSet(&csi.name,"unusedCSI");
    csi.type = CL_AMS_ENTITY_TYPE_CSI;
    
    if ((rc = clAmsMgmtCCBEntityCreate(ccbHandle,&csi)) != CL_OK)
    {
        checkError("Create CSI",rc);
    }

    if ((rc = clAmsMgmtCCBCommit(ccbHandle)) != CL_OK)
    {
        checkError("Commit SI/CSI creation", rc);
    }

    if(rc == CL_OK)
    {
        ClAmsEntityConfigT *pEntityConfig = NULL;
        ClUint64T changeMask = 0;
        ClAmsCSIConfigT csiConfig;

        // Grab the CSI object
        if ((rc = clAmsMgmtEntityGetConfig(mgmtHandle,&csi,&pEntityConfig)) != CL_OK)
        {
            checkError("Get CSI configuration", rc);
        }
      
        memcpy(&csiConfig, pEntityConfig, sizeof(csiConfig));
        clHeapFree(pEntityConfig);

        // Specify a unique CSI type
        changeMask |= CSI_CONFIG_TYPE;
        saNameSet(&csiConfig.type, CSI_TYPE_APP);
        csiConfig.type.length += 1;

        if ((rc = clAmsMgmtCCBEntitySetConfig(ccbHandle,&csiConfig.entity,changeMask)) != CL_OK)
        {
            checkError("Set CSI type", rc);
        }
      
        // Commit CSI
        if ((rc = clAmsMgmtCCBCommit(ccbHandle)) != CL_OK)
        {
            checkError("Commit CSI",rc);
        }      
      
    }

  
}
// Create a new application container in the AMF
void addAppCnt(const char* safName,SafConfig* cfg)
{
  ClRcT rc;
  ClAmsEntityConfigT sg;

  // Create the SG object
  if (ccbHandle==CL_HANDLE_INVALID_VALUE) initHandles();
  initEntity(&sg,safName,CL_AMS_ENTITY_TYPE_SG);

  if ((rc = clAmsMgmtCCBEntityCreate(ccbHandle,&sg)) != CL_OK)
    {
      checkError("Create SG",rc);      
    }

  if ((rc = clAmsMgmtCCBCommit(ccbHandle)) != CL_OK)
    {
      checkError("Commit create SG",rc);      
    }

  // Now configure it -- for now just use the defaults
  if (1)
    {
      ClAmsSGConfigT      sgConfig;
      ClAmsEntityConfigT* pEntityConfig = NULL;
      ClUint64T           changeMask = 0;
      
      if ((rc = clAmsMgmtEntityGetConfig(mgmtHandle,&sg,&pEntityConfig)) != CL_OK)
        {
        checkError("Get SG config",rc);      
        }

      memcpy(&sgConfig, pEntityConfig, sizeof(sgConfig));
      clHeapFree(pEntityConfig);

      changeMask |= SG_CONFIG_REDUNDANCY_MODEL | SG_CONFIG_NUM_PREF_ACTIVE_SUS
        | SG_CONFIG_NUM_PREF_STANDBY_SUS | SG_CONFIG_NUM_PREF_INSERVICE_SUS
        | SG_CONFIG_MAX_ACTIVE_SIS_PER_SU | SG_CONFIG_MAX_STANDBY_SIS_PER_SU
        | SG_CONFIG_INSTANTIATE_DURATION;

      sgConfig.redundancyModel     = CL_AMS_SG_REDUNDANCY_MODEL_TWO_N;
      sgConfig.numPrefActiveSUs    = 1;  // Just a very large number, so the check does not occur in the custom model
      sgConfig.numPrefStandbySUs   = 1;  
      sgConfig.numPrefInserviceSUs = 2;
      sgConfig.maxActiveSIsPerSU   = 1;
      sgConfig.maxStandbySIsPerSU  = 1;
      sgConfig.instantiateDuration = 1000;
      
      //Recovery policy
      if (cfg && cfg->compRestartCountMax > 0 && cfg->compRestartDuration > 0)
        {
          sgConfig.compRestartCountMax = cfg->compRestartCountMax;
          sgConfig.compRestartDuration = cfg->compRestartDuration;	  
          changeMask |= SG_CONFIG_COMP_RESTART_DURATION | SG_CONFIG_COMP_RESTART_COUNT_MAX;
        }
      
      if ((rc = clAmsMgmtCCBEntitySetConfig(ccbHandle,&sgConfig.entity,changeMask) ) != CL_OK)
        {
        checkError("Set SG config", rc);
        }
      
      
      if ((rc = clAmsMgmtCCBCommit(ccbHandle) ) != CL_OK)
        {
        checkError("Commit change SG config",rc);
        }
    }

  // Add the scheduler application in.
  // In particular this defines the CSI TYPE in the SG so it will work when used during component addition.
  //acAddApp(safName,"scheduler","");
 
}
    // Add an application to this app container.
    // The effect of this is to create a new SAF Service Instance (SI) and CSI
    // This SI will be assigned to the SG and therefore a process running on the cluster
    // This process shall use the information in the SI to start the appropriate
    // application running.
void acAddApp(const char* appCnt,const char* appName, const char* activeXml, const char* standbyXml)
{
  ClRcT rc;
  ClAmsEntityConfigT sg;
  ClAmsEntityConfigT si;
  ClAmsEntityConfigT csi;
  
  if (ccbHandle==CL_HANDLE_INVALID_VALUE) initHandles();
  initEntity(&sg,appCnt,CL_AMS_ENTITY_TYPE_SG);
  initEntity(&si,appName,CL_AMS_ENTITY_TYPE_SI);
  initEntity(&csi,appName,CL_AMS_ENTITY_TYPE_CSI);

  // Create the new entities
  if ((rc = clAmsMgmtCCBEntityCreate(ccbHandle,&si)) != CL_OK)
    {
      checkError("Create SI",rc);
    }
  if ((rc = clAmsMgmtCCBCommit(ccbHandle)) != CL_OK)
    {
      checkError("Commit SI creation", rc);
    }
  
  if ((rc = clAmsMgmtCCBEntityCreate(ccbHandle,&csi)) != CL_OK)
    {
      checkError("Create CSI",rc);
    }

  if ((rc = clAmsMgmtCCBCommit(ccbHandle)) != CL_OK)
    {
      checkError("Commit CSI creation", rc);
    }


  // Configure the new entities
  if (1) // configure the SI
    {
      ClUint64T changeMask = 0;
      ClAmsEntityConfigT *pEntityConfig = NULL;
      ClAmsSIConfigT siConfig;

      // Grab the SI object
      if ((rc = clAmsMgmtEntityGetConfig(mgmtHandle,&si,&pEntityConfig)) != CL_OK)
        {
           checkError("Get SI config", rc);
        }

      memcpy(&siConfig, pEntityConfig, sizeof(siConfig));
      clHeapFree(pEntityConfig);

      // Configure SI state
      siConfig.numCSIs = 1;
      siConfig.numStandbyAssignments = 1; 
      changeMask |= SI_CONFIG_NUM_CSIS | SI_CONFIG_NUM_STANDBY_ASSIGNMENTS;

      if ((rc = clAmsMgmtCCBEntitySetConfig(ccbHandle,&siConfig.entity,changeMask)) != CL_OK)
        {
          checkError("Set SI config", rc);
        }

      // Link SI to the CSI
      if ((rc = clAmsMgmtCCBSetSICSIList(ccbHandle,&si,&csi)) != CL_OK)
        {
           checkError("Change SI config", rc);
        }

      // Commit SI
      if ((rc = clAmsMgmtCCBCommit(ccbHandle)) != CL_OK)
        {
           checkError("Commit SI configuration", rc);
        }      
    }

  if (1) // configure the CSI
    {
      ClAmsEntityConfigT *pEntityConfig = NULL;
      ClUint64T changeMask = 0;
      ClAmsCSIConfigT csiConfig;
      ClAmsCSINVPT nvp;

      // Grab the CSI object
      if ((rc = clAmsMgmtEntityGetConfig(mgmtHandle,&csi,&pEntityConfig)) != CL_OK)
        {
          checkError("Get CSI configuration", rc);
        }
      
      memcpy(&csiConfig, pEntityConfig, sizeof(csiConfig));
      clHeapFree(pEntityConfig);

      // Specify a unique CSI type
      changeMask |= CSI_CONFIG_TYPE;
      saNameSet(&csiConfig.type, CSI_TYPE_APP);
      csiConfig.type.length += 1;

      if ((rc = clAmsMgmtCCBEntitySetConfig(ccbHandle,&csiConfig.entity,changeMask)) != CL_OK)
        {
          checkError("Set CSI type", rc);
        }
      
      // Set the name/value pairs
      saNameSet(&nvp.paramName,"activexml");
      saNameSet(&nvp.paramValue,activeXml);
      if ((rc = clAmsMgmtCCBCSISetNVP(ccbHandle,&csi,&nvp)) != CL_OK)
        {
          checkError("Set CSI NVP", rc);
        }
      // Set the name/value pairs
      saNameSet(&nvp.paramName,"standbyxml");
      saNameSet(&nvp.paramValue,standbyXml);
      if ((rc = clAmsMgmtCCBCSISetNVP(ccbHandle,&csi,&nvp)) != CL_OK)
        {
          checkError("Set CSI NVP", rc);
        }

      // Commit CSI
      if ((rc = clAmsMgmtCCBCommit(ccbHandle)) != CL_OK)
        {
          checkError("Commit CSI",rc);
        }      
      
    }

    if (1) // Link the SI to the SG
    {
      if ((rc = clAmsMgmtCCBSetSGSIList(ccbHandle,&sg,&si)) != CL_OK)
        {
          checkError("Add SI to SG", rc);
        }
      
      if ((rc = clAmsMgmtCCBCommit(ccbHandle) ) != CL_OK)
        {
          checkError("Commit adding SI to SG", rc);
        }
    }
    /*
     * Unlock or start the SI
     */
    if((rc = clAmsMgmtEntityUnlock(mgmtHandle, &si)) != CL_OK 
       &&
       CL_GET_ERROR_CODE(rc) != CL_ERR_NO_OP)
    {
        checkError("SI unlock failed", rc);
    }
}
static ClRcT clAmsMgmtSGRedundancyModelEstimate(ClAmsSGRedundancyModelT model,
                                                ClAmsEntityT *sgName,
                                                ClUint32T numActiveSUs,
                                                ClUint32T numStandbySUs,
                                                ClInt32T *extraSIs,
                                                ClInt32T *extraSUs,
                                                ClInt32T *extraNodes)
{
    ClRcT rc = CL_OK;
    ClAmsEntityConfigT *entityConfig = NULL;
    ClAmsSGConfigT sgConfig = {{CL_AMS_ENTITY_TYPE_ENTITY}};
    ClAmsEntityBufferT suBuffer = {0};
    ClAmsEntityBufferT nodeBuffer = {0};
    ClAmsEntityBufferT siBuffer = {0};

    if(!sgName || !extraSIs || !extraSUs || !extraNodes) return CL_AMS_RC(CL_ERR_INVALID_PARAMETER);
    *extraSIs = 0, *extraSUs = 0, *extraNodes = 0;
    rc = clAmsMgmtEntityGetConfig(gHandle, sgName, &entityConfig);
    if(rc != CL_OK)
    {
        clLogError("AMS", "MIGRATE", "SG redundancy estimate -get config returned [%#x]", rc);
        goto out;
    }
    memcpy(&sgConfig, entityConfig, sizeof(sgConfig));
    clHeapFree(entityConfig);

    if(sgConfig.numPrefActiveSUs < numActiveSUs)
    {
        rc = clAmsMgmtGetSGSIList(gHandle, sgName, &siBuffer);
        if(rc != CL_OK)
        {
            clLogError("AMS", "MIGRATE", "AMS sg si list returned [%#x]", rc);
            goto out_free;
        }
        if(siBuffer.count < numActiveSUs)
        {
            *extraSIs = numActiveSUs - siBuffer.count;
        }
    }
    rc = clAmsMgmtGetSGSUList(gHandle, sgName, &suBuffer);
    if(rc != CL_OK)
    {
        clLogError("AMS", "MIGRATE", "AMS sg su list returned [%#x]", rc);
        goto out_free;
    }
    if(suBuffer.count < numStandbySUs + numActiveSUs)
    {
        *extraSUs = (numStandbySUs + numActiveSUs)-suBuffer.count;
        *extraSIs *= sgConfig.maxActiveSIsPerSU;
        rc = clAmsMgmtGetNodeList(gHandle, &nodeBuffer);
        if(rc != CL_OK)
        {
            clLogError("AMS", "MIGRATE", "AMS get node list returned [%#x]", rc);
            goto out_free;
        }
        if(nodeBuffer.count < numActiveSUs + numStandbySUs)
        {
            *extraNodes = (numActiveSUs + numStandbySUs) - nodeBuffer.count;
        }
    }

    rc = CL_OK;

    out_free:
    if(suBuffer.entity) clHeapFree(suBuffer.entity);
    if(nodeBuffer.entity) clHeapFree(nodeBuffer.entity);
    if(siBuffer.entity) clHeapFree(siBuffer.entity);

    out:
    return rc;
}
static ClRcT clAmsMgmtSGMigrateMPlusN(ClAmsSGRedundancyModelT model,
                                      ClAmsEntityT *sgName,
                                      const ClCharT *prefix,
                                      ClUint32T numActiveSUs,
                                      ClUint32T numStandbySUs,
                                      ClAmsMgmtMigrateListT *migrateList)
{
    ClUint32T i;
    ClRcT rc = CL_OK;
    ClAmsEntityBufferT siBuffer = {0};
    ClAmsEntityBufferT suBuffer = {0};
    ClAmsEntityBufferT nodeBuffer = {0};
    ClInt32T extraSIs = 0;
    ClInt32T extraSUs = 0;
    ClInt32T extraNodes = 0;
    ClAmsEntityT *nodeList = NULL;
    ClAmsEntityT *nodes = NULL;
    ClAmsEntityT *sus = NULL;
    ClAmsEntityT *comps = NULL;
    ClAmsEntityT *sis =  NULL;
    ClAmsEntityT *csis = NULL;
    ClInt32T numNodes = 0;
    ClAmsEntityConfigT *pSURefComp = NULL;
    ClAmsEntityConfigT *pSGRefSI = NULL;
    ClAmsEntityConfigT *pSIRefCSI = NULL;
    ClAmsEntityConfigT *pSGConfig = NULL;
    ClAmsSGConfigT sgConfig = {{CL_AMS_ENTITY_TYPE_ENTITY}};
    ClUint32T numSupportedCSITypes = 0;
    SaNameT *pNumSupportedCSITypes = NULL;
    ClAmsMgmtCCBHandleT ccbHandle = 0;
    ClAmsMgmtMigrateListT *unlockList = NULL;

    rc = clAmsMgmtEntityGetConfig(gHandle, sgName, &pSGConfig);
    if(rc != CL_OK)
    {
        clLogError("AMS", "MIGRATE", "SG [%.*s] config get returned [%#x]",
                   sgName->name.length-1, sgName->name.value, rc);
        goto out;
    }

    memcpy(&sgConfig, pSGConfig, sizeof(sgConfig));
    clHeapFree(pSGConfig);

    /*
     * If scaling down actives, ensure that those many service units are locked.
     */
    if(numActiveSUs < sgConfig.numPrefActiveSUs)
    {
        ClInt32T numShrinkSUs = sgConfig.numPrefActiveSUs - numActiveSUs;
        ClAmsEntityBufferT suList = {0};
        ClInt32T numOutOfServiceSUs = 0;
        rc = clAmsMgmtGetSGSUList(gHandle, sgName, &suList);
        if(rc != CL_OK)
        {
            clLogError("AMS", "MIGRATE", "SG [%.*s] su list returned [%#x]",
                       sgName->name.length-1, sgName->name.value, rc);
            goto out;
        }
        for(i = 0; i < suList.count; ++i)
        {
            ClAmsSUConfigT *pSUConfig = NULL;
            rc = clAmsMgmtEntityGetConfig(gHandle, suList.entity+i,
                                          (ClAmsEntityConfigT**)&pSUConfig);
            if(rc != CL_OK)
            {
                clHeapFree(suList.entity);
                clLogError("AMS", "MIGRATE", "SU [%.*s] get config returned [%#x]",
                           suList.entity[i].name.length-1, suList.entity[i].name.value, rc);
                goto out;
            }
            if(pSUConfig->adminState == CL_AMS_ADMIN_STATE_LOCKED_A
               ||
               pSUConfig->adminState == CL_AMS_ADMIN_STATE_LOCKED_I)
            {
                ++numOutOfServiceSUs;
            }
            clHeapFree(pSUConfig);
        }
        clHeapFree(suList.entity);
        if(numOutOfServiceSUs < numShrinkSUs)
        {
            clLogError("AMS", "MIGRATE", "Expected a minimum of [%d] SUs to be out of service to satisfy SG. "
                       "redundancy model shrink. Got [%d] out of service", numShrinkSUs,
                       numOutOfServiceSUs);
            rc = CL_AMS_RC(CL_AMS_ERR_INVALID_ENTITY_STATE);
            goto out;
        }
    }

    rc = clAmsMgmtSGRedundancyModelEstimate(model, sgName, numActiveSUs, numStandbySUs,
                                            &extraSIs, &extraSUs, &extraNodes);

    if(rc != CL_OK)
    {
        goto out;
    }
    
    rc = clAmsMgmtCCBInitialize(gHandle, &ccbHandle);
    if(rc != CL_OK)
    {
        clLogError("AMS", "MIGRATE", "AMS ccb initialize returned [%#x]", rc);
        goto out;
    }

    /* 
     * Add the existing SI CSI list to the supported list.
     */
    rc = clAmsMgmtGetSGSIList(gHandle, sgName, &siBuffer);
    if(rc != CL_OK)
    {
        clLogError("AMS", "MIGRATE", "AMS sg si list returned [%#x]", rc);
        goto out;
    }

    if(siBuffer.count)
    {
        rc = clAmsMgmtEntityGetConfig(gHandle, siBuffer.entity,
                                      &pSGRefSI);
        if(rc != CL_OK)
        {
            clLogError("AMS", "MIGRATE", "AMS reference si get config returned [%#x]",
                       rc);
            goto out_free;
        }
    }

    for(i = 0; i < siBuffer.count; ++i)
    {
        ClUint32T j; 
        ClAmsEntityBufferT csiBuffer = {CL_AMS_ENTITY_TYPE_ENTITY};
        ClAmsSIConfigT siConfig = {{CL_AMS_ENTITY_TYPE_ENTITY}};
        ClUint64T mask = 0;
        memcpy(&siConfig.entity, siBuffer.entity+i, 
               sizeof(siConfig.entity));
        mask |= SI_CONFIG_NUM_STANDBY_ASSIGNMENTS;
        siConfig.numStandbyAssignments = numStandbySUs;
        if(numActiveSUs > 1)
            siConfig.numStandbyAssignments = (numStandbySUs+1)&~1;
        siConfig.numStandbyAssignments = CL_MAX(1, siConfig.numStandbyAssignments/
                                                (numActiveSUs?numActiveSUs:1));
        /*
         * Update the num standby assignments.
         */
        rc = clAmsMgmtCCBEntitySetConfig(ccbHandle, &siConfig.entity, mask);
        if(rc != CL_OK)
        {
            clLogError("AMS", "MIGRATE", "SI [%.*s] num standby set returned [%#x]",
                       siConfig.entity.name.length-1, siConfig.entity.name.value, rc);
        }

        rc = clAmsMgmtGetSICSIList(gHandle, siBuffer.entity+i,
                                   &csiBuffer);
        if(rc != CL_OK)
        {
            clLogError("AMS", "MIGRATE", "AMS get si csi list returned [%#x]", rc);
            goto out_free;
        }
        pNumSupportedCSITypes = (SaNameT*) clHeapRealloc(pNumSupportedCSITypes, (numSupportedCSITypes+csiBuffer.count)*sizeof(SaNameT));
        for(j = 0; j < csiBuffer.count ; ++j)
        {
            ClAmsEntityConfigT *entityConfig = NULL;
            ClAmsCSIConfigT csiConfig = {{CL_AMS_ENTITY_TYPE_ENTITY}};
            ClUint32T k;

            rc = clAmsMgmtEntityGetConfig(gHandle, csiBuffer.entity+j, &entityConfig);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "AMS csi get config returned [%#x]", rc);
                goto out_free;
            }
            memcpy(&csiConfig, entityConfig, sizeof(csiConfig));
            if(!pSIRefCSI)
            {
                pSIRefCSI = entityConfig;
            }
            else
            {
                clHeapFree(entityConfig);
            }
            /*
             * Search for this csi type in the list to see if its 
             * already present
             */
            for(k = 0; k < numSupportedCSITypes; ++k)
            {
                if(!memcmp(pNumSupportedCSITypes[k].value,
                           csiConfig.type.value,
                           pNumSupportedCSITypes[k].length))
                    break;
            }

            if(k == numSupportedCSITypes)
            {
                memcpy(pNumSupportedCSITypes+numSupportedCSITypes,
                       &csiConfig.type, sizeof(csiConfig.type));
                ++numSupportedCSITypes;
            }
        }

        clHeapFree(csiBuffer.entity);
    }
    
    if(extraSIs)
    {
        sis = (ClAmsEntityT*) clHeapCalloc(extraSIs, sizeof(ClAmsEntityT));
        CL_ASSERT(sis != NULL);
        csis = (ClAmsEntityT*) clHeapCalloc(extraSIs, sizeof(ClAmsEntityT));
        for(i = siBuffer.count; i < siBuffer.count + extraSIs; ++i)
        {
            ClAmsEntityT si ={CL_AMS_ENTITY_TYPE_ENTITY};
            ClAmsEntityT csi = {CL_AMS_ENTITY_TYPE_ENTITY};
            ClUint64T bitMask = 0;
            ClAmsSIConfigT siConfig = {{CL_AMS_ENTITY_TYPE_ENTITY}};
            ClAmsCSIConfigT csiConfig = {{CL_AMS_ENTITY_TYPE_ENTITY}};
            si.type = CL_AMS_ENTITY_TYPE_SI;
            snprintf((ClCharT*)si.name.value, sizeof(si.name.value)-1, "%s_%.*s_SI%d", prefix,
                     sgName->name.length-1, (const ClCharT*)sgName->name.value, i);
            clLogNotice("AMS", "MIGRATE", "Creating SI [%s]", si.name.value);
            si.name.length = strlen((const ClCharT*)si.name.value)+1;
            rc = clAmsMgmtCCBEntityCreate(ccbHandle, &si);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "AMS entity create returned [%#x]", rc);
                goto out_free;
            }
            memcpy(&sis[i-siBuffer.count], &si, sizeof(si));
            
            rc = clAmsMgmtCCBSetSGSIList(ccbHandle, sgName, &si);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "AMS set sg silist returned [%#x]", rc);
                goto out_free;
            }

            if(pSGRefSI)
            {
                /*
                 * Set config to the base SI.
                 */
                bitMask = CL_AMS_CONFIG_ATTR_ALL;
                memcpy(&siConfig, pSGRefSI, sizeof(siConfig));
                memcpy(&siConfig.entity, &si, sizeof(siConfig.entity));
                siConfig.numStandbyAssignments = numStandbySUs;
                if(numActiveSUs > 1 )
                    siConfig.numStandbyAssignments = (numStandbySUs+1)&~1;
                siConfig.numStandbyAssignments = CL_MAX(1,siConfig.numStandbyAssignments/
                                                        (numActiveSUs?numActiveSUs:1));
                siConfig.numCSIs = 1;
                siConfig.adminState = CL_AMS_ADMIN_STATE_LOCKED_A;
                rc = clAmsMgmtCCBEntitySetConfig(ccbHandle, &siConfig.entity, bitMask);
                if(rc != CL_OK)
                {
                    clLogError("AMS", "MIGRATE", "AMS entity set config returned [%#x]", rc);
                    goto out_free;
                }
            }

            csi.type = CL_AMS_ENTITY_TYPE_CSI;
            snprintf((ClCharT*)csi.name.value, sizeof(csi.name.value),
                     "%s_CSI%d", (const ClCharT*)si.name.value, i-siBuffer.count);
            csi.name.length = strlen((const ClCharT*)csi.name.value)+1;
            clLogNotice("AMS", "MIGRATE", "Creating CSI [%s]", csi.name.value);
            rc = clAmsMgmtCCBEntityCreate(ccbHandle, &csi);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "AMS csi create returned [%#x]", rc);
                goto out_free;
            }
            memcpy(&csis[i-siBuffer.count], &csi, sizeof(csi));
            rc = clAmsMgmtCCBSetSICSIList(ccbHandle, &si, &csi);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "SET si csi list returned [%#x]", rc);
                goto out_free;
            }
            
            if(pSIRefCSI)
            {
                /*
                 * Load the config. for the base csi type.
                 */
                memcpy(&csiConfig, pSIRefCSI, sizeof(csiConfig));
                memcpy(&csiConfig.entity, &csi, sizeof(csiConfig.entity));
                csiConfig.isProxyCSI = CL_FALSE;
                memcpy(&csiConfig.type, &csiConfig.entity.name, sizeof(csiConfig.type));
                bitMask = CL_AMS_CONFIG_ATTR_ALL;
                rc = clAmsMgmtCCBEntitySetConfig(ccbHandle, &csiConfig.entity, bitMask);
                if(rc != CL_OK)
                {
                    clLogError("AMS", "MIGRATE", "AMS ref csi set config returned [%#x]", rc);
                    goto out_free;
                }
            }
            /*
             * Add this to the supported list.
             */
            pNumSupportedCSITypes = (SaNameT*) clHeapRealloc(pNumSupportedCSITypes, (numSupportedCSITypes+1)*sizeof(SaNameT));
            CL_ASSERT(pNumSupportedCSITypes != NULL);
            memcpy(pNumSupportedCSITypes+numSupportedCSITypes, &csi.name, sizeof(SaNameT));
            ++numSupportedCSITypes;
        }
    }

    if(extraNodes)
    {
        nodes = (ClAmsEntityT*) clHeapCalloc(extraNodes, sizeof(ClAmsEntityT));
        CL_ASSERT(nodes != NULL);

        rc = clAmsMgmtGetNodeList(gHandle, &nodeBuffer);
        if(rc != CL_OK)
        {
            clLogError("AMS", "MIGRATE", "AMS get node list returned [%#x]", rc);
            goto out_free;
        }
        for(i = nodeBuffer.count ; i < nodeBuffer.count + extraNodes; ++i)
        {
            ClAmsEntityT node = {CL_AMS_ENTITY_TYPE_ENTITY};
            node.type = CL_AMS_ENTITY_TYPE_NODE;
            snprintf((ClCharT*) node.name.value, sizeof(node.name.value), "%s_Node%d", prefix, i);
            node.name.length = strlen((const ClCharT*) node.name.value) + 1;
            clLogNotice("AMS", "MIGRATE", "Creating node [%s]", node.name.value);
            rc = clAmsMgmtCCBEntityCreate(ccbHandle, &node);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "AMS ccb create returned [%#x]", rc);
                goto out_free;
            }
            memcpy(&nodes[i-nodeBuffer.count], &node, sizeof(node));
        }
    }

    rc = clAmsMgmtGetSGSUList(gHandle, sgName, &suBuffer);
    if(rc != CL_OK)
    {
        clLogError("AMS", "MIGRATE", "Get SG su list returned [%#x]", rc);
        goto out_free;
    }

    for(i = 0 ; i < suBuffer.count; ++i)
    {
        ClUint32T j;
        ClAmsEntityBufferT compBuffer=
            {
                0
            }
        ;
        rc = clAmsMgmtGetSUCompList(gHandle, &suBuffer.entity[i],
                                    &compBuffer);
        if(rc != CL_OK)
        {
            clLogError("AMS", "MIGRATE", "Get SU comp list returned [%#x]", rc);
            goto out_free;
        }
        /*
         * Get the first component properties.
         */
        if(!pSURefComp)
        {
            rc = clAmsMgmtEntityGetConfig(gHandle, compBuffer.entity,
                                          &pSURefComp);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "AMS base comp get config returned [%#x]",
                           rc);
                goto out_free;
            }
        }

        /*
         * Update all config. with supported csi types.
         * and correct comp config whereever appropriate
         */
        for(j = 0; j < compBuffer.count; ++j)
        {
            ClAmsEntityConfigT *entityConfig =NULL;
            ClAmsCompConfigT compConfig = {{CL_AMS_ENTITY_TYPE_ENTITY}};
            ClUint64T bitMask = 0;
            ClUint32T k ;
            rc = clAmsMgmtEntityGetConfig(gHandle, compBuffer.entity+j,
                                          &entityConfig);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "AMS comp get config returned [%#x]", rc);
                goto out_free;
            }
            memcpy(&compConfig, entityConfig, sizeof(compConfig));
            clHeapFree(entityConfig);
            /*
             * update supported CSI type incase of SI additions.
             */
            if(extraSIs)
            {
                bitMask |= COMP_CONFIG_SUPPORTED_CSI_TYPE;
                compConfig.pSupportedCSITypes = (SaNameT*) clHeapRealloc(compConfig.pSupportedCSITypes, (compConfig.numSupportedCSITypes + extraSIs)* sizeof(SaNameT));
                CL_ASSERT(compConfig.pSupportedCSITypes);
                for(k = compConfig.numSupportedCSITypes; k < compConfig.numSupportedCSITypes + extraSIs; ++k)
                {
                    memcpy(compConfig.pSupportedCSITypes+k, &csis[k-compConfig.numSupportedCSITypes].name, sizeof(SaNameT));
                }
                compConfig.numSupportedCSITypes += extraSIs;
            }
            bitMask |= COMP_CONFIG_NUM_MAX_STANDBY_CSIS;
            /*
             * take active to standby ratio
             */
            compConfig.numMaxStandbyCSIs = numActiveSUs;
            if(numStandbySUs > 1 )
                compConfig.numMaxStandbyCSIs = (numActiveSUs+1)&~1;
            compConfig.numMaxStandbyCSIs = CL_MAX(1, compConfig.numMaxStandbyCSIs/
                                                  (numStandbySUs?numStandbySUs:1));
            rc = clAmsMgmtCCBEntitySetConfig(ccbHandle,
                                             &compConfig.entity,
                                             bitMask);
            clHeapFree(compConfig.pSupportedCSITypes);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "AMS entity set config returned [%#x]", rc);
                goto out_free;
            }
        }
        clHeapFree(compBuffer.entity);
    }

    if(extraSUs)
    {
        sus = (ClAmsEntityT*) clHeapCalloc(extraSUs, sizeof(ClAmsEntityT));
        CL_ASSERT(sus != NULL);
        comps = (ClAmsEntityT*) clHeapCalloc(extraSUs, sizeof(ClAmsEntityT));
        CL_ASSERT(comps != NULL);
        nodeList = (ClAmsEntityT*) clHeapCalloc(extraSUs + extraNodes, sizeof(ClAmsEntityT));
        CL_ASSERT(nodeList != NULL);

        rc = clAmsMgmtGetSUFreeNodes(sgName, prefix, extraSUs, extraNodes, nodeList, &numNodes);

        for(i = suBuffer.count; i < suBuffer.count + extraSUs; ++i)
        {
            ClAmsEntityT su = {CL_AMS_ENTITY_TYPE_ENTITY};
            ClAmsEntityT comp = {CL_AMS_ENTITY_TYPE_ENTITY};
            ClAmsSUConfigT suConfig = 
                {
                    {
                       CL_AMS_ENTITY_TYPE_ENTITY
                    }
                }
            ;
            ClAmsCompConfigT compConfig = {{CL_AMS_ENTITY_TYPE_ENTITY}};
            ClUint64T bitMask = 0;

            su.type = CL_AMS_ENTITY_TYPE_SU;
            snprintf((ClCharT*)su.name.value, sizeof(su.name.value),
                     "%s_%s_SU%d", prefix, (const ClCharT*)nodeList[i-suBuffer.count].name.value, i);

            su.name.length = strlen((const ClCharT*)su.name.value)+1;
            clLogNotice("AMS", "MIGRATE", "Creating SU [%s]", su.name.value);
            rc = clAmsMgmtCCBEntityCreate(ccbHandle, &su);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "SU create returned [%#x]", rc);
                goto out_free;
            }
            memcpy(&sus[i-suBuffer.count], &su, sizeof(su));
            /*
             * Assign this SU under the parent node and SG
             */
            rc = clAmsMgmtCCBSetNodeSUList(ccbHandle, &nodeList[i-suBuffer.count], &su);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "Node su list set returned [%#x]", rc);
                goto out_free;
            }

            /*
             * Give the parent SG. for this SU
             */
            rc = clAmsMgmtCCBSetSGSUList(ccbHandle, sgName, &su);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "Set SG su list returned [%#x]", rc);
                goto out_free;
            }
            bitMask = SU_CONFIG_NUM_COMPONENTS;
            memcpy(&suConfig.entity, &su, sizeof(suConfig.entity));
            suConfig.numComponents = 1;
            rc = clAmsMgmtCCBEntitySetConfig(ccbHandle, &suConfig.entity, bitMask);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "SU set config returned [%#x]", rc);
                goto out_free;
            }
            
            comp.type = CL_AMS_ENTITY_TYPE_COMP;
            snprintf((ClCharT*) comp.name.value, sizeof(comp.name.value), "%s_Comp%d", su.name.value, i - suBuffer.count);
            comp.name.length = strlen((const ClCharT*) comp.name.value) + 1;
            clLogNotice("AMS", "MIGRATE", "Creating component [%s]",
                        comp.name.value);
            rc = clAmsMgmtCCBEntityCreate(ccbHandle, &comp);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "Comp create returned [%#x]", rc);
                goto out_free;
            }
            memcpy(&comps[i-suBuffer.count], &comp, sizeof(comp));
            rc = clAmsMgmtCCBSetSUCompList(ccbHandle, &su, 
                                           &comp);
            if(rc != CL_OK)
            {
                clLogError("AMS", "MIGRATE", "AMS set su comp list returned [%#x]", rc);
                goto out_free;
            }
            
            if(pSURefComp)
            {
                /*
                 * At this stage, we have created the hierarchy. 
                 * Set the comp property to the base component type and
                 * add the num supported CSI types to be part of every component
                 * added to the SU.
                 */

                bitMask = CL_AMS_CONFIG_ATTR_ALL;
                memcpy(&compConfig, pSURefComp, sizeof(compConfig));
                memcpy(&compConfig.entity, &comp, sizeof(compConfig.entity));
                compConfig.numSupportedCSITypes = numSupportedCSITypes;
                compConfig.pSupportedCSITypes = pNumSupportedCSITypes;
                memcpy(&compConfig.parentSU.entity, &su, sizeof(compConfig.parentSU.entity));
                
                /*
                 * Distribute the standbys based on the active/standby ratio.
                 */
                compConfig.numMaxStandbyCSIs = numActiveSUs;
                if(numStandbySUs > 1 )
                    compConfig.numMaxStandbyCSIs = (numActiveSUs+1)&~1;
                compConfig.numMaxStandbyCSIs = CL_MAX(1, compConfig.numMaxStandbyCSIs/
                                                      (numStandbySUs?numStandbySUs:1));
                rc = clAmsMgmtCCBEntitySetConfig(ccbHandle, &compConfig.entity,
                                                 bitMask);
                if(rc != CL_OK)
                {
                    clLogError("AMS", "MIGRATE", "AMS set config returned [%#x]", rc);
                    goto out_free;
                }
            }
        }
    }

    /*
     * At this stage, we are all set to commit. after updating SG config.
     */
    {
        ClUint64T bitMask = 0;
        bitMask |= SG_CONFIG_REDUNDANCY_MODEL;
        sgConfig.redundancyModel = model;
        sgConfig.numPrefActiveSUs = numActiveSUs;
        bitMask |= SG_CONFIG_NUM_PREF_ACTIVE_SUS;
        sgConfig.numPrefStandbySUs = numStandbySUs;
        bitMask |= SG_CONFIG_NUM_PREF_STANDBY_SUS;
        if(sgConfig.numPrefInserviceSUs < numActiveSUs + numStandbySUs)
        {
            sgConfig.numPrefInserviceSUs = numActiveSUs + numStandbySUs;
            bitMask |= SG_CONFIG_NUM_PREF_INSERVICE_SUS;
        }
        sgConfig.numPrefAssignedSUs = numActiveSUs + numStandbySUs;
        bitMask |= SG_CONFIG_NUM_PREF_ASSIGNED_SUS;
        /*
         * Active standby ratio.
         */
        sgConfig.maxStandbySIsPerSU = numActiveSUs;
        if(numStandbySUs > 1 )
            sgConfig.maxStandbySIsPerSU = (numActiveSUs+1)&~1;
        sgConfig.maxStandbySIsPerSU = CL_MAX(1,sgConfig.maxStandbySIsPerSU/
                                             (numStandbySUs?numStandbySUs:1));
        bitMask |= SG_CONFIG_MAX_STANDBY_SIS_PER_SU;
        rc = clAmsMgmtCCBEntitySetConfig(ccbHandle, &sgConfig.entity, bitMask);
        if(rc != CL_OK)
        {
            clLogError("AMS", "MIGRATE", "AMS sg set config returned [%#x]", rc);
            goto out_free;
        }
    }

    rc = clAmsMgmtCCBCommit(ccbHandle);
    if(rc != CL_OK)
    {
        clLogError("AMS", "MIGRATE", "AMS database commit returned [%#x]", rc);
    }

    /*
     * Okay, the commit is successful. Now unlock all added entities
     * except SU so that other attributes could be updated before unlocking
     * Do that in a separate thread as there could be pending invocations.
     */
    unlockList = (ClAmsMgmtMigrateListT*) clHeapCalloc(1, sizeof(*unlockList));
    CL_ASSERT(unlockList != NULL);
    unlockList->si.count = extraSIs;
    unlockList->node.count = extraNodes;
    unlockList->su.count = extraSUs;
                                                
    unlockList->si.entity = (ClAmsEntityT*) clHeapCalloc(extraSIs, sizeof(*sis));
    unlockList->node.entity = (ClAmsEntityT*) clHeapCalloc(extraNodes, sizeof(*nodes));
    unlockList->su.entity = (ClAmsEntityT*) clHeapCalloc(extraSUs, sizeof(*sus));

    CL_ASSERT(unlockList->si.entity && unlockList->node.entity && unlockList->su.entity);

    memcpy(unlockList->si.entity, sis, sizeof(*sis)*extraSIs);
    memcpy(unlockList->node.entity, nodes, sizeof(*nodes)*extraNodes);
    memcpy(unlockList->su.entity, sus, sizeof(*sus) * extraSUs);

    clOsalTaskCreateDetached("MIGRATE-UNLOCK-THREAD", CL_OSAL_SCHED_OTHER, 0, 0, 
                             clAmsMgmtMigrateListUnlock, (void*)unlockList);

    /*
     * Return the newly created info. in the migrated list.
     */
    if(migrateList)
    {
        if(extraSIs)
        {
            migrateList->si.count = extraSIs;
            migrateList->si.entity = sis;
            migrateList->csi.count = extraSIs;
            migrateList->csi.entity = csis;
            sis = csis = NULL;
        }

        if(extraNodes)
        {
            migrateList->node.count = extraNodes;
            migrateList->node.entity = nodes;
            nodes = NULL;
        }

        if(extraSUs)
        {
            migrateList->su.count = extraSUs;
            migrateList->su.entity = sus;
            migrateList->comp.count = extraSUs;
            migrateList->comp.entity = comps;
            sus = comps = NULL;
        }
    }

    out_free:

    clAmsMgmtCCBFinalize(ccbHandle);

    if(siBuffer.entity) clHeapFree(siBuffer.entity);
    if(nodeBuffer.entity) clHeapFree(nodeBuffer.entity);
    if(suBuffer.entity) clHeapFree(suBuffer.entity);
    if(nodeList) clHeapFree(nodeList);
    if(nodes) clHeapFree(nodes);
    if(sus) clHeapFree(sus);
    if(comps) clHeapFree(comps);
    if(sis) clHeapFree(sis);
    if(csis) clHeapFree(csis);
    if(pSGRefSI) clHeapFree(pSGRefSI);
    if(pSIRefCSI) clHeapFree(pSIRefCSI);
    if(pSURefComp) clHeapFree(pSURefComp);
    if(pNumSupportedCSITypes) clHeapFree(pNumSupportedCSITypes);

    out:
    return rc;
}
static ClRcT clAmsMgmtSGRedundancyModelNoRedundancy(ClAmsSGRedundancyModelT model,
                                                    const ClCharT *sg,
                                                    const ClCharT *prefix,
                                                    ClUint32T numActiveSUs,
                                                    ClUint32T numStandbySUs,
                                                    ClAmsMgmtMigrateListT *migrateList)
{
    ClAmsSGConfigT sgConfig = {{CL_AMS_ENTITY_TYPE_ENTITY}};
    ClAmsEntityConfigT *entityConfig = NULL;
    ClRcT rc = CL_OK;
    ClAmsEntityT sgName = {CL_AMS_ENTITY_TYPE_ENTITY};
    ClUint64T bitMask = 0;

    sgName.type = CL_AMS_ENTITY_TYPE_SG;
    saNameSet(&sgName.name, sg);
    ++sgName.name.length;
    rc = clAmsMgmtEntityGetConfig(gHandle, &sgName, &entityConfig);
    if(rc != CL_OK)
    {
        clLogError("AMS", "MIGRATE", "AMS entity get config returned [%#x]", rc);
        goto out;
    }

    memcpy(&sgConfig, entityConfig, sizeof(sgConfig));
    clHeapFree(entityConfig);

    if(sgConfig.redundancyModel == CL_AMS_SG_REDUNDANCY_MODEL_NONE)
    {
        clLogWarning("AMS", "MIGRATE", "Redundancy model is already no redundancy");
        goto out;
    }

    bitMask |= SG_CONFIG_REDUNDANCY_MODEL;
    sgConfig.redundancyModel = CL_AMS_SG_REDUNDANCY_MODEL_NONE;

    bitMask |= SG_CONFIG_NUM_PREF_ACTIVE_SUS_PER_SI;
    sgConfig.numPrefActiveSUsPerSI = 1;
    
    bitMask |= SG_CONFIG_NUM_PREF_ACTIVE_SUS;
    sgConfig.numPrefActiveSUs = numActiveSUs;

    bitMask |= SG_CONFIG_NUM_PREF_STANDBY_SUS;
    sgConfig.numPrefStandbySUs = numStandbySUs;
    
    bitMask |= SG_CONFIG_NUM_PREF_INSERVICE_SUS;
    sgConfig.numPrefInserviceSUs = numActiveSUs + numStandbySUs;

    bitMask |= SG_CONFIG_NUM_PREF_ASSIGNED_SUS;
    sgConfig.numPrefAssignedSUs = numActiveSUs + numStandbySUs;

    rc = clAmsMgmtCCBEntitySetConfig(gCcbHandle, &sgConfig.entity, bitMask);

    if(rc != CL_OK)
    {
        clLogError("AMS", "MIGRATE", "AMS sg set config returned [%#x]", rc);
        goto out;
    }

    rc = clAmsMgmtCCBCommit(gCcbHandle);

    if(rc != CL_OK)
    {
        clLogError("AMS", "MIGRATE", "AMS database commit returned [%#x]", rc);
        goto out;
    }

    out:
    return rc;
}
static ClRcT clAmsMgmtGetSUFreeNodes(ClAmsEntityT *sgName,
                                     const ClCharT *prefix,
                                     ClInt32T extraSUs,
                                     ClInt32T extraNodes,
                                     ClAmsEntityT *nodes,
                                     ClInt32T *pNumNodes)
{
    ClRcT rc = CL_OK;
    ClUint32T i;
    ClAmsEntityBufferT suBuffer = {0};
    ClAmsEntityBufferT nodeBuffer = {0};
    ClAmsEntityT *nodeList = NULL;
    ClAmsEntityConfigT *entityConfig = NULL;
    ClAmsSUConfigT suConfig = {{CL_AMS_ENTITY_TYPE_ENTITY}};
    ClAmsEntityT *controllers = NULL;
    ClAmsEntityT *workers = NULL;
    ClUint32T numControllers = 0;
    ClUint32T numWorkers = 0;
    ClUint32T totalNodes = 0;

    if(!nodes || !pNumNodes)
        return CL_AMS_RC(CL_ERR_INVALID_PARAMETER);

    if(!extraSUs) return rc;

    *pNumNodes = 0;

    rc = clAmsMgmtGetNodeList(gHandle, &nodeBuffer);

    if(rc != CL_OK)
    {
        clLogError("AMS", "MIGRATE", "Get node list returned [%#x]", rc);
        goto out;
    }        

    /*
     * First try distributing to the extra nodes.
     */
    if(extraNodes > 0)
    {
        for(i = nodeBuffer.count; i < nodeBuffer.count + extraNodes; ++i)
        {
            nodes[i - nodeBuffer.count].type= CL_AMS_ENTITY_TYPE_NODE;
            snprintf((ClCharT*)nodes[i-nodeBuffer.count].name.value, sizeof(nodes[i-nodeBuffer.count].name.value),
                     "%s_Node%d", prefix, i);
            nodes[i-nodeBuffer.count].name.length = strlen((const ClCharT*)nodes[i-nodeBuffer.count].name.value)+1;
            nodes[i-nodeBuffer.count].debugFlags = 1;
        }
        *pNumNodes = extraNodes;
    }

    if(extraSUs <= extraNodes) 
    {
        clHeapFree(nodeBuffer.entity);
        return CL_OK;
    }

    controllers = (ClAmsEntityT*) clHeapCalloc(nodeBuffer.count, sizeof(*controllers));
    workers = (ClAmsEntityT*) clHeapCalloc(nodeBuffer.count, sizeof(*controllers));
    CL_ASSERT(controllers && workers);

    /*
     * Separate controllers and workers as node distribution preference is
     * higher for workers than controllers.
     */
    clOsalMutexLock(gpClCpm->cpmTableMutex);
    for(i = 0 ; i < nodeBuffer.count; ++i)
    {
        ClCpmLT *cpmL = NULL;
        rc = cpmNodeFindLocked(nodeBuffer.entity[i].name.value, &cpmL);
        if(rc != CL_OK)
        {
            /*
             * We skip the controller and worker ordering.
             */
            if(controllers)
            {
                clHeapFree(controllers);
            }
            if(workers)
            {
                clHeapFree(workers);
            }
            controllers = nodeBuffer.entity;
            numControllers = nodeBuffer.count;
            break;
        }
        if(!strcmp(cpmL->classType, "CL_AMS_NODE_CLASS_C"))
        {
            memcpy(workers+numWorkers, nodeBuffer.entity+i, 
                   sizeof(*workers));
            ++numWorkers;
        }
        else
        {
            memcpy(controllers+numControllers, nodeBuffer.entity+i,
                   sizeof(*controllers));
            ++numControllers;
        }
    }
    clOsalMutexUnlock(gpClCpm->cpmTableMutex);

    nodeList = (ClAmsEntityT*) clHeapCalloc(nodeBuffer.count + extraNodes, sizeof(ClAmsEntityT));
    CL_ASSERT(nodeList);
    
    memcpy(nodeList, nodes, sizeof(*nodes)*extraNodes);
    if(workers)
    {
        memcpy(nodeList + extraNodes, workers, 
               sizeof(*workers) * numWorkers);
        clHeapFree(workers);
    }
    if(controllers)
    {
        memcpy(nodeList + extraNodes + numWorkers, controllers,
               sizeof(*controllers) * numControllers);
        clHeapFree(controllers);
    }

    clHeapFree(nodeBuffer.entity);
    extraSUs -= extraNodes;

    for(i = 0; i < (ClUint32T) extraNodes; ++i)
        nodeList[i].debugFlags = 1;

    for(; i < nodeBuffer.count + extraNodes; ++i)
        nodeList[i].debugFlags = 0;
    
    /*
     * Now find nodes that are unmapped to the SUs of this SG
     */
    rc = clAmsMgmtGetSGSUList(gHandle, sgName, &suBuffer);
    if(rc != CL_OK)
    {
        clLogError("AMS", "MIGRATE", "SG su list returned [%#x]", rc);
        goto out_free;
    }

    for(i = 0; i < suBuffer.count; ++i)
    {
        ClUint32T j;
        rc = clAmsMgmtEntityGetConfig(gHandle, suBuffer.entity+i,
                                      &entityConfig);
        if(rc != CL_OK)
        {
            clLogError("AMS", "MIGRATE", "SU get config returned [%#x]", rc);
            goto out_free;
        }
        memcpy(&suConfig, entityConfig, sizeof(suConfig));
        clHeapFree(entityConfig);
        for(j = 0; j < nodeBuffer.count+extraNodes; ++j)
        {
            if(!strncmp((const ClCharT*)nodeList[j].name.value, (const ClCharT*)suConfig.parentNode.entity.name.value,
                        nodeList[j].name.length-1))
            {
                /*
                 * Mark this entry as seen.
                 */
                nodeList[j].debugFlags = 1;
            }
        }
    }

    clLogInfo("AMS", "MIGRATE", "Scanning free node list");
    totalNodes = nodeBuffer.count + extraNodes;
    for(i = 0; (i < totalNodes) && extraSUs ; ++i)
    {
        if(!nodeList[i].debugFlags)
        {
            clLogInfo("AMS", "MIGRATE", "Copying node [%s]", nodeList[i].name.value);
            memcpy(nodes + extraNodes, nodeList+i, sizeof(ClAmsEntityT));
            ++extraNodes;
            --extraSUs;
        }
    }

    /*
     * Distribute the remaining cyclically.
     */
    if(extraSUs && extraNodes)
    {
        ClInt32T index = 0;
        ClInt32T currentNodes = extraNodes;
        while(extraSUs--)
        {
            memcpy(nodes+extraNodes, nodes+index, sizeof(ClAmsEntityT));
            ++index;
            index %= currentNodes;
            ++extraNodes;
        }
    }

    *pNumNodes = extraNodes;
    rc = CL_OK;

    out_free:
    if(suBuffer.entity) clHeapFree(suBuffer.entity);
    if(nodeList) clHeapFree(nodeList);
    
    out:
    return rc;
}                                     
static ClRcT clAmsCSIRecovery(ClAmsEntityT *pEntity,
                              ClAmsThresholdT *pThreshold)
{
    ClRcT rc= CL_OK;
    ClAmsEntityConfigT *pEntityConfig = NULL;
    ClAmsCSIConfigT *pCSIConfig = NULL;

    clLogNotice("TRIGGER", "RECOVERY", 
                "Getting CSI config for [%.*s]",
                pEntity->name.length-1, pEntity->name.value);

    rc = clAmsMgmtEntityGetConfig(gClAmsEntityTriggerMgmtHandle,
                                  pEntity, &pEntityConfig);
    if(rc != CL_OK)
    {
        clLogError("TRIGGER", "RECOVERY", 
                   "Entity get config for CSI returned [%#x]", rc);
        goto out;
    }

    pCSIConfig = (ClAmsCSIConfigT*)pEntityConfig;

    if(pThreshold->recoveryReset == CL_TRUE)
    {
        clLogNotice("RECOVERY", "RESET",
                    "Unlocking SI [%.*s]",
                    pCSIConfig->parentSI.entity.name.length-1,
                    pCSIConfig->parentSI.entity.name.value);

        rc = clAmsMgmtEntityUnlock(gClAmsEntityTriggerMgmtHandle,
                                   &pCSIConfig->parentSI.entity);

        if(rc != CL_OK)
        {
            clLogError("RECOVERY", "RESET",
                       "Unlock returned [%#x]", rc);
        }

        goto out_free;
    }

    switch(pThreshold->recovery)
    {

    case CL_AMS_ENTITY_RECOVERY_FAILOVER:
    case CL_AMS_ENTITY_RECOVERY_LOCK:
        clLogNotice("TRIGGER", "RECOVERY",
                    "Switching over work for SI [%.*s] as part of [%s] threshold recovery",
                    pCSIConfig->parentSI.entity.name.length-1,
                    pCSIConfig->parentSI.entity.name.value,
                    CL_METRIC_STR(pThreshold->metric.id));

        rc = clAmsMgmtEntityLockAssignment(gClAmsEntityTriggerMgmtHandle,
                                           &pCSIConfig->parentSI.entity);
    
        if(rc != CL_OK)
        {
            clLogError("TRIGGER", "RECOVERY",
                       "Switching over SI returned [%#x]", rc);
            goto out_free;
        }

        break;
    
    default:
        break;
    }

    out_free:
    clHeapFree(pEntityConfig);

    out:
    return rc;
}
static ClRcT clAmsCompRecovery(ClAmsEntityT *pEntity,
                               ClAmsThresholdT *pThreshold)
{
    ClAmsEntityConfigT *pEntityConfig = NULL;
    ClAmsCompConfigT *pCompConfig = NULL;
    ClRcT rc = CL_OK;

    if(pEntity->type == CL_AMS_ENTITY_TYPE_SU)
    {
        ClAmsEntityBufferT compBuffer = {0};
        rc = clAmsMgmtGetSUCompList(gClAmsEntityTriggerMgmtHandle,
                                    pEntity, &compBuffer);
        if(rc != CL_OK)
        {
            clLogError("TRIGGER", "RECOVERY",
                       "SU [%.*s] get comp list returned [%#x]",
                       pEntity->name.length-1, pEntity->name.value, rc);
            goto out;
        }
        if(!compBuffer.count)
        {
            clLogNotice("TRIGGER", "RECOVERY",
                        "SU doesnt have components. Locking SU");
            rc = clAmsMgmtEntityLockAssignment(gClAmsEntityTriggerMgmtHandle,
                                               pEntity);
            if(compBuffer.entity) clHeapFree(compBuffer.entity);
            goto out_free;
        }
        /*
         * Now overwrite the entity with first comp.
         */
        memcpy(pEntity, &compBuffer.entity[0], sizeof(*pEntity));
        clHeapFree(compBuffer.entity);
    }

    clLogNotice("TRIGGER", "RECOVERY",
                "Getting comp config for [%.*s]",
                pEntity->name.length-1, pEntity->name.value);

    rc = clAmsMgmtEntityGetConfig(gClAmsEntityTriggerMgmtHandle,
                                  pEntity, &pEntityConfig);

    if(rc != CL_OK)
    {
        clLogError("TRIGGER", "RECOVERY", 
                   "Entity get config returned [%#x]", rc);
        goto out;
    }
    pCompConfig = (ClAmsCompConfigT*)pEntityConfig;

    if(pThreshold->recoveryReset == CL_TRUE)
    {
        if(pThreshold->recovery == CL_AMS_ENTITY_RECOVERY_FAILOVER)
        {
            /*
             *Try repairing.
             */
            rc = clAmsMgmtEntityRepaired(gClAmsEntityTriggerMgmtHandle,
                                         &pCompConfig->parentSU.entity);
            if(rc != CL_OK)
            {
                clLogError("TRIGGER", "RECOVERY", 
                           "Repair didn't work. Trying lock assignment first");
                rc = clAmsMgmtEntityLockAssignment(gClAmsEntityTriggerMgmtHandle,
                                                   &pCompConfig->parentSU.entity);
                if(rc != CL_OK)
                {
                    clLogError("TRIGGER", "RECOVERY",
                               "Lockassignment didn't work. Trying unlock as a last resort");
                }
            }
        }
        
        clLogNotice("TRIGGER", "RECOVERY",
                    "Recoverying SU [%.*s] through unlock",
                    pCompConfig->parentSU.entity.name.length-1,
                    pCompConfig->parentSU.entity.name.value);

        rc = clAmsMgmtEntityUnlock(gClAmsEntityTriggerMgmtHandle,
                                   &pCompConfig->parentSU.entity);
        if(rc != CL_OK)
        {
            clLogError("TRIGGER", "RECOVERY RESET",
                       "Unlock for entity [%.*s] returned [%#x]",
                       pCompConfig->parentSU.entity.name.length-1,
                       pCompConfig->parentSU.entity.name.value, rc);
        }

        goto out_free;
    }

    switch(pThreshold->recovery)
    {
    case CL_AMS_ENTITY_RECOVERY_RESTART:

        clLogNotice("TRIGGER", "RECOVERY",
                    "Restarting comp [%.*s] as part of [%s] recovery",
                    pEntity->name.length-1, pEntity->name.value,
                    CL_METRIC_STR(pThreshold->metric.id));

        rc = clAmsMgmtEntityRestart(gClAmsEntityTriggerMgmtHandle,
                                    pEntity);
        if(rc != CL_OK)
        {
            clLogError("TRIGGER", "RECOVERY",
                       "Comp restart returned with [%#x]", rc);
            goto out_free;
        }
        break;

    case CL_AMS_ENTITY_RECOVERY_FAILOVER:
        /*
         * We trigger a fault to AMS with a recommended recovery.
         */
        clAmsTriggerFault(pEntity, CL_AMS_RECOVERY_COMP_FAILOVER);
        break;

    case CL_AMS_ENTITY_RECOVERY_LOCK:
        /*
         * Graceful lock of the SU
         */
        clLogNotice("TRIGGER", "RECOVERY",
                    "Locking work for parent SU [%.*s] as part of [%s] recovery",
                    pCompConfig->parentSU.entity.name.length-1,
                    pCompConfig->parentSU.entity.name.value,
                    CL_METRIC_STR(pThreshold->metric.id));

        rc = clAmsMgmtEntityLockAssignment(gClAmsEntityTriggerMgmtHandle,
                                           &pCompConfig->parentSU.entity);
        if(rc != CL_OK)
        {
            clLogError("TRIGGER", "RECOVERY", 
                       "SU work switchover returned [%#x]", rc);
            goto out_free;
        }
        break;

    default:
        break;
    }

    out_free:
    if(pCompConfig->pSupportedCSITypes)
        clHeapFree(pCompConfig->pSupportedCSITypes);
    
    clHeapFree(pCompConfig);

    out:
    return rc;
}