Name

sn_agent.AgentNowHandler

Description

Sends a request to agents to perform a given check. the main API method is runCheckForCis

Script

var AgentNowHandler = Class.create();

AgentNowHandler.REQUEST_STATUS = {
  PROCESSING: "processing",
  DONE: "done",
  FAILURE: "failure",
  TIMEOUT: "timeout",
  MID_FLOW: "mid_flow"
};

AgentNowHandler.REQUEST_NOT_FOUND_MSG = "no request with given id";
AgentNowHandler.TEST_RESULT_NOT_FOUND_MSG = "no test result with given id";
AgentNowHandler.TEST_RESULT_TIMEOUT_MSG = "request timeout";
AgentNowHandler.BACKGROUND_REQUEST_NOT_FOUND_MSG = "no background check request with given id";

AgentNowHandler.TEST_RESULT_STATUS = {
  PENDING: 0,
  IN_PROGRESS: 1,
  COMPLETE: 2,
  ERROR: 3,
  CANCELED: 4
};

AgentNowHandler.prototype = {
  initialize: function() {},

  // 1. CIs – Glide record of any cmdb table (can be any application, host, or agent). Those are the elements that the check is working against
  // 2. A check object containing the check ID and optionally params. Example:
  //     check = {
  //        "checkDefId": "c143ab237f705300f128134f8dfa9168",
  //        "params": {
  //            "warning": "80",
  //            "critical": "90",
  //        }
  // 
  // 3. Priority: Priority of the request to be set on the ECC queue (0 - interactive, 1 - expedited , 2 - standard)
  // 4. Timeout (s): The request defined timeout, if timeout pass mark the status as timeout
  //
  // the method will return the request ID
  runCheckForCis: function(cis, check, priority, timeout) {
      var clientsGenerator = new PolicyClientsGeneratorNG();
      var mc = new MonitoringConfig();
      var checkJson = this.buildCheckJson(check);
      checkJson = this.injectCommandSuffixBasedOnCheckType(checkJson);
      var command = checkJson['command'];

      var clientsParams = clientsGenerator.getClientsByCisForCheckNoPolicy(cis, checkJson['id'], command);
      return this.runCheck(cis, checkJson, this.getPolicyPerMid(clientsParams), priority, timeout);
  },

  injectCommandSuffixBasedOnCheckType: function(checkJson) {
      // For Upgrade check types, we would like to add the version flag and is debug mode automatically
      if (checkJson.check_type_id == "b69143c853a901100112ddeeff7b125b") {
          var agentVer = AgentVersionFieldStyle.getAgentVersionFinal();

          // add version
          checkJson.command = checkJson.command + ' -v ' + agentVer;

          // Add dev mode flag
          if (gs.getProperty('sn_agent.dev_mode', 'false') == 'true')
              checkJson.command = checkJson.command + ' -d true';
      } else if (checkJson.check_type_id == "754f5f84532d01100112ddeeff7b1248" && checkJson.command == "read-file.rb") {
          // For Upgrade log file check type, include the label in the command for the file_path check parameter
          checkJson.command = "read-file.rb -f {{.labels.params_file_path}}";
      }

      return checkJson;
  },

  // Kills background checks that were started by running a request with the given request ID
  stopBackgroundCheck: function(requestId) {
      // reconstruct an array containing all ids of agents which were relevant for the request with the given id
      var agentIds = [];
      var gr = new GlideRecord("sn_agent_flags");
      gr.addQuery("name", "STARTSWITH", ["back_req", requestId, ""].join("_"));
      gr.query();
      if (!gr.hasNext()) {
          gs.error(gs.getMessage("background check with request id [ {0} ] was never created or already stopped", requestId));
          return AgentNowHandler.BACKGROUND_REQUEST_NOT_FOUND_MSG;
      }
      while (gr.next()) {
          var agentIdsOfFlag = JSON.parse(gr.getValue("hash"));
          for (var i = 0; i < agentIdsOfFlag.length; i++)
              agentIds.push(agentIdsOfFlag[i]);
          gr.deleteRecord();
      }
      var agentsGr = new GlideRecord("sn_agent_cmdb_ci_agent");
      agentsGr.addQuery("agent_id", agentIds);
      agentsGr.query();
      var killCheck = {
          name: "kill_" + requestId,
          kill_background: true,
          background_requestId: requestId
      };
      this.runCheck(agentsGr, killCheck, this.getPolicyPerMid(new PolicyClientsGeneratorNG().getClientsByCisForCheckNoPolicy(agentsGr)), 0, 0);
      return null;
  },

  // Given a request id returned by runCheckForCis, return a JSON containing the request status and error message if the status indicates a failure
  getRequestStatus: function(requestId) {
      var retJson = {
          status: "",
          err_msg: null
      };
      var gr = new GlideRecord("sn_agent_request");
      if (!gr.get(requestId)) {
          retJson.status = AgentNowHandler.REQUEST_STATUS.FAILURE;
          retJson.err_msg = AgentNowHandler.REQUEST_NOT_FOUND_MSG;
      } else {
          retJson.status = gr.getValue("status");
          if (retJson.status == AgentNowHandler.REQUEST_STATUS.FAILURE)
              retJson.err_msg = gr.getValue("error_message");
      }
      return retJson;
  },

  // given a test result id for a test check execution, return a JSON containing the test status and output message
  getTestResultStatus: function(testResultId) {
      var retJson = {
          status: AgentNowHandler.TEST_RESULT_STATUS.PENDING,
          output: null
      };
      var testResultGr = new GlideRecord("sn_agent_test_result");
      if (!testResultGr.get(testResultId)) {
          retJson.status = AgentNowHandler.TEST_RESULT_STATUS.ERROR;
          retJson.output = AgentNowHandler.TEST_RESULT_NOT_FOUND_MSG;
          return retJson;
      }
      retJson.status = parseInt(testResultGr.getValue("status"));
      if (retJson.status == AgentNowHandler.TEST_RESULT_STATUS.PENDING)
          retJson.output = "test result is still pending";
      else if (retJson.status == AgentNowHandler.TEST_RESULT_STATUS.IN_PROGRESS) {
          retJson.output = "test result is still in progress";
      } else if (retJson.status == AgentNowHandler.TEST_RESULT_STATUS.COMPLETE) {
          retJson.output = testResultGr.getValue("output");
      } else if (retJson.status == AgentNowHandler.TEST_RESULT_STATUS.CANCELED) {
          retJson.output = testResultGr.getValue("output");
      } else { // retJson.status == AgentNowHandler.TEST_RESULT_STATUS.ERROR
          retJson.output = testResultGr.getValue("error_msg");
      }
      return retJson;
  },

  runCheckForAgentPerMid: function(check, policyPerMid, priority, timeout) {
      var checkJson = this.buildCheckJson(check);
      return this.runCheck("", checkJson, policyPerMid, priority, timeout);
  },

  getPolicyPerMid: function(clientsParams) {
      var midToPolicy = {};
      var agentsGr = new GlideRecord("sn_agent_ci_extended_info");
      agentsGr.addQuery("agent_id", Object.keys(clientsParams));
      agentsGr.addEncodedQuery("status!=2");
      agentsGr.query();
      while (agentsGr.next()) {
          var midName = global.JSUtil.getBooleanValue(agentsGr, "use_cloud_services") ? ACCConstants.CLOUD_SERVICES_POD_PREFIX + agentsGr.mid : "" + agentsGr.mid.name;
          var agent_id = agentsGr.agent_id;
          var policyPerMid = midToPolicy[midName];
          if (!policyPerMid) {
              policyPerMid = {};
              policyPerMid["auto_binding"] = true;
              policyPerMid["clients_cis"] = {};
              midToPolicy[midName] = policyPerMid;
          }
          policyPerMid["clients_cis"][agent_id] = clientsParams[agent_id];
      }
      return midToPolicy;
  },

  runCheck: function(cis, checkJson, midToPolicy, priority, timeout) {
      var agentsFromAllMids = [];
      for (var mid in midToPolicy) {
          var agentsForSpecificMid = Object.keys(midToPolicy[mid]["clients_cis"]);
          for (var i = 0; i < agentsForSpecificMid.length; i++)
              agentsFromAllMids.push(agentsForSpecificMid[i]);
      }
      var numberOfActualAgents = agentsFromAllMids.length;

      if (priority == null)
          priority = '2'; //if no priority was provided - use Standard

      //don't rely on the timeout in the check definition, use the one from api
      if (timeout)
          checkJson["timeout"] = "" + timeout;
      else
          timeout = checkJson["timeout"]; //if no timeout, grab it from the check def

      checkJson["priority"] = priority;
      var requestId = this.createAgentRequest(cis, checkJson, numberOfActualAgents, priority, timeout);

      var background = checkJson["params_background"];
      if (numberOfActualAgents > 0 && !gs.nil(background) && background)
          this.createBackgroundRequestFlags(requestId, agentsFromAllMids);

      checkJson["requestId"] = requestId;

      //only in case type is not test check and not check discover and not null (e.g. when killing background check the request will not have a check type id)
      if (!gs.nil(checkJson["check_type_id"]) && checkJson["check_type_id"] != "a32f261967133300b7b72dbd2685eff9" && checkJson["check_type_id"] != "4048774567633300b7b72dbd2685efa1") {
          //when sending multiple requests with same check def and ci, the agent will refuse to run a check if it already
          //running (identified by <check def id>_<ci id>). To avoid that situation, we will prefix the check def id with
          //the request id, thus each request will be identified (<request_id>_<check_def_id>_<ci_id>) uniquely.
          //for discovery we don't want to allow executing more than one request at a time
          //in test check we relay on the "id" to be the check id, otherwise ci params will not be passed
          checkJson["id"] = requestId + '_' + checkJson["id"];
      }
      var checksWrapper = [];
      checksWrapper.push(checkJson);

      for (mid in midToPolicy) {
          var policy = midToPolicy[mid];
          policy["checks"] = checksWrapper;
          var payload;
          if (mid.startsWith(ACCConstants.CLOUD_SERVICES_POD_PREFIX)) {
              // cloud services case, convert V1 check request policy to a V2 configuration object then sign it to generate the payload
              payload = (new ConfigPublishPayload()).convertOnDemandPolicyToSignedPayload(policy);
          } else
              payload = (new MonitoringSync()).getPayload(JSON.stringify(policy));

          new MonitoringConfig().sendProbe('on_demand_request', 'on_demand_request', "mid.server." + mid, payload, priority, requestId);
      }

      return requestId;
  },

  buildCheckJson: function(check) {
      var gr = new GlideRecord("sn_agent_check_def");
      if (!gr.get(check.checkDefId))
          return {};

      var accUtils = new ACCConfigUtils();
      var checkJson = accUtils.getCheckJson(gr);
      if (check.check_type_id) // if we got a check type - use it
          checkJson["check_type_id"] = check.check_type_id;
      else {
          checkJson["check_type_id"] = gr.getValue("check_script_type");
          if (gr.check_script_type) {
              var midScriptRef = gr.check_script_type.mid_script;
              if (midScriptRef)
                  checkJson["mid_script"] = midScriptRef.name + "";
              checkJson["instance_script"] = gr.check_script_type.enable_instance_script + "";
          }
      }
      if (check.params) {
          if (!checkJson["params"])
              checkJson["params"] = {};

          for (var key in check.params) {
              checkJson["params"][key] = check.params[key];
          }
      }

      return checkJson;
  },

  createAgentRequest: function(cis, check, numberOfAgents, priority, timeout) {
      var gr = new GlideRecord("sn_agent_request");
      gr.setValue("check", JSON.stringify(check));
      gr.setValue("check_def", check.id);
      gr.setValue("timeout", timeout + "");
      gr.setValue("priority", priority + "");
      gr.setValue("num_of_requested_checks", numberOfAgents);
      if (cis) {
          gr.setValue("table", cis.getTableName());
          gr.setValue("encoded_query", cis.getEncodedQuery());
          var cisCount = cis.getRowCount();
          if (numberOfAgents == 0) {
              gr.setValue("status", "failure");
              gr.setValue("error_message", "no agents found for relevant CIs");
          } else {
              if (numberOfAgents < cisCount) {
                  gr.setValue("error_message", "cis count is: " + cisCount + ", but number of found agents is: " + numberOfAgents);
              }
              if (check.instance_script == "false" && check.mid_script) {
                  gr.setValue("status", "mid_flow"); //mid flow only without instance script - the request record will not be updated anymore
              } else {
                  gr.setValue("status", "processing");
              }
          }
      }

      return gr.insert();
  },

  processEccRecord: function(current) {
      var xmlDoc = new XMLDocument2();
      var payload = this.getEccPayload(current);
      xmlDoc.parseXML(payload);

      var output = xmlDoc.getFirstNode("//results/result/output");
      // Check for errors
      var results = xmlDoc.getFirstNode("//results");
      // clear variable values
      payload = 0;
      xmlDoc = 0;

      if (results.hasAttribute("error")) {
          var errMsg = "Found error on main results node - cannot process the payload";
          if (!output)
              throw errMsg;
          else
              gs.error("AgentNowHandler: " + errMsg + ". Error found on ECC queue=" + current.sys_id + ". Error=" + results.getAttribute("error"));
      }
      // clear variable holdings
      results = 0;
      // track the agent ids
      var agentIds = [];
      var isAttachment = current.payload == "<see_attachment/>";

      if (output) {
          var priorityToCheckTypeToResults = {};
          var requestIdToNumberOfChecks = {};

          //in case we are grabbing log, we don't have check results and the name will be file name
          if (current.name == "on_demand_request") {
              var checkResults = JSON.parse(output.getTextContent());
              output = 0;
              for (var index = 0; index < checkResults.length; index++) {
                  var checkResult = checkResults[index];

                  if (isAttachment)
                      // track the agent ids that we see while processing so we can add the agent ids to the input payload
                      agentIds.push("\"" + checkResult["agent_id"] + "\"");

                  // if agent is connecting without MID and the registration has been invalidated ignore incoming payload
                  if (checkResult["use_cloud_services"] && this.isAgentValidated(checkResult["agent_id"]))
                      continue;

                  var check = checkResult["check"];

                  if (!this.isBackgroundFlow(check)) {
                      //the default is the non interactive priority
                      var priority = 2;
                      //things coming from policy, don't have priority
                      if (check["priority"])
                          priority = check["priority"];
                      var typeId = check["check_type_id"];
                      var checkTypeToResults = priorityToCheckTypeToResults[priority];
                      if (!checkTypeToResults) {
                          checkTypeToResults = {};
                          priorityToCheckTypeToResults[priority] = checkTypeToResults;
                      }
                      var checkTypeResults = checkTypeToResults[typeId];
                      if (!checkTypeResults) {
                          checkTypeResults = [];
                          checkTypeToResults[typeId] = checkTypeResults;
                      }
                      checkTypeResults.push(checkResult);
                  }

                  var requestId = check["requestId"];
                  if (requestId) {
                      var numberOfChecks = requestIdToNumberOfChecks[requestId];
                      if (!numberOfChecks) {
                          numberOfChecks = 0;
                      }
                      requestIdToNumberOfChecks[requestId] = numberOfChecks + 1;
                  }
              }
              // clear variable
              checkResults = 0;

              var scriptIdToTypeId = {};

              //iterate over the priorities
              for (priority = 0; priority < 3; priority++) {
                  checkTypeToResults = priorityToCheckTypeToResults[priority];
                  if (checkTypeToResults) {
                      var checkTypeGr = new GlideRecord("sn_agent_check_type");
                      checkTypeGr.addQuery("sys_id", Object.keys(checkTypeToResults));
                      checkTypeGr.query();
                      while (checkTypeGr.next()) {
                          if (checkTypeGr.instance_script) {
                              var evaluator = new GlideScopedEvaluator();
                              evaluator.putVariable("checkResults", checkTypeToResults[checkTypeGr.getValue("sys_id")]);
                              //in case there is an exception inside the script its caught in glide level and written to logs...
                              evaluator.evaluateScript(checkTypeGr, 'instance_script');
                          }
                      }
                  }
              }

              this.updateProcessedChecks(current.sys_id + "", requestIdToNumberOfChecks);
          } else {
              //just need the key of agent correlator to switch the state of the output record to "done"
              requestIdToNumberOfChecks[current.agent_correlator] = "";
          }
          var time = new GlideDateTime();
          var hoursAgo = gs.getProperty("sn_agent.time_ago_in_seconds_to_query_ecc_queue", 43200); //12 hours in seconds by default
          time.addSeconds(-1 * hoursAgo);
          //set the ouptut ecc queue records in processed state
          var outputRequestRecords = new GlideRecord("ecc_queue");
          outputRequestRecords.addQuery("agent_correlator", Object.keys(requestIdToNumberOfChecks));
          //update only the record of current mid
          outputRequestRecords.addQuery("agent", current.agent);
          outputRequestRecords.addQuery("state", "processing");
          outputRequestRecords.addQuery("sys_created_on", ">", time); //improve the query performance by querying only the current shard table
          outputRequestRecords.setValue("state", "processed");
          outputRequestRecords.updateMultiple();
      }

      current.processed = new GlideDateTime();
      current.state = 'processed';
      if (isAttachment && agentIds.length > 0)
          // DEF0253876: add the agent ids to the input payload so that this ecc queue record
          // gets associated with the agent ids in the "Recent ECC queues" UI action
          current.payload = current.payload + "\nAgent IDs: " + agentIds.join(',');
      current.update();
  },

  markAgentsForCollectionFailedForDiscoveryTypeCheck: function(eccQueueSysId) {
      return this.markAgentsHostDataForDiscoTypeChecks(eccQueueSysId, '2'); // 2=Collection Failed
  },

  markAgentsHostDataForDiscoTypeChecks: function(eccQueueSysId, hostDataStatus) {
      if (!eccQueueSysId) {
          gs.error("AgentNowHandler: Did not get an ecc queue sys id");
          return;
      }

      var eccGr = new GlideRecord('ecc_queue');
      if (!eccGr.get('sys_id', eccQueueSysId)) {
          gs.error("AgentNowHandler: Cannot locate ecc queue with sys id = " + eccQueueSysId);
          return;
      }

      var payload = eccGr.getValue('payload');
      // First validate this is a discovery type check
      var checkTypeRegEx = /\"check_type_id\"\s*:\s*"(.*?)"/g;
      var matchCheck = checkTypeRegEx.exec(payload);
      if (!matchCheck || !matchCheck[1]) {
          gs.warn("AgentNowHandler: Could not locate check type, return");
          return;
      }

      var checkTypeId = matchCheck[1];
      if (!AgentDiscoverySharedUtils.isDiscoveryCheckType(checkTypeId)) {
          gs.debug("AgentNowHandler: This is NOT a discovery check type, return");
          return;
      }

      if (hostDataStatus == '')
          gs.warn("AgentNowHandler: We need to retry to Collect host data");

      var agentIds = [];
      /* This regex will catch the client_cis as a JSON string representation
      	Input: <output>{"auto_binding":true,"clients_cis":{"d8c726724c3bbb91":{"a9f0a61d539a85100112ddeeff7b12fb":...}</output>
      	Catch groups: {"auto_binding":true,"clients_cis":{"d8c726724c3bbb91":{"a9f0a61d539a85100112ddeeff7b12fb":...}
      */
      var clientsCisRegEx = /\{(.*)\}/g;
      var match = clientsCisRegEx.exec(payload);

      // need to get the clients_cis
      if (!match || !match[1]) {
          gs.error("AgentNowHandler: Could not catch clients_cis from payload: " + payload);
          return;
      }

      // match[1] now hold clients_cis as JSON string representation
      var clientCisAsStr = "{" + match[1] + "}"; // Add {} to make the root object
      var clientCisObj = JSON.parse(clientCisAsStr);
      for (var key in clientCisObj.clients_cis) {
          agentIds.push(key);
      }

      if (!agentIds || agentIds.length < 1) {
          gs.warn("AgentNowHandler: no agents to retry, we should had at least 1");
          return;
      }

      AgentDiscoverySharedUtils.setAgentsHostDataStatus(agentIds, hostDataStatus);
  },

  updateProcessedChecks: function(sys_id, requestIdToNumberOfChecks) {
      var agentRequestGr;
      for (requestId in requestIdToNumberOfChecks) {
          agentRequestGr = new GlideRecord("sn_agent_request");
          agentRequestGr.addQuery("sys_id", requestId);
          agentRequestGr.query();
          agentRequestGr.next();
          var numberOfRequested = agentRequestGr.getValue("num_of_requested_checks");

          if (numberOfRequested == requestIdToNumberOfChecks[requestId]) {
              //in case num of requested is equal to the number of checks on the ecc queue record - can handle directly
              agentRequestGr.setValue("num_of_processed_checks", parseInt(requestIdToNumberOfChecks[requestId]));
              agentRequestGr.setValue("status", "done");
              agentRequestGr.update();
          } else {
              this.updateRequestChecksTable(sys_id, requestId, parseInt(requestIdToNumberOfChecks[requestId]));
          }

      }
  },

  updateRequestChecksTable: function(eccId, requestId, numberOfProcessedChecks) {
      var gr = new GlideRecord("sn_agent_request_checks");
      gr.setValue("ecc_queue", eccId);
      gr.setValue("request", requestId);
      gr.setValue("num_of_processed_checks", numberOfProcessedChecks);
      gr.insert();
  },

  handleRequestChecksTable: function() {
      var processedRecords = [];
      var requestIdToNumberOfChecks = {};
      var gr = new GlideRecord("sn_agent_request_checks");
      gr.addQuery("status", "pending");
      gr.query();
      while (gr.next()) {
          var request = gr.getValue("request");
          var numberOfChecks = requestIdToNumberOfChecks[request];
          if (!numberOfChecks) {
              numberOfChecks = 0;
          }
          requestIdToNumberOfChecks[request] = numberOfChecks + parseInt(gr.getValue("num_of_processed_checks"));
          processedRecords.push(gr.getUniqueValue());
      }

      for (requestId in requestIdToNumberOfChecks) {
          agentRequestGr = new GlideRecord("sn_agent_request");
          agentRequestGr.addQuery("sys_id", requestId);
          agentRequestGr.query();
          agentRequestGr.next();
          var numberOfRequested = agentRequestGr.getValue("num_of_requested_checks");
          var numOfProcessed = parseInt(agentRequestGr.getValue("num_of_processed_checks")) || 0;
          numOfProcessed += parseInt(requestIdToNumberOfChecks[requestId]);
          agentRequestGr.setValue("num_of_processed_checks", numOfProcessed);
          if (numberOfRequested == numOfProcessed)
              agentRequestGr.setValue("status", "done");
          agentRequestGr.update();

      }

      //update processedRecords status to done in bulk
      gr = new GlideRecord('sn_agent_request_checks');
      gr.addQuery("sys_id", "IN", processedRecords);
      gr.setValue("status", "done");
      gr.updateMultiple();

      //go over all records that are still in 'processing' status and haven't been updated
      //in the last 2 minutes + their timeout value, and set their status to timeout
      gr = new GlideRecord("sn_agent_request");
      gr.addQuery("status", "processing");
      gr.query();
      var gdt1 = new GlideDateTime();
      var gdt2 = new GlideDateTime();
      while (gr.next()) {
          //safely call parseInt becuase "timeout" is guarenteed to be integer
          gdt1.subtract(2 * 60 * 1000 + parseInt(gr.getValue("timeout")) * 1000);
          gdt2.setValue(gr.getValue("sys_updated_on"));
          if (gdt2.compareTo(gdt1) < 0) {
              gr.setValue("status", "timeout");
              gr.update();
              this.markTestResultsInTimeout(gr.getUniqueValue());
          }
          gdt1 = new GlideDateTime();
      }
  },

  markTestResultsInTimeout: function(requestId) {
      var testResultGr = new GlideRecord("sn_agent_test_result");
      testResultGr.addQuery("agent_request", requestId);
      testResultGr.addQuery("status", "IN", "0,1");
      testResultGr.setValue("status", "3");
      testResultGr.setValue("error_msg", AgentNowHandler.TEST_RESULT_TIMEOUT_MSG);
      testResultGr.updateMultiple();
  },

  getEccPayload: function(ecc) {
      if (ecc.payload != "<see_attachment/>") {
          return ecc.payload;
      }
      var attachmentGr = new GlideRecord("sys_attachment");
      attachmentGr.addQuery("table_sys_id", ecc.sys_id);
      attachmentGr.addQuery("table_name", "ecc_queue");
      attachmentGr.query();
      attachmentGr.next();
      var attachmentHandler = new GlideSysAttachment();
      return attachmentHandler.getContent(attachmentGr);
  },

  //
  // Check if the payload is an attachment, and if so, that it does not exceed the max payload size property value.
  //
  canProcessPayload: function(ecc) {
      if (ecc.payload != "<see_attachment/>") {
          return true;
      }
      var aggregateGr = new GlideAggregate("sys_attachment");
      aggregateGr.addAggregate("COUNT", "table_sys_id");
      aggregateGr.addQuery("table_sys_id", ecc.sys_id);
      aggregateGr.addQuery("table_name", "ecc_queue");
      aggregateGr.addQuery("size_bytes", "<=", gs.getProperty("sn_agent.ecc_queue.max_payload_size", 5000000));
      aggregateGr.query();
      aggregateGr.next();
      return aggregateGr.getAggregate("COUNT", "table_sys_id") > 0;
  },

  // Decide if the given CI class is an agent (sn_agent_cmdb_ci_agent), a host (extends cmdb_ci_hardware), or an application
  classifyClass: function(tableName) {

      //gs.debug('classify ' + tableName);
      if (tableName == 'cmdb' || tableName == 'cmdb_ci')
          return 'host';

      if (tableName == "sn_agent_cmdb_ci_agent")
          return 'agent';

      var baseTables = new GlideTableHierarchy(tableName).getTables();
      for (var i = 0; i < baseTables.length; i++) {
          var currTable = baseTables[i];
          if (currTable == "cmdb_ci_hardware")
              return 'host';
          if (currTable == "cmdb_ci_appl")
              return 'app';
      }

      return 'unknown';
  },

  //
  // check if CI as associated live agent. The CI can be the CI of the agent itself (sn_agent_cmdb_ci_agent), a host associated
  // with an agent, or application running on host associated with an agent
  //
  hasAgent: function(ci) {
      // Validity check
      if (!ci || ci == '')
          return false;

      // First we need to find the class of the CI
      var cmdbCi = new GlideRecord('cmdb_ci');
      if (!cmdbCi.get(ci)) {
          return false;
      }

      var ciClass = cmdbCi.getValue('sys_class_name') + '';
      var agentCiType = this.classifyClass(ciClass);
      //gs.debug('agentCiType = ' + agentCiType);
      // Handle the case the CI is the agent itself
      var agentGr;
      if (agentCiType == 'agent') {
          agentGr = new GlideRecord('sn_agent_cmdb_ci_agent');
          agentGr.addQuery('sys_id', ci);
          agentGr.addQuery('agent_extended_info.status', '0');
          agentGr.query();
          return (agentGr.next());
      }

      // Handle the case the CI is host
      if (agentCiType == 'host') {
          agentGr = new GlideRecord('sn_agent_cmdb_ci_agent');
          agentGr.addQuery('agent_extended_info.cmdb_ci', ci);
          agentGr.addQuery('agent_extended_info.status', '0');
          agentGr.query();
          return (agentGr.next());
      }

      // In case the CI is an application
      if (agentCiType == 'app') {
          // Find the host
          var relGr = new GlideRecord('cmdb_rel_ci');
          relGr.addQuery('parent', ci);
          relGr.addQuery('type', '60bc4e22c0a8010e01f074cbe6bd73c3'); // Runs-on relation type
          relGr.query();
          if (relGr.next())
              return this.hasAgent(relGr.child);
          return false;
      }

      return false;
  },

  createBackgroundRequestFlags: function(requestId, agentIds) {
      // max length of the hash field on sn_agent_flags is 4,000. length of each agent id is 16.
      // to be on the safe side lets limit the size of the array to include 200 agent ids.
      // 200 * 16 = 3,200. 3,200 + overhead of formatting into json array < 4,000.
      var maxAgentIdsPerFlag = 200;
      var flagIndex = 0;
      while (agentIds.length > 0) {
          var numAgentIdsLeft = agentIds.length;
          var flagAgentIdsArr = [];
          for (var i = 0; i < numAgentIdsLeft && i < maxAgentIdsPerFlag; i++)
              flagAgentIdsArr.push(agentIds.shift());
          var gr = new GlideRecord("sn_agent_flags");
          gr.initialize();
          gr.setValue("name", ["back_req", requestId, flagIndex].join("_"));
          gr.setValue("hash", JSON.stringify(flagAgentIdsArr));
          gr.insert();
          flagIndex++;
      }
  },

  // determine if the check response is part of a background flow check - start a background check or kill one
  isBackgroundFlow: function(check) {
      var background = check["background_response"];
      var killBackground = check["kill_background"];
      return (!gs.nil(background) && background == "true") || (!gs.nil(killBackground) && killBackground == "true");
  },

  // Determine if the agent connecting via Cloud Services is validated or not
  isAgentValidated: function(agentId) {
      var regGr = new GlideRecord("sn_agent_agent_registration");
      regGr.addQuery("agent_id", agentId);
      regGr.query();
      regGr.next();
      return regGr.getValue("is_validated") == '0'; // '0' representation of false
  },

  type: 'AgentNowHandler'
};

Sys ID

158279505372b30034b8ddeeff7b1270

Offical Documentation

Official Docs: