Name

global.Nginx

Description

Process the NGINX load balancer information collected by the probe.

Script

// Discovery

var Nginx = Class.create();
Nginx.prototype = Object.extendsObject ( LBModule, {
  
  initialize: function (blocks, serverIP , webServerGr) {
  	this.servers = blocks.serverList;
  	this.upstreams = blocks.upstreamList; 
  	this.hosts = blocks.hostList; 
  	this.webServerGr = webServerGr;
  	this.serverIP = serverIP; 
  	this.serverName = '';
  	this.lbGr = null; 
  	this.type = 'Nginx';
  },
  
  /*
   * Return true if nginx is configured as a load-balancer
   * It is possible that nginx is setup only as a webserver, in this case 
   * no information is populated. 
   */
  isLoadBalancer: function () {
        var RunsOn_Runs = '60bc4e22c0a8010e01f074cbe6bd73c3';
        var hostCISysID, hostCIClass;
        if (this.servers.length > 0) {
          // Fetching the related host CI for the web server
          var hostRelGr = new GlideRecord('cmdb_rel_ci');
          hostRelGr.addQuery('parent', this.webServerGr.getValue('sys_id'));
          hostRelGr.addQuery('type', RunsOn_Runs);
          hostRelGr.query();
          if(hostRelGr.next()) {
              hostCISysID = hostRelGr.getValue('child');
              hostCIClass = hostRelGr.getElement('child.sys_class_name');
          }

          this.serverName = this.webServerGr.getValue('name').split('@')[1];
          this.lbGr = this.updateNginxLbTable(this.serverName, this.serverIP, 'cmdb_ci_lb_nginx', hostCISysID, hostCIClass, this.webServerGr.getValue('sys_id'));

          return true;
        }
        return false;
  },
  
  /*
   * Populate LB information for Nginx
   * We start from every virtual server defined by the server block 
   * Every service is defined based on the ip, port and input_url, so for every 
   * port or ip or host name assigned to a server we need to create a new service.
   * For example : server {
   *						listen 	10.12.12.23:80
   *						listen	 10.12.12.24:80
   *						server_name example.org example.com
   *						...
   *						location / {
   *								proxy_pass http://myCloud
   *						}
   * we need to create 4 services 
   * service1: (ip: 10.12.12.23:80, port: 80, input_url:example.org/)
   * service2: (ip: 10.12.12.23:80, port: 80, input_url:example.com/)
   * service3: (ip: 10.12.12.24:80, port: 80, input_url:example.org/)
   * service4: (ip: 10.12.12.24:80, port: 80, input_url:example.com/)
   */
  populateInfo: function () {
  	
  	for (var i =0; i < this.servers.length ; i++) {
  		
  		var server = this.servers[i];
  		// For every server, process listen parameters to find ip and port
  		for (var j = 0; j < server.listens.length; j++){
  			var listen = server.listens[j];
  			// Process list of locations to find the url and poolName 
  			for (var k = 0; k < server.locations.length; k++) {
  				var location = server.locations[k];
  				var serviceGrList = this.populateServiceInfo (server, listen, location); 
  				this.populatePoolInfo (serviceGrList, location); 
  				
  			}
  		}
  	}
  	// Create Relationship 'provides:: provided by' between the inginx web server and the load_balancer
  	
  	var cmdbGr = g_device.getCmdbCi();
  	var discoFunctions = new DiscoveryFunctions();
  	discoFunctions.createRelationshipIfNotExists(cmdbGr, this.lbGr.sys_id+'','Provides::Provided by');
  	
  	this.reconcile(this.lbGr.getValue('sys_id'));
  	
  },
  /*
   * For every name of the server we create a service and populate information
   * in cmdb_ci_lb_service.
   */
  populateServiceInfo: function (server, listen, location) {
  	var serviceList = [];

  	// Don't support IPv6
  	if (listen.indexOf('[::]') > -1)
  		return serviceList;
  						
  	// No information for the pool						
  	if (this.upstreams[location.proxyPass] == undefined)
  		return serviceList; 
  
  	// Find ip and port for the service
  	var ip = this.serverIP;		  // default IP address is the ip address of the server
  	var port = 80;   				//default port for nginx is 80
  	
  	
  	var parts = listen.split(':');
  	if (parts.length == 1) 			// It is possible that we have only the port:  listen 80;
  		port = parts[0]; 
  	else {
  		port = parts[1];
  		if (parts[0] != 'localhost' && parts[0] != '*')	// If the ip part is '*' or localhost ip is the same as serverIP
  			ip = parts[0];
  	}
  	
  	// Process url part from location block
  	// If url or the server_name is regular expression then input_url is populated
  	// with this format "regExpr:server_name/url"
  	var regExprUrl = false; 
  	var locationUrl = location.url;
  	
  	if (locationUrl.charAt(0) == '~') {	// '~' at the begining of the url menas we used regular expression
  		regExprUrl = true;
  		locationUrl = locationUrl.substring(locationUrl.indexOf('~')+1); 
  	}
  	
  	// It is possible that server_name is not defined 
  	// In this case all location are related to the main server
  	if ( server.names.length == 0 )
  		server.names.push (''); 
  	
  	// create a service for every defined virtual server name
  	// For every url the complete url is a combination of the server-name and url
  	// Example:
  	// 		server_name	myExample.org
  	// 		location  /{
  	//				....
  	//		 }
  	// the input_url which is populated is myExample.org/
  	for (var i = 0; i < server.names.length; i++) {
  		var service = {}; 
  		service.name = 'Nginx@' + this.serverName + ':' + port;
  		service.port = port;
  		service.ip_address = ip; 
  		// It is possible that the server_name is defined as a regular expression
  		// the same rules for url is followed
  		var regExprServer = false;
  		var name = server.names[i]; 
  		if (name.charAt(0) == '~' ) {
  			regExprServer = true;
  			name = name.substring(name.indexOf('~')+1);
  		}
  		
  		if (locationUrl.indexOf('/') != 0)
  			service.input_url = name +'/'+ locationUrl;
  		else
  			service.input_url = name + locationUrl;
  		
  		if (regExprUrl || regExprServer)
  			service.input_url = 'regExpr:' + service.input_url;
  		
  		service.load_balancer = this.lbGr.sys_id + '';
  		serviceList.push (this.updateServiceTable(service));
  	}
  	
  	return serviceList; 	
  					
  },
  
  /* 
   * Based on the name of the pool, the corresponding upstream block is found
   * and the method of load balancing is populated.
   */
  populatePoolInfo: function (serviceGrList, location) {
  	for (var i = 0 ; i < serviceGrList.length ; i++) {
  		var serviceGr = serviceGrList[i];
  		
  		// Populate pool information in cmdb_ci_pool table
  		var poolName  = location.proxyPass;
  		var lbMethod = this.upstreams[poolName].method;
  		var poolGr = this.updatePoolTable(poolName, lbMethod, this.lbGr, serviceGr);
  					
  		//Populate pool memebrs information 
  		if (!gs.nil (poolGr)) 
  			this.populatePoolMemberInfo (poolName, poolGr);
  			
  		
  					
  	}
  },
  /*
   * From the upstream block corresponding to the pool, the information 
   * for the pool members are populated 
   */ 
  populatePoolMemberInfo: function (poolName, poolGr) {
  	var pool = this.upstreams[poolName];
  	
  	for (var i = 0; i < pool.servers.length; i++) {
  		var server = pool.servers[i];
  		var ipInfo = server.split(':');
  		var ip = server.split(':')[0];
  		var port = server.split(':')[1];
  		if (gs.nil(port))
  			port = 80;    	//default port is 80 
  			
  		//Create a member object 
  		var member = {};
  		member.name = 'LBMember@' + poolName;
  		member.service_port = port;
  		member.load_balancer = this.lbGr.sys_id + '';
  		if (this.isValidIPv4 (ip))
  			member.ip_address = ip;
  		else {
  			member.fqdn = ip;
  			if (this.hosts [ip] != undefined)
  				member.ip_address = this.hosts[ip];
  			
  		}
  		this.updatePoolMemberTable (member, poolGr) ;
  	}
  	
  	
  },
  /* 
   * Check if a string for ip is an IPv4 ?
   */
  isValidIPv4: function(ip) {
	try {
  	var valid = new SncAddress32Bit(ip);
	} catch (ex) {
   	return false;
   }

   return true;
  },
  			 
  type: 'Nginx'
});

Sys ID

387c2933d7722100a866ee5b5e61032a

Offical Documentation

Official Docs: