Name

sn_cimaf.CIMetricStagingUtilSNC

Description

No description available

Script

var CIMetricStagingUtilSNC = Class.create();
CIMetricStagingUtilSNC.prototype = {

  initialize: function() {},

  TABLES: {
      METRIC_STAGING: 'sn_cimaf_metric_staging',
      ADAPTER_CONFIGURATION: 'sn_cimaf_adapter_config',
      SYS_HUB_FLOW: 'sys_hub_flow'
  },

  FIELDS: {
      BATCH_ID: 'batch_id',
      PAYLOAD: 'payload',
      REQUEST_ID: 'request_id',
      STATE: 'state',
      METRIC: 'metric',
      METRIC_DEFINITION: 'metric_definition',
      CONFIGURATION_ITEM: 'configuration_item',
      ADAPTER_CONFIG: 'adapter_config',
      TRANSFORM_FLOW: 'transform_flow',
      TRANSFORM_SCRIPT: 'transform_script',
      SYS_ID: 'sys_id',
      INTERNAL_NAME: 'internal_name',
      SYS_SCOPE: 'sys_scope',
      SCOPE: 'scope',
      PROVIDER: 'provider',
      TRANSFORM_ACTION: 'transform_action',
      TIMESTAMP: 'timestamp',
      SYS_CREATED_ON: 'sys_created_on'
  },

  STAGING_STATES: {
      IN_PROGRESS: "in_progress",
      COMPLETED: "completed",
      FAILED: "failed"
  },

  TRANSFORM_ACTIONS: {
      FLOW: 'flow',
      SCRIPT: 'script'
  },

  // returns batch id if a similar metric request is already in progress in the defined time limit
  checkDuplicateRequestInProgress: function(ciSysId, metricDefSysId) {
      var metricStagingGr = new GlideRecord(this.TABLES.METRIC_STAGING);
      metricStagingGr.addQuery(this.FIELDS.STATE, this.STAGING_STATES.IN_PROGRESS);
      metricStagingGr.addQuery(this.FIELDS.CONFIGURATION_ITEM, ciSysId);
      metricStagingGr.addQuery(this.FIELDS.ADAPTER_CONFIG + '.' + this.FIELDS.METRIC_DEFINITION, metricDefSysId);
      metricStagingGr.setLimit(1);
      var timeLimit = gs.getProperty("sn_cimaf.metric_collection.duplicate_request_time_limit", 5);
      metricStagingGr.addQuery(this.FIELDS.SYS_CREATED_ON + "RELATIVEGT@minute@ago@" + timeLimit);
      metricStagingGr.query();

      if (metricStagingGr.next()) {
          return metricStagingGr.getValue(this.FIELDS.BATCH_ID);
      }
  },

  addStagingRecord: function(cmdbSysId, adapterConfigSysId, batchId, requestId) {
      var metricStagingGr = new GlideRecord(this.TABLES.METRIC_STAGING);
      metricStagingGr[this.FIELDS.BATCH_ID] = batchId;
      metricStagingGr[this.FIELDS.REQUEST_ID] = requestId;
      metricStagingGr[this.FIELDS.ADAPTER_CONFIG] = adapterConfigSysId;
      metricStagingGr[this.FIELDS.CONFIGURATION_ITEM] = cmdbSysId;
      metricStagingGr[this.FIELDS.STATE] = this.STAGING_STATES.IN_PROGRESS;
      return metricStagingGr.insert();
  },
  
  updateStagingRecordWithRequestId: function(stagingSysId, requestId) {
      var metricStagingGr = new GlideRecord(this.TABLES.METRIC_STAGING);
      if (metricStagingGr.get(stagingSysId)) {
          metricStagingGr.setValue(this.FIELDS.REQUEST_ID, requestId);
          metricStagingGr.update();
      }
  },

  updateStagingRecordByRequestId: function(requestId, payload /* JSON Object */ , timestamp /* GlideDateTime */ , provider /* optional */ ) {
      var metricStagingGr = new GlideRecord(this.TABLES.METRIC_STAGING);
      metricStagingGr.addQuery(this.FIELDS.REQUEST_ID, requestId);
      if (provider) {
          metricStagingGr.addQuery(this.FIELDS.ADAPTER_CONFIG + '.' + this.FIELDS.PROVIDER, provider);
      }
      metricStagingGr.query();
      if (metricStagingGr.next()) {
          this.updateStagingRecord(metricStagingGr, payload, timestamp);
      }
  },

  updateStagingRecordById: function(stagingSysId, payload /* JSON Object */ , timestamp) {
      var metricStagingGr = new GlideRecord(this.TABLES.METRIC_STAGING);
      if (metricStagingGr.get(stagingSysId)) {
          this.updateStagingRecord(metricStagingGr, payload, timestamp);
      }
  },

  // Sets state 'completed'
  updateStagingRecord: function(metricStagingGr, payload /* JSON Object */ , timestamp) {
      if (!metricStagingGr || !metricStagingGr.isValidRecord())
          return;
      try {
          payload = JSON.stringify(payload);
      } catch (e) {
          gs.error("updateStagingRecord: invalid payload object");
          return;
      }
      if (!timestamp) { // some providers might not provide timestamp, in such case set current date time.
          timestamp = new GlideDateTime();
      }
      metricStagingGr.setValue(this.FIELDS.STATE, this.STAGING_STATES.COMPLETED);
      metricStagingGr.setValue(this.FIELDS.PAYLOAD, payload);
      metricStagingGr.setValue(this.FIELDS.TIMESTAMP, timestamp.getValue());
      metricStagingGr.update();
  },

  handleStagingErrorByRequestId: function(requestId, payload /* JSON Object */ , provider /* optional */ ) {
      var metricStagingGr = new GlideRecord(this.TABLES.METRIC_STAGING);
      metricStagingGr.addQuery(this.FIELDS.REQUEST_ID, requestId);
      if (provider) {
          metricStagingGr.addQuery(this.FIELDS.ADAPTER_CONFIG + '.' + this.FIELDS.PROVIDER, provider);
      }
      metricStagingGr.query();
      if (metricStagingGr.next()) {
          this.handleStagingError(metricStagingGr, payload);
      }
  },

  handleStagingErrorById: function(stagingSysId, payload /* JSON Object */ ) {
      var metricStagingGr = new GlideRecord(this.TABLES.METRIC_STAGING);
      if (metricStagingGr.get(stagingSysId)) {
          this.handleStagingError(metricStagingGr, payload);
      }
  },

  // Sets state 'failed'
  handleStagingError: function(metricStagingGr, payload /* JSON Object */ ) {
      if (!metricStagingGr || !metricStagingGr.isValidRecord())
          return;
      try {
          payload = JSON.stringify(payload);
      } catch (e) {
          gs.error("handleStagingError: invalid payload object");
          return;
      }
      metricStagingGr.setValue(this.FIELDS.STATE, this.STAGING_STATES.FAILED);
      metricStagingGr.setValue(this.FIELDS.PAYLOAD, payload);
      metricStagingGr.update();
  },

  /*
   * Check if all stagging records are either completed or failed (not in progress).
   */
  canInitiateTransform: function(batchId) {
      var metricStagingGr = new GlideRecord(this.TABLES.METRIC_STAGING);
      metricStagingGr.addQuery(this.FIELDS.BATCH_ID, batchId);
      metricStagingGr.addQuery(this.FIELDS.STATE, this.STAGING_STATES.IN_PROGRESS);
      metricStagingGr.query();
      return !metricStagingGr.hasNext();
  },

  getFlowName: function(flowSysId) {
      if (!flowSysId)
          return '';
      var flowGr = new GlideRecord(this.TABLES.SYS_HUB_FLOW);
      if (flowGr.get(flowSysId)) {
          var sysScopeGr = flowGr[this.FIELDS.SYS_SCOPE].getRefRecord();
          if (sysScopeGr && sysScopeGr.isValidRecord()) {
              return sysScopeGr.getValue(this.FIELDS.SCOPE) + '.' + flowGr.getValue(this.FIELDS.INTERNAL_NAME);
          }
      }
      return '';
  },

  initiateTransform: function(batchId, adapterConfigSysId) {
      if (!batchId) {
          gs.error("[initiateTransform] The batchId are null or invalid");
          return;
      }

      var adapterConfigGr = new GlideRecord(this.TABLES.ADAPTER_CONFIGURATION);

      if (!adapterConfigGr.get(adapterConfigSysId))
          return;

      var metricStagingGr = new GlideRecord(this.TABLES.METRIC_STAGING);
      metricStagingGr.addQuery(this.FIELDS.BATCH_ID, batchId);
      metricStagingGr.addQuery(this.FIELDS.STATE, this.STAGING_STATES.COMPLETED);
      metricStagingGr.query();

      if (!metricStagingGr.hasNext()) {
  		gs.info("[initiateTransform] All metric staging records are failed. batchId :: " + batchId);
  		return;
  	}

      var transformAction = adapterConfigGr.getValue(this.FIELDS.TRANSFORM_ACTION);
      var inputs = {
          staging_records: metricStagingGr
      };
      var metricResult = {};
      if (transformAction == this.TRANSFORM_ACTIONS.FLOW && global.JSUtil.notNil(adapterConfigGr.transform_flow)) {
          var transformFlowName = this.getFlowName(adapterConfigGr.getValue(this.FIELDS.TRANSFORM_FLOW));
          if (transformFlowName) {
              var flowResult = sn_fd.FlowAPI.getRunner().subflow(transformFlowName).inForeground().withInputs(inputs).run();
              metricResult = flowResult.getOutputs();
          }
      } else if (transformAction == this.TRANSFORM_ACTIONS.SCRIPT && global.JSUtil.notNil(adapterConfigGr.transform_script)) {
          var transformScript = adapterConfigGr.getValue(this.FIELDS.TRANSFORM_SCRIPT);
          if (transformScript) {
              var evaluator = new GlideScopedEvaluator();
              try {
                  metricResult = evaluator.evaluateScript(adapterConfigGr, this.FIELDS.TRANSFORM_SCRIPT, inputs);
              } catch (e) {
                  gs.error("Error while executing the transform script defined at adapter: " + e);
              }
          }
      } else if (global.JSUtil.notNil(adapterConfigGr.provider) && global.JSUtil.notNil(adapterConfigGr.provider.default_transform_flow)) {
          var transformFlowName = this.getFlowName(adapterConfigGr.provider.default_transform_flow + '');
          if (transformFlowName) {
              var flowResult = sn_fd.FlowAPI.getRunner().subflow(transformFlowName).inForeground().withInputs(inputs).run();
              metricResult = flowResult.getOutputs();
          }
      }

      /*
       * Create metric record using payload returned by flow or script.
       */
      if (metricResult) {

          var lastestStagingGr = new GlideRecord(this.TABLES.METRIC_STAGING);
          lastestStagingGr.addQuery(this.FIELDS.BATCH_ID, batchId);
          lastestStagingGr.addQuery(this.FIELDS.STATE, this.STAGING_STATES.COMPLETED);
          lastestStagingGr.orderBy('timestamp');
          lastestStagingGr.setLimit(1);
          lastestStagingGr.query();

          if (lastestStagingGr.next()) {
              if (metricResult.payload) {
                  var metricSysId = new CIMetricEngine().createMetric(lastestStagingGr.configuration_item + "",
                      lastestStagingGr.adapter_config.metric_definition + "",
                      metricResult.payload,
                      lastestStagingGr.timestamp + "");

                  if (metricSysId) {
                      var failedStagingGr = new GlideRecord(this.TABLES.METRIC_STAGING);
                      failedStagingGr.addQuery(this.FIELDS.BATCH_ID, batchId);
                      failedStagingGr.addQuery(this.FIELDS.STATE, this.STAGING_STATES.FAILED);
                      failedStagingGr.query();
                      failedStagingGr.setValue('metric', metricSysId + '');
                      failedStagingGr.updateMultiple();
                  }
              } else {
                  gr.error("initiateTransform:: transform flow/script result is expected to contain payload");
              }
          } else {
              gs.info("[initiateTransform] All the stagging records in the batch [" + batchId + "] are errored out.");
          }

          /*
           * All completed stagging records in the batch are deleted.
           */
          metricStagingGr.deleteMultiple();
      }

  },

  type: 'CIMetricStagingUtilSNC'
};

Sys ID

bf4dd692c34301104442a81c8640dd9a

Offical Documentation

Official Docs: