Name

sn_cmp.CMPCIRelationshipUtil

Description

No description available

Script

var CMPCIRelationshipUtil = Class.create();
CMPCIRelationshipUtil.prototype = {
  initialize: function () {
  },

  /**
  * Infers an eventual LDC on which a particular CI is hosted.
  * A general approach is to follow a bunch of HostedOn:Hosts relationships all the way from the top and locate the
  * eventual LDC. However for some CIs/Resource Blocks , this might not be the case. For example: Subnets have a
  * Contains:ContainedBy relationship with Network.
  * This script implements the general method to reach the LDC given a CI, however customizations can be made for
  * specific CIs here.
  **/
  ldcIdForConfigurationItem: function (ciId) {
      gs.info("Debugging for CI: " + ciId);
      var ldcId = this._getLDCForCI(ciId);

      //Not directly inferred - which means the CI does not have a direct 'Hosted On::Hosts'
      //relationship with a LDC.

      if (gs.nil(ldcId)) {
          var ciClassName = this.getCIClass(ciId);
          if (!gs.nil(ciClassName) && ciClassName == "cmdb_ci_cloud_subnet")
              ldcId = this._getContainedBy(ciId);

          // To deduce LDCs for specific ci types, add more else if blocks.
          // ex. else if(!gs.nil(ciClassName) && ciClassName == "cmdb_ci_compute_security_group")
      }
      return ldcId;
  },

  /**
   * Each CI shall ultimatly relates to a given serviceAccount.
   * This method traverses the hierarchy of these relationships and finds the service account.
   * @param ciId
   * @returns serviceAccountId for which this CI belongs to.
   */
  getLdcAndServiceAccount: function (ciId) {
      gs.info("Debugging for CI: " + ciId);
  	// if ciId is nil, it means discovery on service account, exiting early
  	if(gs.nil(ciId))
  		return null;
  	
      var response = this._getRelationshipGraph(ciId,false);
      gs.info('Graph :'+JSON.stringify(response));

      var result = this._buildResults(response);
      if (result!=null && result.trim() != '') {
          return result;
      } else {
          response = this._getRelationshipGraph(ciId, true);
          gs.info('Graph :'+JSON.stringify(response));
          return this._buildResults(response);
      }
  },

  /**
   * builds the results from payload containing graph. checks for SA and Ldc
   */
  _buildResults: function(payload) {
      var result = '';
      var resultObj = {};
      if (payload && payload.length > 0 && payload[payload.length - 1].type == 'cmdb_ci_cloud_service_account') {
          resultObj.serviceAccount = payload[payload.length - 1].sys_id;
          //last but one is LDC
          if (payload.length > 1 && this._isLdcInstance(payload[payload.length - 2].type)) {
              resultObj.ldc = payload[payload.length - 2].sys_id;
          }
          result = JSON.stringify(resultObj);
      }
     return result;
  },

  /**
   * Take the ci type name and checks if it extends from Logical Datacenter ( directly or indirectly), 
   * there by we can say if its instance of Logical Datacenter.
   * @param name of the type 
   */
  _isLdcInstance: function(type) {
      if(!type)
          return false;

      if (type == 'cmdb_ci_logical_datacenter')
          return true;
  
      var gr = new GlideRecord('sys_db_object');
      gr.addQuery('name', type);
      gr.query();
      if (gr.next()) {
          if (gr.super_class.name && gr.super_class.name == 'cmdb_ci_logical_datacenter')
              return true;
          else if (gr.super_class.name)
              return this._isLdcInstance(gr.super_class.name);
          else
              return false;
      } else
          return false;
  },

  _getResourceBlock: function (type) {
      var rbGR = new GlideRecord('sn_cmp_rb_resourceblock');
      rbGR.get('refcitype', type);
      return rbGR.getUniqueValue();
  },

  /**
   * gets parent to chid hierarchy recursively from cmdb_rel_ci
   * @param childSysId
   * @param graph
   * @param level
   * @param isReversalAllowed
   */
  _getParentFromChild: function (childSysId, graph, level, isReversalAllowed) {
      if (level == -1) return;

      var relCIGr = new GlideRecord('cmdb_rel_ci');
      relCIGr.addQuery('child', childSysId);
      relCIGr.addQuery('type.name', '!=', 'Hosted on::Hosts');
      relCIGr.addQuery('parent.sys_class_name', '!=', 'sn_cmp_stack');
      relCIGr.query();

      if (relCIGr.getRowCount() == 0) {
          //dont let it come back and cause recursion
          if (isReversalAllowed) this._getChildFromParent(childSysId, graph, level - 1, false);
          return;
      }

      if (relCIGr.next()) {
          var parent = relCIGr.getValue('parent');
          var details = this._buildDetails(parent, relCIGr.parent.name, relCIGr.parent.sys_class_name);
          graph.push(details);
          if (details.type === 'cmdb_ci_cloud_service_account') {
              //prune recursion
              return;
          }
          this._getParentFromChild(parent, graph, level - 1, true);
      }
  },

  /**
   * gets child to parent hierarchy recursively from cmdb_rel_ci
   * @param parentSysId
   * @param graph
   * @param level
   * @param isReversalAllowed
   */
  _getChildFromParent: function (parentSysId, graph, level, isReversalAllowed) {
      if (level == -1) return;

      relCIGr = new GlideRecord('cmdb_rel_ci');
      relCIGr.addQuery('parent', parentSysId);
      relCIGr.addQuery('type.name', 'IN', 'Hosted on::Hosts,Manages::Managed by');
      relCIGr.addQuery('child.sys_class_name', '!=', 'sn_cmp_stack');
      relCIGr.query();

      if (relCIGr.getRowCount() == 0) {
          //dont let it come back and cause recursion
          if (isReversalAllowed) this._getParentFromChild(parentSysId, graph, level - 1, false);
          return;
      }

      if (relCIGr.next()) {
          var parent = relCIGr.getValue('child');
          var details = this._buildDetails(relCIGr.child, relCIGr.child.name, relCIGr.child.sys_class_name);
          graph.push(details);
          if (details.type === 'cmdb_ci_cloud_service_account') {
              //prune recursion
              return;
          }
          this._getChildFromParent(parent, graph, level - 1, true);
      }
  },

  _getRelationshipGraph: function (ciId, getChildFirst, level) {
      //in case not provided, by default navigate to service account, this also guards against infinite recursion
      if (!level) level = 20;

      var details = this._getDetails(ciId);
      var graph = [];
      graph.push(details);
      //current level added, hence -1
      if (getChildFirst) {
          this._getChildFromParent(ciId, graph, level - 1, true);
      } else {
          this._getParentFromChild(ciId, graph, level - 1, true);
      }
      return graph;
  },

  _getDetails: function (ciId) {
      var cmdbCIGr = new GlideRecord('cmdb_ci');
      cmdbCIGr.get(ciId);
      return this._buildDetails(cmdbCIGr.sys_id, cmdbCIGr.name, cmdbCIGr.sys_class_name);
  },

  _buildDetails: function (sysId, name, type) {
      return {
          'name': name + '',
          'sys_id': sysId + '',
          'type': type + ''
      };
  },

  /**
  * Since Resource Block Operations support operation delegation, its important to know what the parent resource is
  * for a particular CI, if a delegation operation is encountered.
  * Custom handling for different CIs can be added here.
  **/
  parentForConfigurationItem: function (ciId) {
      var parentCIId = this._getParentForCI(ciId);
      var parentRB = '';
      // To deduce LDCs for specific ci types, add more else if blocks.
      // ex. else if(!gs.nil(ciClassName) && ciClassName == "cmdb_ci_compute_security_group")
      if (!gs.nil(parentCIId)) {
          //Get mapped Resource Block
          var ciGR = new GlideRecord('cmdb_ci');
          if (ciGR.get(parentCIId)) {
              parentRB = this._getResourceBlock(ciGR.sys_class_name);
          }
      }
      var parentConfigInfo = { parentCI: parentCIId, parentResource: parentRB };
      return new global.JSON().encode(parentConfigInfo);
  },

  getCIClass: function (ciId) {
      var attributeClass = null;
      var cmdbRecord = new GlideRecord("cmdb");
      cmdbRecord.addQuery("sys_id", ciId);
      cmdbRecord.query();
      if (cmdbRecord.next()) {
          attributeClass = cmdbRecord.getValue("sys_class_name");
      }
      return attributeClass;

  },

  _getContainedBy: function (instanceId) {
      var relCIGr = new GlideRecord('cmdb_rel_ci');
      relCIGr.addQuery('child', instanceId);
      relCIGr.addQuery('type.name', 'Contains::Contained by');
      relCIGr.query();
      while (relCIGr.next()) {
          var ldcId = this._getLDCForCI(relCIGr.getValue('parent'));//network
          if (!gs.nil(ldcId)) {
              return ldcId;
          }
      }
  },

  _getLDCForCI: function (ciId) {
      var parentCI = this._getParentForCI(ciId);
      if (parentCI && this._isLDC(parentCI)) {
          return parentCI;
      }
  },

  _getParentForCI: function (parent) {
      var relCIGr = new GlideRecord('cmdb_rel_ci');
      relCIGr.addQuery('type.name', 'Hosted on::Hosts');
      relCIGr.addQuery('parent', parent);
      relCIGr.query();
      if (relCIGr.next()) {
          return relCIGr.getValue('child');
      }
  },

  _isLDC: function (ldcId) {
      var ldcGr = new GlideRecord("cmdb_ci_logical_datacenter");
      return ldcGr.get(ldcId);
  },

  type: 'CMPCIRelationshipUtil'
};

Sys ID

46ab25900b216300ac950bcb15673a95

Offical Documentation

Official Docs: