Name
global.CloudServiceAccountPatterns
Description
Trigger execution of patterns associated with cmdb_ci_cloud_service_account as part of execution of discovery schedule of type Cloud Resources
Script
var CloudServiceAccountPatterns = Class.create();
CloudServiceAccountPatterns.prototype = {
initialize: function() {
var logger;
},
/*
* find the MID server that matches the cloud type based on the service account
*/
findMidByServiceAccount: function (service_account) {
// Get glide record of the service account
var serviceAccountGr = new GlideRecord('cmdb_ci_cloud_service_account');
if (!serviceAccountGr.get(service_account)) {
logger.warn('Service account not found: ' + service_account);
return;
}
// find provider type by the service account datacenter type
var capiProviderGr = new GlideRecord('sn_capi_provider');
capiProviderGr.addQuery('datacenter_class', serviceAccountGr.datacenter_type);
capiProviderGr.query();
if (!capiProviderGr.next()) {
logger.warn("Provider type not found. datacenter_type: " + serviceAccountGr.datacenter_type);
return;
}
var service_account_id = serviceAccountGr.getValue("account_id");
var invocationContext = {};
invocationContext['service_account_id'] = service_account_id;
var cmdMidSelector = new global.CloudMidSelectionApi();
var mid_id = cmdMidSelector.selectMid(null, capiProviderGr.name, null, JSON.stringify(invocationContext));
if (!mid_id) {
logger.warn("MID not found for schedule");
return;
}
// Find the mid name
var midGr = new GlideRecord('ecc_agent');
if (!midGr.get(mid_id)) {
logger.warn('MID ' + mid_id + ' not found in table ecc_agent');
return null;
}
var agent = midGr.name;
return agent;
},
getCredAliasNames: function (tags) {
if (!tags)
return;
var names = [];
var gr = new GlideRecord('sys_alias');
gr.addQuery('sys_id', tags);
gr.query();
while (gr.next()) {
names.push(gr.id);
}
return names.join(",");
},
getDatacenterTypeBySchedule: function(discoverySchedule) {
var ldcConfigGr = new GlideRecord('cmp_discovery_ldc_config');
ldcConfigGr.addQuery('discovery_schedule', discoverySchedule);
ldcConfigGr.addNotNullQuery('service_account.datacenter_type');
ldcConfigGr.setLimit(1);
ldcConfigGr.query();
if (!ldcConfigGr.next()) {
logger.warn('No record found in cmp_discovery_ldc_config having a service account with configured datacenter type');
return null;
}
return ldcConfigGr.service_account.datacenter_type + '';
},
getDatacenterTypeByAccountList: function(serviceAccounts) {
var serviceAccountGr = new GlideRecord('cmdb_ci_cloud_service_account');
serviceAccountGr.addQuery('sys_id', 'IN', serviceAccounts);
serviceAccountGr.addNotNullQuery('datacenter_type');
serviceAccountGr.setLimit(1);
serviceAccountGr.query();
if (!serviceAccountGr.next()) {
logger.warn('No record found in cmdb_ci_cloud_service_account with a valid datacenter type');
return null;
}
return serviceAccountGr.datacenter_type + '';
},
// Get all Infra patterns of service account associated. Consult sa_ci_to_map in order to avoid running pattern of wrong cloud
getPatternsToRun: function(provider, excludedPatterns) {
if (!provider) {
logger.warn('No provider was provided. Can\'t perform lookup for service account patterns to execute');
return [];
}
if (!excludedPatterns)
excludedPatterns = [];
var patternsToRun = [];
var saCiToPattern = new GlideRecord('sa_ci_to_pattern');
saCiToPattern.addQuery('ci_type', provider);
saCiToPattern.addQuery('pattern.active', '1');
saCiToPattern.addQuery('pattern.cpattern_type','3');
saCiToPattern.addQuery('pattern.ci_type','cmdb_ci_cloud_service_account');
saCiToPattern.addQuery('pattern', 'NOT IN', excludedPatterns);
saCiToPattern.query();
while (saCiToPattern.next())
patternsToRun.push(saCiToPattern.pattern + '');
return patternsToRun;
},
getAccountsToLDCsMap: function (ldcList) {
if (!ldcList)
return {};
var ldcArr = ldcList.split(',');
if (ldcArr.length == 0)
return {};
var ldcsChunkSize = 100,
ldcsChunk,
accountToLDCs = {};
while (ldcArr.length) {
ldcsChunk = ldcArr.splice(0, ldcsChunkSize);
var relGr = new GlideRecord('cmdb_rel_ci');
relGr.addQuery('parent', 'IN', ldcsChunk);
relGr.addQuery('type', '5f985e0ec0a8010e00a9714f2a172815'); // Hosted-on
relGr.query();
while (relGr.next()) {
var serviceAccount = relGr.child + '';
/*
* We check if the account already exists because the same account
* can show up multiple times in cmp_discovery_ldc_config for different LDCs
* See attached pic at DEF0092784 [DEF0092784_3SubAccounts_3LDCs.png]
*/
if (!accountToLDCs.hasOwnProperty(serviceAccount))
accountToLDCs[serviceAccount] = [];
accountToLDCs[serviceAccount].push(relGr.parent + '');
}
}
// Remove accounts that are not valid anymore [in case database has bad data for some reason]
var serviceAccounts = Object.keys(accountToLDCs);
for (var idx in serviceAccounts) {
var serviceAccountGlideRecord = new GlideRecord('cmdb_ci_cloud_service_account');
if (!serviceAccountGlideRecord.get('sys_id', serviceAccounts[idx]))
delete accountToLDCs[serviceAccounts[idx]];
}
return accountToLDCs;
},
/*
* Find all the infrastructure patterns associated with CI type cmdb_ci_cloud_service_account and trigger them
*/
runServiceAccountPatterns: function (discoveryStatus, ldcList) {
logger = new DiscoveryLogger(discoveryStatus);
// Load the discovery status record
var statusGr = new GlideRecord('discovery_status');
if (!statusGr.get(discoveryStatus)) {
logger.warn('Discovery status ' + discoveryStatus + ' not found');
return;
}
/*
* Find the discovery schedule from the discovery status
* In case of an invalid schedule we still want to try and get accounts.
* because it may indicate we are on 'Discover Now' type of discovery
* triggered by CMP's admin screen
*/
var discoveryScheduleGlideRecord = new GlideRecord('discovery_schedule');
var discoverySchedule = statusGr.dscheduler + '';
if (!discoveryScheduleGlideRecord.get('sys_id', discoverySchedule))
discoverySchedule = null;
/*
* DEF0107342
* Had to comment the below section to provide a workaround for the defect
* This code should stay here to be uncommented\modified for future fix
*
* var serviceAccounts = [];
* // Find service accounts
* if (discoverySchedule != null)
* serviceAccounts = this.findServiceAccountsBySchedule(discoverySchedule);
* else
* serviceAccounts = this.findServiceAccountsByLDCs(ldcList);
*/
var accountToLDCs = this.getAccountsToLDCsMap(ldcList);
var serviceAccounts = Object.keys(accountToLDCs);
// If for some reason [shouldn't happen] we have no accounts back, use the schedule
if (serviceAccounts.length == 0)
serviceAccounts = this.findServiceAccountsBySchedule(discoverySchedule);
if (serviceAccounts.length == 0) {
logger.warn('No service acocunt defined on cmp_discovery_ldc_config for schedule "' + statusGr.dscheduler.name + '"');
return;
}
var datacenterType;
/*
* If we have a schedule, find datacenter type using cmp_discovery_ldc_config
* Datacenter type should be the same for a single schedule
* Otherwise, grab it from the accounts found
* This helps take out some queries of the loop: Exclude list & CIs to pattern
*/
if (discoverySchedule != null)
datacenterType = this.getDatacenterTypeBySchedule(discoverySchedule);
else
datacenterType = this.getDatacenterTypeByAccountList(serviceAccounts);
if (datacenterType == null)
return;
// Build exclude list
var grExclude = new GlideRecord('sa_cloud_topology_discovery_pattern');
grExclude.addQuery('datacenter_type', datacenterType);
grExclude.query();
var excludedPatterns = [];
while (grExclude.next())
excludedPatterns.push(grExclude.pattern + '');
var patternsToRun = this.getPatternsToRun(datacenterType, excludedPatterns);
var cad = new CloudApplicationDiscovery();
// Prepare and trigger all infrastructure patterns for all service accounts found
for (var idx in serviceAccounts) {
var serviceAccountId = serviceAccounts[idx];
serviceAccountGr = new GlideRecord('cmdb_ci_cloud_service_account');
if (!serviceAccountGr.get(serviceAccountId)) {
logger.warn('Service account ' + serviceAccountId + ' not found');
continue;
}
var ppe = cad.createPreExecutionData(serviceAccountId, null);
ppe.addString('cloud_account_id', serviceAccountGr.account_id);
ppe.addString('cloud_datacenter_type', serviceAccountGr.datacenter_type);
ppe.addString('cloud_datacenter_url', serviceAccountGr.datacenter_url);
if (serviceAccountGr.discovery_credentials) {
var credGr = new GlideRecord('discovery_credentials');
if (credGr.get(serviceAccountGr.discovery_credentials)) {
ppe.addString('cloud_cred_name', credGr.name);
ppe.addString('cloud_cred_id', serviceAccountGr.discovery_credentials);
ppe.addString('cloud_cred_alias', this.getCredAliasNames(credGr.tag));
}
}
// Fill cmp_discovery_ldc_config on the pattern context
ldcConfigGr = new GlideRecord('cmp_discovery_ldc_config');
ldcConfigGr.addQuery('service_account', serviceAccountId);
// Same account can be on different schedules. We want to get info only for current schedule
ldcConfigGr.addQuery('discovery_schedule', discoverySchedule);
ldcConfigGr.query();
while (ldcConfigGr.next())
ppe.addTableEntry('cmp_discovery_ldc_config',this.glideRecordToMap(ldcConfigGr));
// If we were given list of LDCs, place them on the pattern context
if (accountToLDCs[serviceAccountId]) {
var ldcGr = new GlideRecord(serviceAccountGr.datacenter_type);
ldcGr.addQuery('sys_id', 'IN', accountToLDCs[serviceAccountId]);
ldcGr.query();
while (ldcGr.next())
ppe.addTableEntry(serviceAccountGr.datacenter_type, this.glideRecordToMap(ldcGr));
}
// Now trigger each of the patterns
for (var patternIdx in patternsToRun) {
var patternSysId = patternsToRun[patternIdx];
this.runServiceAccountPattern(serviceAccountId, serviceAccountGr.name + '', discoveryStatus, statusGr.dscheduler + '', patternSysId, ppe);
}
}
},
/*
* run single pattern associated with cmdb_ci_cloud_service_account
*/
runServiceAccountPattern: function (service_account, service_account_name, status, discovery_schedule, pattern_id, ppe) {
var agent;
try {
agent = new CloudResourceDiscoveryUtil().getSelectedMidFromSchedule(discovery_schedule);
if(!agent)
agent = this.findMidByServiceAccount(service_account);
} catch (e) {
logger.warn('No MID found for service account ' + service_account + '. ' + e.getMessage());
}
if (!agent) {
logger.warn('No MID found for service account ' + service_account);
return;
}
var probeParams = {};
var cad = new CloudApplicationDiscovery();
cad.launchPatternCore(service_account, service_account_name, status, discovery_schedule, pattern_id, agent, probeParams, ppe);
},
/*
* convert glide record to javascript map
*/
glideRecordToMap: function (gr) {
var map = {};
var iterator = gr.getFields().iterator();
while (iterator.hasNext()) {
var field = iterator.next();
if (JSUtil.notNil(gr.getValue(field.getName()))) {
var fieldName = field.getName() + '';
if (fieldName.indexOf('sys_') != 0 || fieldName == 'sys_class_name' || fieldName == 'sys_id')
map[field.getName()] = gr.getValue(field.getName());
}
}
map['sys_id'] = gr.getUniqueValue();
return map;
},
/*
* DEF0107342
* Not being called
* This code should stay here for future fix
*/
findServiceAccountsByLDCs: function (ldcList) {
if (!ldcList)
return [];
var ldcArr = ldcList.split(',');
if (ldcArr.length == 0)
return [];
var serviceAccounts = [];
var relGr = new GlideRecord('cmdb_rel_ci');
relGr.addQuery('parent', 'IN', ldcArr);
relGr.addQuery('type', '5f985e0ec0a8010e00a9714f2a172815'); // Hosted-on
relGr.query();
while (relGr.next()) {
var serviceAccount = relGr.child + '';
/*
* We check if the account already exists because the same account
* can show up multiple times in cmp_discovery_ldc_config for different LDCs
* See attached pic at DEF0092784 [DEF0092784_3SubAccounts_3LDCs.png]
*/
if (serviceAccounts.indexOf(serviceAccount) == -1)
serviceAccounts.push(serviceAccount);
}
return serviceAccounts;
},
findServiceAccountsBySchedule: function (discoverySchedule) {
/*
* Checking only "Cloud Wizard" table to fetch all accounts
* PRB1310674, which was fixed in NY, is redirecting schedule creation from the service account's
* form to "Cloud Wizard", hence even old way of creating schedules will create entries
* in cmp_discovery_ldc_config from NY and above
*/
var ldcConfigGr = new GlideRecord('cmp_discovery_ldc_config');
ldcConfigGr.addQuery('discovery_schedule', discoverySchedule);
ldcConfigGr.query();
var serviceAccounts = [];
while (ldcConfigGr.next()) {
var serviceAccount = ldcConfigGr.service_account + '';
/*
* We check if the account already exists because the same account
* can show up multiple times in cmp_discovery_ldc_config for different LDCs
* See attached pic at DEF0092784 [DEF0092784_3SubAccounts_3LDCs.png]
*/
if (serviceAccounts.indexOf(serviceAccount) == -1)
serviceAccounts.push(serviceAccount);
}
return serviceAccounts;
},
type: 'CloudServiceAccountPatterns'
};
Sys ID
ba115ad9c3a123003e76741e81d3ae9d