Name

sn_agent.AgentNowSetup

Description

No description available

Script

var AgentNowSetup = Class.create();
AgentNowSetup.prototype = Object.extendsObject(global.AbstractAjaxProcessor, {

  setup: function() {

      var mid = this.getParameter('sysparm_mid');
      var port = this.getParameter('sysparm_port');
      var ip_address = this.getParameter('sysparm_ip_address');

      return this.setupExt(mid, port, ip_address);
  },

  setupExt: function(mid, port, ip_address) {

      var retObj = {
          "msg": "",
          "extToPoll": []
      };

      var errorMsg = this.validateParams(port, ip_address);
      if (!gs.nil(errorMsg)) {
          retObj.msg = errorMsg;
          return new global.JSON().encode(retObj);
      }

      var midGr = this.getMidGr(mid);

      if (midGr) {
          // if this method is activated, then we should setup both extensions from scratch using the given parameters.
          // Stop and delete/modify existing extensions
          var webserverGr = this.getWebServer(midGr);
          if (webserverGr != null) {
              if ((webserverGr.getValue("status") + "").toLowerCase() != "started") {
                  // apply the changes required and start as we can't delete because web server table doesn't allow deletion from different scope
                  webserverGr.setValue("port_number", port);
                  webserverGr.update();
                  new global.MIDExtensionContext(webserverGr).start();
                  retObj.extToPoll.push(webserverGr.getUniqueValue());
              }
          } else {
              webserverGr = this.createWebServer(midGr, port);
              if (webserverGr == null) {
                  retObj.msg = gs.getMessage("Error. Failed to setup Agent Client Collector. MID Web Server creation didn't succeed.");
                  return new global.JSON().encode(retObj);
              }
              retObj.extToPoll.push(webserverGr.getUniqueValue());
          }

          var websocketGr = this.getWebSocket(midGr);
          if (websocketGr != null) {
              if ((websocketGr.getValue("status") + "").toLowerCase() == "started")
                  new global.MIDExtensionContext(websocketGr).stop();
              websocketGr.setWorkflow(false); // BR prevents deletion while stopping
              websocketGr.deleteRecord();
          }

          websocketGr = this.createWebSocket(midGr, ip_address);
          if (websocketGr == null) {
              retObj.msg = gs.getMessage("Error. Failed to setup Agent Client Collector. WebSocket Endpoint creation didn't succeed.");
              return new global.JSON().encode(retObj);
          }
          retObj.extToPoll.push(websocketGr.getUniqueValue());

          retObj.msg = this.getEndpointUrl(midGr, websocketGr, webserverGr);

      } else {

          retObj.msg = gs.getMessage("Error. Failed to setup Agent Client Collector on this MID (sys_id == {0}).", mid);
      }

      return new global.JSON().encode(retObj);
  },


  getMidName: function(midId) {
      var midGr = new GlideRecord("ecc_agent");
      if (midGr.get(midId))
          return midGr.getValue("name");
      return "";
  },

  multiSetup: function() {
      var createExtToMidIdsList = this.getParameter('sysparm_createExtToMidIdsList').split(",");
      var port = this.getParameter('sysparm_port');
      var extSetupList = {};

      for (var i = 0; i < createExtToMidIdsList.length; i++) {
          var midId = createExtToMidIdsList[i];
          var setUpJson = JSON.parse(this.setupExt(midId, port, null));
          setUpJson["name"] = this.getMidName(midId);
          extSetupList[midId] = setUpJson;
      }
      return encodeURIComponent(JSON.stringify(extSetupList));
  },

  validateParams: function(port, ip_address) {

      var message = "";

      var portMsg = "";
      var portNum = parseInt(port);
      if (isNaN(portNum) || portNum < 1 || portNum > 65535) {
          portMsg = gs.getMessage("Invalid port. Valid range is 1-65535.");
      }

      var ipMsg = "";
      if (ip_address && !this.validateIPaddress(ip_address)) {
          ipMsg = gs.getMessage("Invalid IP address");
      }

      if (message != "" && portMsg != "") {
          message = gs.getMessage("{0}. {1}", [message, portMsg]);
      } else if (portMsg != "") { //message must be empty string
          message = gs.getMessage("Error. {0}", portMsg);
      }

      if (message != "" && ipMsg != "") {
          message = gs.getMessage("{0}. {1}", [message, ipMsg]);
      } else if (ipMsg != "") { //message must be empty string
          message = gs.getMessage("Error. {0}", ipMsg);
      }

      return message;
  },

  startExt: function(tableName, sysId) {

      var gr = new GlideRecord(tableName);
      gr.get(sysId);
      context = new global.MIDExtensionContext(gr);
      context.start();
  },

  createWebSocket: function(midGr, ip_address) {

      var websocketGr = new GlideRecord("sn_agent_ext_context");
      websocketGr.initialize();
      websocketGr.setValue("name", "mid_websocket_" + midGr.getValue("name"));
      websocketGr.setValue("mid_server", midGr.getUniqueValue());

      if (ip_address)
          websocketGr.setValue("ip_address", ip_address);

      websocketGr.setValue("short_description", "Automatically created extension using the 'ACC Setup'");

      var websocketId = websocketGr.insert();
      if (gs.nil(websocketId))
          return null;

      this.startExt("sn_agent_ext_context", websocketId);
      return websocketGr;
  },

  handleApiKey: function(midGr, webserverGr) {
      var apiKeyCredGr = new GlideRecord("mid_webserver_api_key_credentials");
      // pre San Diego flow. If San Diego and beyond then API Key creation is handled by business rule on web server table
      if (!apiKeyCredGr.isValid()) {
          var apiKey = new global.MidWebServerApiKey();
          var midDomain = midGr.getValue("sys_domain");
          var key = apiKey.getKey(midDomain);
          if (key != "")
              webserverGr.setValue("secret_key", key);
          else
              webserverGr.setValue("secret_key", apiKey.generate(midDomain));
      }
  },

  createWebServer: function(midGr, port) {

      var webserverGr = new GlideRecord("ecc_agent_ext_context_webserver");
      webserverGr.initialize();
      webserverGr.setValue("name", "mid_webserver_" + midGr.getValue("name"));
      webserverGr.setValue("mid_server", midGr.getUniqueValue());
      webserverGr.setValue("port_number", port);
      webserverGr.setValue("execute_on", "Specific MID Server");
      webserverGr.setValue("authentication_type", "3");
      this.handleApiKey(midGr, webserverGr);
      webserverGr.setValue("secure_connection", true);
      webserverGr.setValue("short_description", "Automatically created extension using the 'ACC Setup'");
      var webserverId = webserverGr.insert();
      if (gs.nil(webserverId))
          return null;
      this.startExt("ecc_agent_ext_context_webserver", webserverId);
      return webserverGr;
  },

  getEndpointUrl: function(midGr, websocketGr, webserverGr) {
      // try using the calculated values
      var endpoint = websocketGr.getValue('endpoint_url');
      var endpoint_ip6;
      var msg;

      if (endpoint) {
          msg = gs.getMessage("Endpoint is ready to use: {0}", endpoint);

          endpoint_ip6 = websocketGr.getValue('endpoint_url_ipv6');
          if (!endpoint_ip6)
              return msg;

          msg = gs.getMessage("Endpoints are ready for use: {0} and {1}", [endpoint, endpoint_ip6]);
          return msg;
      }

      // otherwise, calculate it
      endpoint = this.calculateEndpointUrlForIpVersion(websocketGr, 4);
      endpoint_ip6 = this.calculateEndpointUrlForIpVersion(websocketGr, 6);

      if (!endpoint_ip6)
          msg = gs.getMessage("Endpoint is ready to use: {0}", endpoint);
      else
          msg = gs.getMessage("Endpoints are ready for use: {0} and {1}", [endpoint, endpoint_ip6]);

      return msg;
  },

  validateIPaddress: function(inputText) {
      var ipformat = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;

      if (inputText.match(ipformat))
          return true;

      return false;
  },

  buildMessage: function(msgArray) {
      var message = "";
      for (index in msgArray) {
          message += msgArray[index];
      }

      return message;
  },

  // pre-San Diego release, only IPv4 values were stored in IP address fields and the logic to 
  // validate IP Addresses was not exposed to the ACC-F scoped app
  shouldValidateIp: function() {
      return (typeof global.ScopedIpUtils == 'function');
  },

  getIpFromWebSocket: function(extContextGr, ipVersion) {
      var ip = extContextGr.getValue('ip_address');
      if (!ip)
          return '';

      if (!this.shouldValidateIp())
          return ip;

      // the IP Address field can store either IPv4 or IPv6, so verify the version before returning
      if (ipVersion == 4 && global.ScopedIpUtils.isV4(ip))
          return ip;

      if (ipVersion == 6 && global.ScopedIpUtils.isV6(ip))
          return ip;

      return '';
  },

  getIpFromMidRecord: function(midSysId, ipVersion) {
      if (!midSysId || !ipVersion)
          return '';

      var midGr = new GlideRecord('ecc_agent');
      midGr.addQuery('sys_id', midSysId);
      midGr.query();
      if (!midGr.next())
          return ''; /*no associated MID - return empty string */

      var ip = midGr.getValue('ip_address');

      if (!this.shouldValidateIp())
          return ip;

      // the IP Address field can store either IPv4 or IPv6, so verify the version before returning
      if (ipVersion == 4 && global.ScopedIpUtils.isV4(ip))
          return ip;

      if (ipVersion == 6 && global.ScopedIpUtils.isV6(ip))
          return ip;

      return '';
  },

  getIpFromMidIpAddressTable: function(midSysId, ipVersion) {
      if (!midSysId || !ipVersion)
          return '';

      var midIpGr = new GlideRecord('ecc_agent_ip_address');
      midIpGr.addQuery('mid_server', midSysId);
      midIpGr.addQuery('ip_version', ipVersion);
      midIpGr.query();
      if (midIpGr.next())
          return midIpGr.getValue('ip_address');

      return '';
  },

  calculateEndpointUrlForIpVersion: function(extContextGr, ipVersion) {
      var midSysId = extContextGr.getValue('mid_server');

      var ip = this.getIpFromWebSocket(extContextGr, ipVersion);

      if (!ip)
          ip = this.getIpFromMidRecord(midSysId, ipVersion);

      if (!ip)
          ip = this.getIpFromMidIpAddressTable(midSysId, ipVersion);

      if (!ip)
          return '';

      var gr = new GlideRecord('ecc_agent_ext_context_webserver');
      gr.addQuery('mid_server', midSysId);
      gr.query();
      var port = '8800';
      var protocol = 'ws';
      if (gr.next()) {
          port = gr.getValue('port_number');
          if (gr.getValue('secure_connection') == '1') {
              protocol += 's';
          }
      }

      if (ipVersion == 6)
          return gs.getMessage('{0}://[{1}]:{2}/ws/events', [protocol, ip, port]);

      return gs.getMessage('{0}://{1}:{2}/ws/events', [protocol, ip, port]);
  },

  // current refers to the sn_agent_ext_context record
  // called from the calculated field sn_agent_ext_context.endpoint_url
  calculateEndpointUrl: function(current) {
      return this.calculateEndpointUrlForIpVersion(current, 4);
  },

  // current refers to the sn_agent_ext_context record
  // called from the calculated field sn_agent_ext_context.endpoint_url_ipv6
  calculateIPv6EndpointUrl: function(current) {
      // pre-San Diego release family doesn't know how to handle this field
      if (!this.shouldValidateIp())
          return '';

      return this.calculateEndpointUrlForIpVersion(current, 6);
  },

  getMidGrIfMidIsAvailable: function(midId) {
      var midGr = new GlideRecord("ecc_agent");
      if (midGr.get(midId)) {
          if (midGr.status == 'Up' && midGr.validated == 'true')
              return midGr;
      }
      return null;
  },

  isSetupAlreadyConfiguredOnMids: function() {
      var selectedMids = this.getParameter('sysparm_mids');
      var isAccAlreadyConfiguredWrapper = function(midId) {
          return this.isAccAlreadyConfigured(midId);
      };
      return this.setupMids(selectedMids, isAccAlreadyConfiguredWrapper.bind(this));
  },

  setupMids: function(selectedMidsStr, isAccAlreadyConfiguredFunc) {
      var selectedMids = selectedMidsStr.split(',');
      var maxSelectedMids = gs.getProperty("sn_agent.maximum_mids_to_select", 20);
      if (selectedMids.length > maxSelectedMids) {
          // Use toString() so that the (selectedMids.length) does not appear as a decimal number in the message
          gs.addErrorMessage(gs.getMessage("The number of MIDs selected is {0}, but the maximum allowed is {1} according to the 'sn_agent.maximum_mids_to_select' property.", [(selectedMids.length).toString(), maxSelectedMids]));
          return -1;
      }

      var retObjList = {};
      for (var i = 0; i < selectedMids.length; i++) {
          var midId = selectedMids[i];
          var midGr = this.getMidGrIfMidIsAvailable(midId);
          if (midGr != null) {
              var isAccAlreadyConfigured;
              //We allow setup Agent Client Collector only from domain leaf
              var isDomainLeaf = new sn_agent.DomainInfo().isDomainLeaf(midGr.sys_domain);
              if (!isDomainLeaf) {
                  isAccAlreadyConfigured = {
                      'isSetupConfigured': true,
                      'msg': gs.getMessage("Error. Failed to setup Agent Client Collector. The setup is allowed only for leaf domains."),
                      'extToPoll': []
                  };
              } else if (!AccExtSetupUtil.isSetupEnabledForMid(midId)) {
                  isAccAlreadyConfigured = {
                      'isSetupConfigured': true,
                      'msg': gs.getMessage("Error. Failed to setup Agent Client Collector. Setup is allowed only when the user domain is identical to the MID Server domain, or when the mid is in a leaf domain and the user is in the global domain."),
                      'extToPoll': []
                  };
              } else {
                  isAccAlreadyConfigured = isAccAlreadyConfiguredFunc(midId);
              }
              isAccAlreadyConfigured['name'] = midGr.getValue('name');
              retObjList[midId] = isAccAlreadyConfigured;
          }
      }
      return JSON.stringify(retObjList);
  },

  isSetupAlreadyConfigured: function() {

      var mid = this.getParameter('sysparm_mid');
      var retObj = this.isAccAlreadyConfigured(mid);
      return new global.JSON().encode(retObj);

  },

  isAccAlreadyConfigured: function(midId) {
      var retObj = {
          'isSetupConfigured': true,
          'msg': "",
          "extToPoll": []
      };

      if (!GlidePluginManager.isActive('com.snc.sa.mid.webserver')) {
          retObj.msg = gs.getMessage("Error. Install com.snc.sa.mid.webserver plugin before setting up ACC listener");
          return retObj;
      }

      var midGr = this.getMidGr(midId);

      if (midGr) {

          var webServerGr = this.getWebServer(midGr);
          var webSocketGr = this.getWebSocket(midGr);

          // check which extensions are already present and if they are started or not
          if (webServerGr || webSocketGr) {

              if (!webSocketGr) { // webserver exists but websocket doesn't

                  if (webServerGr.getValue("authentication_type") == "1") { // 1 -> Keybased
                      retObj.msg = gs.getMessage("Error. MID Web Server associated with this MID uses Keybased authentication, which is not supported.");
                      return retObj;
                  }

                  if ((webServerGr.getValue("status") + "").toLowerCase() != "started") {
                      var webserverId = webServerGr.getUniqueValue();
                      this.startExt("ecc_agent_ext_context_webserver", webserverId);
                      retObj.extToPoll.push(webserverId);
                  }

                  webSocketGr = this.createWebSocket(midGr);
                  if (gs.nil(webSocketGr)) {
                      retObj.msg = gs.getMessage("Error. Failed Creating WebSocket Endpoint extension on this MID ({0}).", midGr.getValue("name"));
                      return retObj;
                  }
                  retObj.extToPoll.push(webSocketGr.getUniqueValue());

              } else if (!webServerGr) { // websocket exists but webserver doesn't

                  // in this case let's make sure that the websocket extension is stopped and deleted
                  gs.warn(gs.getMessage("ACC Extensions Setup: Found WebSocket Endpoint extension on a MID Server that doesn't have a MID Web Server extension. Making sure it is stopped and deleted..."));
                  // send the MID a command to stop the extension if it started
                  if ((webSocketGr.getValue("status") + "").toLowerCase() == "started")
                      new global.MIDExtensionContext(webSocketGr).stop();
                  webSocketGr.setWorkflow(false); // BR prevents deletion while stopping
                  webSocketGr.deleteRecord();
                  retObj.isSetupConfigured = false; // now the given MID has no extensions at all so setup is not configured...
                  return retObj;

              } else { // both extensions exist

                  if ((webServerGr.getValue("status") + "").toLowerCase() != "started") {
                      webserverId = webServerGr.getUniqueValue();
                      this.startExt("ecc_agent_ext_context_webserver", webserverId);
                      retObj.extToPoll.push(webserverId);
                  }

                  if ((webSocketGr.getValue("status") + "").toLowerCase() != "started") {
                      var websocketId = webSocketGr.getUniqueValue();
                      this.startExt("sn_agent_ext_context", websocketId);
                      retObj.extToPoll.push(websocketId);
                  }
              }

              retObj.msg = this.getEndpointUrl(midGr, webSocketGr, webServerGr);

          } else
              retObj.isSetupConfigured = false;

      } else {
          retObj.msg = gs.getMessage("Error. Failed to setup Agent Client Collector on this MID (sys_id == {0}).", midId);
      }

      return retObj;
  },

  getMidGr: function(midId) {
      var gr = new GlideRecord("ecc_agent");
      if (gr.get(midId)) {
          return gr;
      }

      return null;
  },

  getWebSocket: function(midGr) {
      var websocketGr = new GlideRecord("sn_agent_ext_context");
      websocketGr.addQuery("mid_server", midGr.getUniqueValue());
      websocketGr.query();
      if (websocketGr.next())
          return websocketGr;

      return null;
  },

  getWebServer: function(midGr) {
      var webserverGr = new GlideRecord("ecc_agent_ext_context_webserver");
      webserverGr.addQuery("mid_server", midGr.getUniqueValue());
      webserverGr.query();
      if (webserverGr.next())
          return webserverGr;

      return null;
  },

  type: 'AgentNowSetup'
});

Sys ID

69494d79532e730034b8ddeeff7b1251

Offical Documentation

Official Docs: