Name
global.DiscoveryAcceleratorManager
Description
Handles requests from Discovery Accelerator Scripted REST API
Script
var DiscoveryAcceleratorManager = Class.create();
DiscoveryAcceleratorManager.prototype = {
initialize: function() {
this.discoveryCredentialTypes = '';
},
_getAcceleratorRunFlowRecord: function() {
var accelRunGlideRecord = new GlideRecord('discovery_accel_config');
accelRunGlideRecord.query();
accelRunGlideRecord.next();
return accelRunGlideRecord;
},
getFlowData: function() {
return {
credentialTypes: this._getDiscoveryCredentialTypes(),
credentials: this._getDiscoveryCredentials(),
preferredSelectedCredential: 'windows_credentials',
schedule: this._getSchedule(),
routerLocations: this._getLocationsData()
};
},
//_getDiscoveryCredentialTypes needs to be called first before this function is being called
//make sure discoveryCredentialTypes are populated so only discovery relavent credentials are returned
_getDiscoveryCredentials: function() {
var creds = [];
var credGlideRecord = new GlideRecord('discovery_credentials');
credGlideRecord.addQuery('sys_class_name','IN', this.discoveryCredentialTypes);
credGlideRecord.query();
while (credGlideRecord.next()) {
var cred = {};
cred.sysId = credGlideRecord.getUniqueValue() + '';
cred.type = credGlideRecord.type + '';
cred.name = credGlideRecord.name + '';
cred.userName = credGlideRecord.user_name + '';
cred.sysClassName = credGlideRecord.sys_class_name + '';
cred.active = !!credGlideRecord.active;
creds.push(cred);
}
return creds;
},
_getDiscoveryCredentialTypes: function() {
var credTypes = [];
this.discoveryCredentialTypes = '';
var gr = new GlideRecord("credential_type_metadata");
gr.addQuery("applies_to","ip");
gr.query();
while(gr.next()) {
var credType = {};
credType.label = gr.credential_type + '';
credType.type = gr.credential_type + '';
//Get table label
var grDb = new GlideRecord("sys_db_object");
grDb.addQuery("name",gr.credential_type + '');
grDb.query();
if(grDb.next())
credType.label = grDb.label + '';
credTypes.push(credType);
this.discoveryCredentialTypes += credType.type;
if(gr.hasNext())
this.discoveryCredentialTypes += ',';
}
return credTypes;
},
_getSchedule: function() {
var accelRunGlideRecord = this._getAcceleratorRunFlowRecord();
if (accelRunGlideRecord.getRowCount() == 0) {
accelRunGlideRecord.initialize();
accelRunGlideRecord.insert();
return {};
}
return {
maxRun: accelRunGlideRecord.max_run + '',
runType: accelRunGlideRecord.run_type + '',
runDayOfWeek: parseInt(accelRunGlideRecord.run_dayofweek, 10) || 1,
runDayOfMonth: parseInt(accelRunGlideRecord.run_dayofmonth, 10) || 1,
runTime: accelRunGlideRecord.run_time + '',
runPeriod: accelRunGlideRecord.run_period + '',
runStart: accelRunGlideRecord.run_start + '',
active: !!accelRunGlideRecord.active,
locationBased: !!accelRunGlideRecord.location_based
};
},
saveSchedule: function(scheduleData) {
if (scheduleData.runType == 'periodically' && JSUtil.nil(scheduleData.runPeriod)) {
return {
success: false,
message: 'Run period must not be empty'
};
}
var accelRunGlideRecord = this._getAcceleratorRunFlowRecord();
var errorMessage = '';
accelRunGlideRecord.setValue('active', scheduleData.active);
accelRunGlideRecord.setValue('run_type',scheduleData.runType);
accelRunGlideRecord.setValue('location_based',scheduleData.locationBased);
if (JSUtil.notNil(scheduleData.runTime))
accelRunGlideRecord.setValue('run_time', scheduleData.runTime);
if (JSUtil.notNil(scheduleData.runPeriod))
accelRunGlideRecord.setValue('run_period', new GlideDateTime(scheduleData.runPeriod));
else
accelRunGlideRecord.setValue('run_period', "");
if (JSUtil.notNil(scheduleData.runStart))
accelRunGlideRecord.setValue('run_start', scheduleData.runStart);
if (JSUtil.notNil(scheduleData.runDayOfWeek))
accelRunGlideRecord.setValue('run_dayofweek', scheduleData.runDayOfWeek);
if (JSUtil.notNil(scheduleData.runDayOfMonth))
accelRunGlideRecord.setValue('run_dayofmonth', scheduleData.runDayOfMonth);
if (JSUtil.notNil(scheduleData.maxRun))
accelRunGlideRecord.setValue('max_run', new GlideDateTime(scheduleData.maxRun));
else
// Empty max_run will result the following error in Discovery Log: Failed to parse max_run into a Date object
// This is why we put a 0ed date
accelRunGlideRecord.setValue('max_run', new GlideDateTime(new Date(0)));
var success = accelRunGlideRecord.update();
errorMessage = success ? '' : 'Error while updating schedule config record. Please check System Log for more information';
if (success)
this._createOrUpdateDiscoverySchedules();
return {
success: success,
message: errorMessage
};
},
assignLocationToRouters: function(assignmentData) {
var networkDevicesGlideRecord = new GlideRecord('cmdb_ci_netgear'),
locationGlideRecord = new GlideRecord('cmn_location'),
errorMessage = '',
numRoutersCantBeUpdated = 0,
numUpdatedRouters = 0,
locationSysId = assignmentData.location,
routers = assignmentData.routers;
if (!locationSysId || !locationGlideRecord.get('sys_id', locationSysId)) {
errorMessage = 'Location doesn\'t exist';
} else if ( !routers ) {
errorMessage = 'No routers selected';
} else {
networkDevicesGlideRecord.addQuery('sys_id', 'IN', routers);
networkDevicesGlideRecord.query();
numUpdatedRouters = networkDevicesGlideRecord.getRowCount();
numRoutersCantBeUpdated = routers.split(',').length - numUpdatedRouters;
if (numRoutersCantBeUpdated > 0)
errorMessage = numRoutersCantBeUpdated + ' router(s) out of ' + routers.length + ' can\'t be updated';
networkDevicesGlideRecord.setWorkflow(true);
networkDevicesGlideRecord.setValue('location', locationSysId);
networkDevicesGlideRecord.updateMultiple();
}
return {
success: (errorMessage == '') ? true : false,
message: errorMessage,
count: numUpdatedRouters
};
},
unassignLocationToRouters: function( routerData ) {
var routers = routerData.routers;
var networkDevicesGlideRecord = new GlideRecord('cmdb_ci_netgear'),
numUpdatedRouters = 0;
networkDevicesGlideRecord.addQuery('sys_id', 'IN', routers);
networkDevicesGlideRecord.query();
while (networkDevicesGlideRecord.next()) {
networkDevicesGlideRecord.location = '';
if (networkDevicesGlideRecord.update())
numUpdatedRouters++;
}
return {
success: true,
message: '',
count: numUpdatedRouters
};
},
_getLocationsData: function() {
var locationsData = {},
currentTraveresedRouterLocation,
networkDevicesGlideRecord = new GlideRecord('cmdb_ci_netgear');
networkDevicesGlideRecord.addQuery('can_route', true);
networkDevicesGlideRecord.query();
while (networkDevicesGlideRecord.next()) {
currentTraveresedRouterLocation = networkDevicesGlideRecord.location + '';
currentTraveresedRouterLocation = currentTraveresedRouterLocation ? currentTraveresedRouterLocation : 'unassigned';
if (!locationsData[currentTraveresedRouterLocation]) {
locationsData[currentTraveresedRouterLocation] = {
name: (networkDevicesGlideRecord.location) ? networkDevicesGlideRecord.location.name + '' : currentTraveresedRouterLocation,
routers: [],
timezone: (networkDevicesGlideRecord.location) ? networkDevicesGlideRecord.location.time_zone + '' : ''
};
}
locationsData[currentTraveresedRouterLocation].routers.push(networkDevicesGlideRecord.getUniqueValue() + '');
}
return locationsData;
},
_getLocations: function() {
var locations = [];
var gr = new GlideAggregate("cmdb_ci_netgear");
gr.addNotNullQuery("location");
gr.addQuery('can_route', true);
gr.groupBy("location");
gr.query();
while(gr.next()) {
locations.push(gr.location + "");
}
return locations;
},
// Helper method to set all values from accelConfig to the discovery_schedule
_setScheduleValues: function(scheduleGr, accelConfigGr, locationSysId) {
scheduleGr.setValue('max_run', accelConfigGr.max_run);
scheduleGr.setValue('run_type', accelConfigGr.run_type);
scheduleGr.setValue('run_dayofweek', accelConfigGr.run_dayofweek);
scheduleGr.setValue('run_dayofmonth', accelConfigGr.run_dayofmonth);
scheduleGr.setValue('run_period', accelConfigGr.run_period);
scheduleGr.setValue('active', accelConfigGr.active);
scheduleGr.setValue('accel_config', accelConfigGr.sys_id);
scheduleGr.setValue('mid_select_method', 'auto_select');
// Now do the location based timezone magic.
var runTime = accelConfigGr.run_time;
var startTime = accelConfigGr.run_start;
if (JSUtil.notNil(locationSysId)) {
// Get timezone of the location
var locGr = new GlideRecord("cmn_location");
if (locationSysId)
locGr.get('sys_id', locationSysId);
var timeZone = locGr.time_zone;
// If timezone - set location by timezone otherwise - just proceed
// We are getting the time in the userLocalTime in UTC. So if the user puts in 1PM
// and the user is in PTC timezone - you will get run_time of 1PM + 8 hours for UTC - So 21:00:00
// Here we want to find the difference between the usertimezone and the location time zone and use that
// as the offset to set the time of when things to run.
// So that's what we do.
if (JSUtil.notNil(timeZone)) {
// Adjust the time accordingly for run_time
runTime = new GlideDateTime(accelConfigGr.run_time);
this._convertTime(runTime, timeZone, false);
// Adjust the time accordingly for startTime
if (!JSUtil.nil(startTime)) {
startTime = new GlideDateTime(accelConfigGr.run_start);
this._convertTime(startTime, timeZone, true);
}
}
}
scheduleGr.setValue('run_time', runTime);
scheduleGr.setValue('run_start', startTime);
},
// Convert time from current timezone to location timezone
_convertTime: function(time, timeZone, useTimeForOffset) {
/*
* This function responsible for converting schedule's time, configured by user's time zone, to the exact same time but on different locations
* All calculations are done using winter clock. GlideDateTime class will detect DST time zone, and reduce an hour if needed
* Since GlideDateTime supports DTS, we have to take it into consideration when calculating the time for the schedule
*
* For example:
* Pacific user creates a discovery to run at 12am, and he has 3 routers in: San Diego, Hong Kong & London
* Schedules should be created as follows:
* a. San Diego schedule should show 12am (8am UTC) - Same as user's time zone
* b. Hong Long schedule should show 8am (4pm UTC) - 8am PST is 12am in Hong Kong
* c. London schedule should show 4pm (12am UTC) - 4pm PST is 12am in London
*
* Remember, all times calculated are in winter clock: London is GMT, Hong Kong stays the same (no DST all year) & Pacific is PST (not PDT)
*/
var gdtOffset,
dstOffsetInMs = 0;
if (useTimeForOffset)
gdtOffset = time;
else
gdtOffset = new GlideDateTime();
// In case a time zone is currently DST, we need to save DST offset
// In this case it is user's time zone DST offset
dstOffsetInMs = gdtOffset.getDSTOffset();
// "userOffset" will be -8 hours for PST
// When we are in winter clock, the calculatio will be: -8h - 0h DST offset
// When we are in DST, the calculatio will be: -7h - 1h DST offset
userOffset = gdtOffset.getTZOffset() - dstOffsetInMs;
// Set GlideDateTime time zone to be location's time zone - For example London
var tz = Packages.java.util.TimeZone.getTimeZone(timeZone);
gdtOffset.setTZ(tz);
// In case a time zone is currently DST, we need to save DST offset
// In this case it is location's time zone DST offset
dstOffsetInMs = gdtOffset.getDSTOffset();
// "locationOffset" will be 0 hours for London
// When we are in winter clock, the calculatio will be: 0h - 0h DST offset
// When we are in DST, the calculatio will be: 1h - 1h DST offset
var locationOffset = gdtOffset.getTZOffset() - dstOffsetInMs;
// Subtract the 2 - so above example it will be -8 hours
var offset = userOffset - locationOffset;
// Final calculation for London -
// 12am PST = 8am UTC + (-8h offset) = 12am UTC = 4pm PST = 12am GMT (London's winter time)
time.setNumericValue(time.getNumericValue() + offset);
},
// Update the discovery_schedule record with new accelerator config changes.
_updateDiscoverySchedule: function(scheduleGr, accelConfigGr, locationSysId) {
this._setScheduleValues(scheduleGr, accelConfigGr, locationSysId);
scheduleGr.update();
},
// Create the discovery_schedule record with the accleartor config changes
_createDiscoverySchedule: function(accelConfigGr, locationSysId) {
var gr = new GlideRecord("discovery_schedule");
gr.initialize();
//
// Set location, schedule name, and rest of values
//
if (JSUtil.notNil(locationSysId)) {
gr.setValue('location', locationSysId);
}
gr.setValue('name', this._getScheduleName(locationSysId));
this._setScheduleValues(gr, accelConfigGr, locationSysId);
// go ahead and insert
gr.insert();
},
// Set the name of the schedule
_getScheduleName: function(locationSysId) {
// If location there - then try to get location name
if (JSUtil.notNil(locationSysId)) {
var locationGr = new GlideRecord("cmn_location");
if (locationSysId && locationGr.get('sys_id', locationSysId))
return "Auto schedule " + locationGr.name;
else
return "Auto schedule " + locationSysId;
}
return "Auto schedule";
},
// Inactivate system schedule created in K
_inactivateSystemSchedule: function() {
var gr = new GlideRecord("discovery_schedule");
gr.addQuery("was_created_by_system", true);
gr.query();
if (gr.next()) {
gr.setValue("active", false);
gr.update();
}
},
// create or update the discovery schedules
_createOrUpdateDiscoverySchedules: function() {
// Get the discovery_accel_config config, init, and getLocations we need to create schedules for.
var accelConfigGr = this._getAcceleratorRunFlowRecord();
var gr = new GlideRecord("discovery_schedule");
gr.addQuery("accel_config", accelConfigGr.sys_id);
gr.query();
// Handle if location
if (!!accelConfigGr.location_based) {
var locationsToCreate = this._getLocations();
//
// Go through all the schedules already created and see if we need to update them or delete them
//
while (gr.next()) {
var locationSysId = gr.location + '';
// delete record if we don't have any routers in this location anymore else update it
var index = locationsToCreate.indexOf(locationSysId);
if (index == -1) {
gr.deleteRecord();
}
else {
// remove it from the list
locationsToCreate.splice(index, 1);
this._updateDiscoverySchedule(gr, accelConfigGr, locationSysId);
}
}
//
// Let's create any that we have not updated
//
for (var i=0; i < locationsToCreate.length; i++) {
this._createDiscoverySchedule(accelConfigGr, locationsToCreate[i]);
}
}
else { // No location schedule
// Did we update the schedule?
var scheduleUpdated = false;
//
// Go through all the schedules already created and see if we need to update them or delete them
//
while (gr.next()) {
if (JSUtil.nil(gr.location + '')) {
this._updateDiscoverySchedule(gr, accelConfigGr);
scheduleUpdated = true;
}
else
gr.deleteRecord();
}
// Create schedule if there are none for non-location
if (!scheduleUpdated)
this._createDiscoverySchedule(accelConfigGr);
}
this._inactivateSystemSchedule();
},
triggerDiscoveryNow: function() {
var accelConfigGr = this._getAcceleratorRunFlowRecord();
var disco = new Discovery();
var gr = new GlideRecord("discovery_schedule");
gr.addQuery("accel_config", accelConfigGr.sys_id);
gr.query();
while(gr.next()) {
disco.discoverNow(gr);
}
},
type: 'DiscoveryAcceleratorManager'
};
Sys ID
148cffd453730300e06462f706dc346e