Name

global.VCenterESXHostsStorageSensor

Description

Implementation of the VMWare - vCenter ESX Hosts Storage sensor. Create records for ESX host hardware network adapters, disks, HBAs, FC ports, iSCSI and FC disks. Create relationships between DAS/iSCSI/FC disks and datastore disks.

Script

/* jshint -W030, -W083 */

ArrayPolyfill;
FunctionPolyfill;

var VCenterESXHostsStorageSensor;

// DiscoveryCMPUtils won't be available if cloud management isn't active.  Declaring
// this ensures that we won't get an exception when we check to see if it's active.
var DiscoveryCMPUtils;

(function() {

  var vCenterSysId, vCenterUuid, datacenterMorId, datacenterSysId,esxSysId,
      debug, _this, enableCmpApi,lookUpSysIds,
      df = new DiscoveryFunctions(),
      sr = new StorageReconciler(),
      vmMap = {},
      esxMap = {},
      schema = {
          cmdb_ci_network_adapter: {
              fixup: fixupNic,
              index: ['cmdb_ci', 'mac_address', 'name']
          },
          cmdb_ci_disk: {
              fixup: fixupDisk,
              index: ['device_id', 'computer'],
              childOf: {
                  cmdb_ci_vcenter_datastore_disk: 'Exports to::Imports from'
              }
          },
          cmdb_ci_storage_hba: {
              fixup: fixupHba,
              index: ['device_id', 'computer']
          },
          cmdb_ci_fc_port: {
              fixup: fixupFcPort,
              index: ['controller', 'wwpn']
          },
          cmdb_ci_iscsi_disk: {
              fixup: fixupDisk,
              index: ['computer', 'name', 'iqn'],
              childOf: {
                  cmdb_ci_vcenter_datastore_disk: 'Exports to::Imports from'
              }
          },
          cmdb_ci_fc_disk: {
              fixup: fixupDisk,
              index: ['device_id', 'computer'],
              childOf: {
                  cmdb_ci_vcenter_datastore_disk: 'Exports to::Imports from'
              },
          },
          cmdb_fc_initiator: {
              index: ['fc_disk']
          },
          cmdb_fc_target: {
              index: ['fc_disk'],
          },
          cmdb_ci_ip_address: {
              index: ['nic']
          }
      },
      args = {
          schema: schema
      };

  VCenterESXHostsStorageSensor = {
      process: process,
      type: "DiscoverySensor"
  };

  /*
  Sample data.  Truncated for brevity, so possibly inconsistent:
  	{
  	  "cmdb_ci_network_adapter": [
  		{
  		  "name": "vmnic0",
  		  "cmdb_ci": "host-1033"
  		},
  		{
  		  "name": "vmnic1",
  		  "cmdb_ci": "host-1033"
  		}
  	  ],
  	  "cmdb_ci_storage_hba": [

  	  ],
  	  "cmdb_ci_fc_port": [

  	  ],
  	  "cmdb_ci_disk": [
  		{
  		  "computer": "host-1033",
  		  "size_bytes": 587128266752,
  		  "device_id": "mpx.vmhba1:C0:T0:L0",
  		  "device_lun": "key-vim.host.ScsiDisk-0000000000766d686261313a303a30",
  		  "correlation_id": "0000000000766d686261313a303a30",
  		  "name": "Local VMware Disk (mpx.vmhba1:C0:T0:L0)",
  		  "vendor": "VMware",
  		  "model": "Block device",
  		  "datastores": [
  			"datastore-1183",
  			"datastore-184"
  		  ]
  		},
  		{
  		  "computer": "host-109",
  		  "size_bytes": 587128266752,
  		  "device_id": "mpx.vmhba1:C0:T0:L0",
  		  "device_lun": "key-vim.host.ScsiDisk-0000000000766d686261313a303a30",
  		  "correlation_id": "0000000000766d686261313a303a30",
  		  "name": "Local VMware Disk (mpx.vmhba1:C0:T0:L0)",
  		  "vendor": "VMware",
  		  "model": "Block device",
  		  "datastores": [
  			"datastore-184",
  			"datastore-103"
  		  ]
  		}
  	  ],
  	  "cmdb_ci_fc_disk": [

  	  ],
  	  "cmdb_ci_iscsi_disk": [

  	  ]
  	}
  */
  //////////////////////////////////////////////////////////////////////////
  function process(result) {

      var name;
      getProbeParms();
      _this = this;

  	if (esxSysId)
  		 lookUpSysIds = VMUtils.lookupSysIdsESX; 
  	else
  		lookUpSysIds = VMUtils.lookupSysIds;
  	
      args.location = this.getLocationID();
      args.statusId = new DiscoveryStatus(g_probe.getParameter('agent_correlator') + '');
  	args.mutexPrefix = datacenterMorId || esxSysId ;
      args.ignoreStaleness = true;

      // During normal discovery g_probe_parameters should always be defined.
      // It's only undefined during test execution.
      if (typeof g_probe_parameters != 'undefined') {
          g_probe_parameters.cidata = this.getParameter('cidata');
          g_probe_parameters.source = this.getParameter('source');
      }

      args.results = JSON.parse(output);
      args.results.cmdb_ci_ip_address = [];

      VMUtils.triggerNextPage(_this, args.results.leftOverMors);

      JsonCi.prepare(args);
      JsonCi.writeJsObject(args, this.getLocationID(), this.statusID);
      JsonCi.writeRelationships(args);
      enableCmpApi && DiscoveryCMPUtils.callCmpApi(args.results, vCenterUuid, datacenterMorId);

      createIScsiRels();
      createFcRels();

      //do L3 mapping for ESX servers
      if (gs.getProperty('glide.discovery.L3_mapping', 'false') == 'true') {

          //loop through each ESX to create L3 mapping
          for (name in esxMap) {
              var ciid = esxMap[name] + '';
              if (!ciid)
                  continue;

              var cigr = new GlideRecord("cmdb_ci");

              if (!cigr.get('sys_id', ciid))
                  continue;

              var gru = GlideScriptRecordUtil.get(cigr);
              cigr = gru.getRealRecord();

              var DL3M = new DeviceL3Mapping(cigr);
              DL3M.map();

          }
      }


  }

  //////////////////////////////////////////////////////////////////////////
  function createFcRels() {


      var diskArr = [];
      args.results.cmdb_ci_fc_disk.forEach(
          function(disk) {
              try {
                  var rawWwnn, wwnn, wwpn, vols,
                      initiators = [],
                      targets = [],
                      wwInfo = {};

                  if (disk.targets) {
                      for (rawWwnn in disk.targets) {
                          wwnn = StorageWWN.parse(rawWwnn);
                          wwInfo[wwnn] = wwInfo[wwnn] || {};

                          for (wwpn in disk.targets[rawWwnn]) {
                              wwpn = StorageWWN.parse(wwpn);
                              wwInfo[wwnn][wwpn] = 1;
                              targets.push(wwpn);
                          }
                      }
                  }

                  if (disk.initiators) {
                      for (rawWwnn in disk.initiators) {
                          wwnn = StorageWWN.parse(rawWwnn);
                          for (wwpn in disk.initiators[rawWwnn]) {
                              wwpn = StorageWWN.parse(wwpn);
                              initiators.push(wwpn);
                              reconcileInitiatorInfo(disk, wwnn, wwpn);
                          }
                      }
                  }

                  reconcileTargetInfo(disk, wwInfo);

                  vols = sr.createFCDiskToVolumeRel(disk.sys_id, disk.device_lun, targets, initiators);
                  removeIncorrectRels(disk.sys_id, vols);
              } catch (e) {
                  var error = e.msg || e.toString();
                  if (error.indexOf('Controller is empty for FC') != -1) {
                      if (disk.name != undefined && diskArr.indexOf(disk.name) == -1)
                          diskArr.push(disk.name);
                  } else {
                      DiscoveryLogger.warn(error, 'VCenterESXHostsStorageSensor', _this.getEccQueueId());
                  }

              }
          });
      if (diskArr.length > 0) {
          errorHandler({
              msg: "Controller is empty for FC Ports: ",
              disk_ids: diskArr,
              sys_class: 'cmdb_ci_fc_disk',
              code: 'SN-1701'
          });
      }


      function reconcileInitiatorInfo(disk, wwnn, wwpn) {
          var gr = new GlideRecord('cmdb_fc_initiator');
          gr.addQuery('fc_disk', disk.sys_id);
          gr.addQuery('wwpn', wwpn);
          gr.query();

          if (gr.next()) {
              gr.wwnn = wwnn;
              gr.wwpn = wwpn;
              gr.update(); // no op if nothing changes
          } else {
              gr.initialize();
              gr.fc_disk = disk.sys_id;
              gr.wwnn = wwnn;
              gr.wwpn = wwpn;
              gr.insert();
          }
      }

      // Populate wwnn and wwpn for the paths from this server to FC disks in cmdb_fc_target table
      function reconcileTargetInfo(disk, wwInfo) {
          var gr = new GlideRecord('cmdb_fc_target');
          gr.addQuery('fc_disk', disk.sys_id);
          gr.query();

          // Go through what's in the db and reconcile it with what we found
          while (gr.next()) {
              if (wwInfo[gr.wwnn] && wwInfo[gr.wwnn][gr.wwpn])
                  delete wwInfo[gr.wwnn][gr.wwpn];
              else
                  gr.deleteRecord();
          }

          // Insert whats left over
          for (var nName in wwInfo) {
              var curInfo = wwInfo[nName];
              for (var pName in curInfo) {
                  gr.initialize();
                  gr.fc_disk = disk.sys_id;
                  gr.wwnn = nName;
                  gr.wwpn = pName;
                  gr.insert();
              }
          }
      }
  }

  //////////////////////////////////////////////////////////////////////////
  function createIScsiRels() {

      var diskArr = [];
      args.results.cmdb_ci_iscsi_disk.forEach(
          function(disk) {
              try {
                  var vols = sr.createISCSIDiskToVolumeRel(disk.sys_id, disk.device_lun, disk.iqn, disk.initiator_iqn);
                  removeIncorrectRels(disk.sys_id, vols);
              } catch (e) {
                  var error = e.msg || e.toString();
                  if (error.indexOf('iSCSI Export not found for target IQN:') != -1) {
                      if (disk.iqn != undefined && diskArr.indexOf(disk.iqn) == -1)
                          diskArr.push(disk.iqn);
                  } else {
                      DiscoveryLogger.warn(error, 'VCenterESXHostsStorageSensor', _this.getEccQueueId());
                  }
              }
          });
      if (diskArr.length > 0) {
          errorHandler({
              msg: "iSCSI Export not found for, target IQNs:",
              disk_ids: diskArr,
              sys_class: 'cmdb_ci_iscsi_disk',
              code: 'SN-1700'
          });

      }

  }

  /////////////////////////////////////////////////////////////////////////
  function errorHandler(errors) {
      var idStr = '';
      var len = (errors.disk_ids.length < 5) ? errors.disk_ids.length : 5;
      for (var i = 0; i < len; i++)
          idStr += errors.disk_ids[i].toString() + ", ";
      if (len > 5)
          idStr += 'and many more';
      errors.msg += idStr;
      var errorManager = new SNC.DiscoveryErrorManager();

      errorManager.addError(new SNC.DiscoveryErrorMsg(errors.code, 'Discovery', args.statusId.sysID, null, errors.msg, null, args.statusId.sysID));

  }

  //////////////////////////////////////////////////////////////////////////
  function removeIncorrectRels(diskSysId, volumes) {

      // Geneva and Helsinki could create incorrect disk to volume relationships.
      // Remove the incorrect relationships here.
      var gr = new GlideRecord('cmdb_rel_ci');
      gr.addQuery('child', diskSysId);
      // This is the sys_id of Exports to::Imports from
      gr.addQuery('type', '0e8ffb1537303100dcd445cbbebe5d40');
      gr.addQuery('parent.sys_class_name', 'cmdb_ci_storage_volume');
      gr.query();
      while (gr.next()) {
          if (!volumes['' + gr.parent])
              gr.deleteRecord();
      }
  }

  //////////////////////////////////////////////////////////////////////////
  function fixupDisk(disk) {
      var datastores,
          mm = MakeAndModelJS.fromNames(disk.vendor || '', disk.model || '', 'hardware');

      disk.storage_type = disk.storage_type || 'disk';
      disk.device_interface = disk.device_interface || 'scsi';
      disk.manufacturer = disk.vendor = '' + mm.getManufacturerSysID();
      disk.model_id = '' + mm.getModelNameSysID();

  	disk.computer = lookUpSysIds(disk.computer, 'cmdb_ci_esx_server', esxSysId || vCenterSysId , 'morid');
  	datastores = lookUpSysIds(disk.datastores, 'cmdb_ci_vcenter_datastore', esxSysId || vCenterSysId);


      gr = new GlideRecord('cmdb_ci_vcenter_datastore_disk');
  	if (!esxSysId)
  		gr.addQuery('vcenter_uuid', vCenterUuid);
      gr.addQuery('name', disk.device_id);
      gr.addQuery('datastore', 'IN', datastores);
      gr.query();
      disk.cmdb_ci_vcenter_datastore_disk = [];
      while (gr.next())
          disk.cmdb_ci_vcenter_datastore_disk.push('' + gr.sys_id);
  }

  //////////////////////////////////////////////////////////////////////////
  function fixupHba(hba) {
      var mm = MakeAndModelJS.fromNames(null, hba.model_id, 'hardware');
      hba.model_id = '' + mm.getModelNameSysID();
      hba.wwnn = StorageWWN.parse(hba.wwnn);

  	hba.computer = lookUpSysIds(hba.computerMorid, 'cmdb_ci_esx_server', esxSysId || vCenterSysId, 'morid');
  }

  //////////////////////////////////////////////////////////////////////////
  function fixupFcPort(port) {
      port.wwnn = StorageWWN.parse(port.wwnn);
      port.wwpn = StorageWWN.parse(port.wwpn);
      port.speed = new DiscoveryDataRate(port.speed, DiscoveryDataRate.Units.GBps).to(DiscoveryDataRate.Units.GFC) + ' GFC';
      port.name = 'FC Port ' + port.wwpn;

      port.controller = args.results.cmdb_ci_storage_hba[port.controller];
  	port.computer = lookUpSysIds(port.controller.computerMorid, 'cmdb_ci_esx_server', esxSysId || vCenterSysId , 'morid');

  }

  //////////////////////////////////////////////////////////////////////////
  function fixupNic(nic) {

      nic.ip_address = nic.ip_address || '';
      nic.dhcp_enabled = nic.dhcp_enabled || 0;
      nic.virtual = nic.virtual || 0;

  	nic.cmdb_ci = lookUpSysIds(nic.cmdb_ci, 'cmdb_ci_esx_server', esxSysId || vCenterSysId, 'morid');

      if (nic.ip_address) {
          var morid = (nic.cmdb_ci.morid || nic.cmdb_ci) + '';
          esxMap[morid] = nic.cmdb_ci;
          args.results.cmdb_ci_ip_address.push({
              name: nic.name,
              ip_address: nic.ip_address,
              ip_version: 4,
              nic: nic,
              netmask: nic.netmask
          });

      }

  }

  //////////////////////////////////////////////////////////////////////////
  function getProbeParms() {
  	vCenterSysId = (g_probe.getParameter('vcenter_sys_id') || '') + '';
      vCenterUuid  = (g_probe.getParameter('vcenter_uuid') || '') + '';
  	datacenterSysId =  (g_probe.getParameter('datacenter_sys_id') || '') + ''; 
  	datacenterMorId =  (g_probe.getParameter('datacenter_mor_id') || '') + '';
      debug = '' + g_probe.getParameter('debug');
      enableCmpApi = DiscoveryCMPUtils.isCmpActive() && (('' + g_probe.getParameter('enable_cmp_qa')) == 'true');
  	esxSysId = (g_probe.getParameter('esx_sys_id') || '') + '';
  }

})();

Sys ID

54f22f788f731200c2fe0b5437bdeeaf

Offical Documentation

Official Docs: