Name
global.CloudDiscoveryScheduleConfig
Description
No description available
Script
var CloudDiscoveryScheduleConfig = Class.create();
CloudDiscoveryScheduleConfig.prototype = {
//Initializing script includes, used in this script include, globally
CLOUD_DISCOVERY_UTIL: new CloudResourceDiscoveryUtil(),
CLOUD_WIZARD_DISCOVERY: new CloudWizardDiscovery(),
initialize: function() {
this.SCHEDULE_NAME_DUPLICATION_ERR_MSG = gs.getMessage('Schedule name already exists. Provide different schedule name.');
this.VALID_GCP_PULL_EVENT_ITOM_PATTERN_VERSION = this.CLOUD_DISCOVERY_UTIL.checkSupportedPluginVersionInstalled(this.CLOUD_DISCOVERY_UTIL.ITOM_PATTERN_PLUGIN_NAME, this.CLOUD_DISCOVERY_UTIL.GCP_PULL_EVENT_SUPPORT_ITOM_PATTERN_VERSION);
//Service Account Mapping Table Name -> service_account_options , field name -> 'shouldPullEvents'
this.DB_FIELD_NAME_SHOULD_PULL_EVENTS = 'shouldPullEvents';
this.CLOUD_SERVICE_ACCOUNT_FORM_FIELDS_METADATA = this.CLOUD_DISCOVERY_UTIL.getCloudServiceAccountFormFieldsMetadata();
},
midSelectionTypeHelpText: {
"auto_select": gs.getMessage('Allow Discovery to select the MID Server automatically based on the Discovery IP Ranges you configure'),
"specific_cluster": gs.getMessage('Use a preconfigured cluster of MID Servers.'),
"specific_mid": gs.getMessage('Use only one MID Server')
},
/**
* API fetches service accounts created for the given provider
*
* @datacenterClass – Provider class for which the service account details has to be fetched eg:- cmdb_ci_aws_datacenter
*
* [{
"sysId": "",
"name": "",
"accountId": "",
"discoveryCredentials": "",
"datacenterURL": "",
"datacenterClass": "",
"isMasterAccount": false,
"parentAccount": ""
* }]
*
*/
getServiceAccountsByDatacenterType: function(datacenterClass) {
var resultForServiceAccounts = {};
var ldcServiceAccounts = [];
var serviceAccounts = [];
var serviceAccountGR = new GlideRecord('cmdb_ci_cloud_service_account');
serviceAccountGR.addQuery('datacenter_type', datacenterClass);
serviceAccountGR.addQuery('install_status', '!=', '7');
serviceAccountGR.query();
// To improve the performance Getting service account sysId whose datacenter is already discovered
var ldcGR = new GlideRecord("cmdb_rel_ci");
ldcGR.addQuery('type', this.CLOUD_DISCOVERY_UTIL.getRelTypeId('Hosted on::Hosts'));
ldcGR.addQuery('parent.sys_class_name', datacenterClass);
ldcGR.query();
while (ldcGR.next())
ldcServiceAccounts.push(ldcGR.getValue('child'));
if (serviceAccountGR.getRowCount() > 0) {
var allServiceAccountsSysIDs = [];
while (serviceAccountGR.next()) {
var currentAccountSysID = serviceAccountGR.getUniqueValue() + '';
var serviceAccount = this.getServiceAccountDetailsFromGR(serviceAccountGR);
// Hide the non master cloud service account whose "exclude_from_discovery" flag is true
if (!serviceAccount.isMasterAccount && serviceAccount.excludeFromDiscovery)
continue;
// If the datacenter is already discovered or not
serviceAccount['isDatacentersDiscovered'] = (ldcServiceAccounts.indexOf(currentAccountSysID) != -1);
serviceAccounts.push(serviceAccount);
allServiceAccountsSysIDs.push(currentAccountSysID);
}
// Get the access role information as well for the AWS specific Cloud Service Accounts to show in the CDU UI
if (datacenterClass == 'cmdb_ci_aws_datacenter')
this.getAccessRoleNameForServiceAccounts(serviceAccounts, allServiceAccountsSysIDs);
} else
resultForServiceAccounts.errorDetail = gs.getMessage('No cloud service account(s) found for the given datacenter type');
resultForServiceAccounts.allServiceAccountsInfo = serviceAccounts;
return resultForServiceAccounts;
},
getAccessRoleNameForServiceAccounts: function(serviceAccounts, allServiceAccountsSysIDs) {
var accessRoleInfo = {};
var accessRoleGR = new GlideRecord('cloud_service_account_aws_cross_assume_role_params');
accessRoleGR.addQuery('cloud_service_account', 'IN', allServiceAccountsSysIDs);
accessRoleGR.query();
while (accessRoleGR.next())
accessRoleInfo[accessRoleGR.getValue('cloud_service_account')] = accessRoleGR.getValue('access_role_name');
serviceAccounts.forEach(function(serviceAccountInfo) {
if (accessRoleInfo[serviceAccountInfo.sysId])
serviceAccountInfo['accessRoleName'] = accessRoleInfo[serviceAccountInfo.sysId];
});
},
getMemberServiceAccounts: function(masterAccount, discoverMemberAccounts, midServer) {
var resultForMemberServiceAccounts = {};
var serviceAccounts = [];
var masterAccGR = new GlideRecord('cmdb_ci_cloud_service_account');
if (masterAccGR.get(masterAccount)) {
var serviceAccountGR = new GlideRecord('cmdb_ci_cloud_service_account');
serviceAccountGR.addQuery('install_status','!=','7'); // Retired/Deleted Service Accounts should not be included in the list
serviceAccountGR.addQuery('exclude_from_discovery', false);
if (masterAccGR.getValue('datacenter_type') == 'cmdb_ci_google_datacenter' && masterAccGR.getValue('organization_id')) {
serviceAccountGR.addQuery('organization_id', masterAccGR.getValue('organization_id'));
serviceAccountGR.addQuery('sys_id', '!=', masterAccount);
serviceAccountGR.query();
} else {
serviceAccountGR.addQuery('parent_account', masterAccount);
serviceAccountGR.query();
}
if (serviceAccountGR.getRowCount() > 0) {
while (serviceAccountGR.next())
serviceAccounts.push(this.getServiceAccountDetailsFromGR(serviceAccountGR));
} else {
//If there are no member accounts present for given service account then discover them
var discoverMembers = JSUtil.toBoolean(discoverMemberAccounts);
if (discoverMembers) {
var discoveredMembers = this.getMemberAccountsForMasterViaPattern(masterAccGR.getUniqueValue() + '', midServer);
if (discoveredMembers.memberAccountDetails)
serviceAccounts = discoveredMembers.memberAccountDetails;
}
}
if (serviceAccounts.length > 0) {
var cloudAccountGR = new GlideRecord('cmdb_ci_cloud_service_account');
cloudAccountGR.get(masterAccount);
/* GCP is a special case for which discovery supports the related projects via 'organization_id' as of today and
* in the near future, Super-Sub Accounts hierarchy via Master-Member framework of Cloud Service Account.
*
* Below check is to update the master cloud service account's "is_master" flag if at all pattern misses adding that information in any case
*/
if (!cloudAccountGR.is_master_account && !(cloudAccountGR.getValue('organization_id') && (cloudAccountGR.getValue('datacenter_type') == 'cmdb_ci_google_datacenter'))){
cloudAccountGR.is_master_account = true;
cloudAccountGR.update();
}
} else
resultForMemberServiceAccounts.errorDetail = gs.getMessage('No member account(s) found for the given cloud service account');
} else
resultForMemberServiceAccounts.errorDetail = gs.getMessage('No cloud service account record found for the given sys id');
resultForMemberServiceAccounts.memberAccounts = serviceAccounts;
return resultForMemberServiceAccounts;
},
/**
* API fetches all the datacenters for the given service account
*
* @serviceAccount – service account for which the associated datacenter details has to be fetched
* @scheduleId - Discovery Schedule created for the service account. Find no. of datacenters selected for the specific schedule
*
* @Output - Marks selected field to true for the selected specific datacenters.
* [{
"sysId": "",
"name": "",
"region": "",
"selected": true/false
* }]
*
*/
getDatacentersForServiceAccount: function(serviceAccount, scheduleId) {
var resultForDatacenters = {};
var datacenters = [];
var accountGR = new GlideRecord('cmdb_ci_cloud_service_account');
if (accountGR.get(serviceAccount)) {
var ldcGR = new GlideRecord('cmdb_ci_logical_datacenter');
this.CLOUD_DISCOVERY_UTIL.queryRelCIBasedOnChild(serviceAccount, 'Hosted on::Hosts', ldcGR);
ldcGR.query();
if (ldcGR.getRowCount() > 0) {
while (ldcGR.next()) {
datacenters.push({
sysId: ldcGR.getValue('sys_id'),
objectId: ldcGR.getValue('object_id'),
name: ldcGR.getValue('name'),
region: ldcGR.getValue('region'),
selected: false
});
}
} else
resultForDatacenters.errorDetail = 'No datacenter(s) found for the given service account';
//Only if scheduleId exists, find the specific datacenters associated with the schedule and set the selected falg to true.
//If all datacenters are selected, mark selected is true for all the datacenters.
if (resultForDatacenters.datacentersList) {
var ldcConfigGR = new GlideRecord('cmp_discovery_ldc_config');
var scheduleGR = ldcConfigGR.addJoinQuery('discovery_schedule', 'discovery_schedule', 'sys_id');
ldcConfigGR.addQuery('discovery_schedule', scheduleId);
ldcConfigGR.addQuery('service_account', serviceAccount);
ldcConfigGR.query();
if (ldcConfigGR.getRowCount() > 0) {
while (ldcConfigGR.next()) {
var ldc = ldcConfigGR.getValue('ldc');
if (JSUtil.nil(ldc)) {
for (var i=0; i<datacenters.length; i++)
datacenters[i].selected = true;
} else {
var matchedIndex = datacenters.map(function(e) { return e.sysId; }).indexOf(ldcConfigGR.getValue('ldc'));
if (matchedIndex != -1)
datacenters[matchedIndex].selected = true;
}
}
}
}
} else
resultForDatacenters.errorDetail = gs.getMessage('No cloud service account found for the given sys id');
resultForDatacenters.datacentersList = datacenters;
return resultForDatacenters;
},
/**
* API fetches all the providers supported for discovery
*
* [{
"sysId": "",
"name": ""
* }]
*/
getDiscoveryProvidersList: function() {
var resultForDiscoProviders = {};
var providers = [];
var discoveryProviderGR = new GlideRecord('discovery_cloud_provider');
discoveryProviderGR.orderBy('provider');
discoveryProviderGR.query();
if (discoveryProviderGR.getRowCount() > 0) {
while (discoveryProviderGR.next()) {
this.showPullEventInServiceAccForm = false;
var capiProviderGR = new GlideRecord('sn_capi_provider');
if (capiProviderGR.get('name', discoveryProviderGR.getValue('provider'))) {
var providerInfoObj = {
sysId: capiProviderGR.getValue('sys_id'),
name: discoveryProviderGR.getValue('provider'),
datacenterClass: capiProviderGR.getValue('datacenter_class'),
credential: discoveryProviderGR.getValue('credential'),
active: capiProviderGR.getValue('active'),
fieldOptions: this.getServiceAccountFieldOptions(discoveryProviderGR.getValue('provider'), capiProviderGR.getValue('datacenter_class'))
};
if (this.showPullEventInServiceAccForm)
providerInfoObj.showPullEventInServiceAccForm = true;
providers.push(providerInfoObj);
}
}
} else
resultForDiscoProviders.errorDetail = gs.getMessage('No discovery provider(s) are found');
resultForDiscoProviders.discoveryProviders = providers;
return resultForDiscoProviders;
},
getServiceAccountFieldOptions: function(provider, datacenterClass) {
var fieldOptionsJSON = [];
var fieldOptionsGR = new GlideRecord("service_account_field_options");
fieldOptionsGR.orderBy('display_order');
fieldOptionsGR.query("provider_type.provider", provider);
while (fieldOptionsGR.next()) {
fieldOptionsObj = {
Name: fieldOptionsGR.getValue('name'),
DisplayOrder: fieldOptionsGR.getValue('display_order'),
Label: gs.getMessage('{0}', fieldOptionsGR.getValue('label')),
Mandatory: fieldOptionsGR.getValue('mandatory') == 1,
FieldType: fieldOptionsGR.getValue('field_type'),
helpText: (fieldOptionsGR.getValue('help_text')) ? gs.getMessage('{0}', fieldOptionsGR.getValue('help_text')) : '',
readOnly: fieldOptionsGR.getValue('read_only') == 1
};
if (this.DB_FIELD_NAME_SHOULD_PULL_EVENTS == fieldOptionsGR.getValue('name') && this.showPullEvent(datacenterClass) || this.DB_FIELD_NAME_SHOULD_PULL_EVENTS != fieldOptionsGR.getValue('name'))
fieldOptionsJSON.push(fieldOptionsObj);
}
return fieldOptionsJSON;
},
/**
* API fetches all the active mids (up and validated) with their capabilities
*
* [{
"sysId": "",
"name": ""
* }]
*/
getAllActiveMids: function() {
var resultForMids = {};
var midServers = [];
var midServerGR = new GlideRecord('ecc_agent');
midServerGR.addQuery('status', 'up');
midServerGR.addQuery('validated', 'true');
midServerGR.query();
if (midServerGR.getRowCount() > 0) {
while (midServerGR.next()) {
midServers.push({
sysId: midServerGR.getValue('sys_id'),
name: midServerGR.getValue('name')
});
}
} else
resultForMids.errorDetail = gs.getMessage('No active mid server(s) found');
resultForMids.mids = midServers;
return resultForMids;
},
/**
* API fetches all the active mids (up and validated) based on the capability
*
* [{
"sysId": "",
"name": ""
* }]
*/
getActiveMidsByProvider: function(provider,filter) {
var resultForMidsByProvider = {};
var midServers = [];
var filterProperty = {'AWS' : 'aws', 'Google' : 'gcp', 'Azure' : 'azure'};
var midServerGR = new GlideRecord('ecc_agent');
midServerGR.addQuery('status', 'up');
midServerGR.addQuery('validated', 'true');
var capabilityGR = midServerGR.addJoinQuery('ecc_agent_capability_m2m', 'sys_id', 'agent');
capabilityGR.addCondition('capability.capability', provider);
capabilityGR.addOrCondition('capability.capability', 'ALL');
capabilityGR.addOrCondition('capability.capability', 'Cloud Management');
if(JSUtil.toBoolean(filter))
{
var filterGR = midServerGR.addJoinQuery('ecc_agent_config','sys_id','ecc_agent');
filterGR.addCondition('param_name','CONTAINS',filterProperty[provider]);
}
midServerGR.query();
if (midServerGR.getRowCount() > 0) {
while (midServerGR.next()) {
midServers.push({
sysId: midServerGR.getValue('sys_id'),
name: midServerGR.getValue('name'),
validated: midServerGR.getDisplayValue('validated'),
status: midServerGR.getDisplayValue('status'),
hostName: midServerGR.getValue('host_name')
});
}
} else
resultForMidsByProvider.errorDetail = gs.getMessage('No active mid server(s) found for the given provider');
resultForMidsByProvider.midsInfo = midServers;
return resultForMidsByProvider;
},
/**
* API fetches all mid server clusters
*
* [{
"sysId": "",
"name": ""
* }]
*/
getMidServerClusters: function() {
var resultForMidClusters = {};
var midServerClusters = [];
var midServerClusterGR = new GlideRecord('ecc_agent_cluster');
midServerClusterGR.query();
if (midServerClusterGR.getRowCount() > 0) {
while (midServerClusterGR.next()) {
midServerClusters.push({
sysId: midServerClusterGR.getValue('sys_id'),
name: midServerClusterGR.getValue('name')
});
}
} else
resultForMidClusters.errorDetail = gs.getMessage('No mid server cluster(s) found');
resultForMidClusters.midClusters = midServerClusters;
return resultForMidClusters;
},
getMidServerClustersForProvider: function(provider) {
var midServers = this.getActiveMidsByProvider(provider,'false');
var midSysId = [];
var clusterMap = {};
if(midServers.midsInfo) {
midServers.midsInfo.forEach(function(mid) {
midSysId.push(mid.sysId);
});
}
var resultForMidClusters = {};
var midServerClusters = [];
var midServerClusterGR = new GlideRecord('ecc_agent_cluster_member_m2m');
midServerClusterGR.addQuery('agent', 'IN', midSysId);
midServerClusterGR.query();
if (midServerClusterGR.getRowCount() > 0) {
while (midServerClusterGR.next()) {
var clusterId = midServerClusterGR.getValue('cluster')
if(!clusterMap[clusterId]) {
midServerClusters.push({
sysId: clusterId,
name: midServerClusterGR.cluster.name
});
clusterMap[clusterId] = true;
}
}
} else
resultForMidClusters.errorDetail = gs.getMessage('No mid server cluster(s) found');
resultForMidClusters.midClusters = midServerClusters;
return resultForMidClusters;
},
/**
* API fetches the credentials based on the given provider
*
* @provider - provider from which the credentials has to be captured eg:- AWS/Azure/VMware
*
* [{
"sysId": "",
"name": ""
* }]
*/
getCredentialsByProvider: function(provider) {
var resultForCredentials = {};
var credentials = [];
var discoveryProviderGR = new GlideRecord('discovery_cloud_provider');
if (discoveryProviderGR.get('provider', provider)) {
var credentialGR = new GlideRecord(discoveryProviderGR.credential);
credentialGR.addQuery('active', true);
credentialGR.query();
if (credentialGR.getRowCount() > 0) {
while (credentialGR.next()) {
credentials.push({
sysId: credentialGR.getUniqueValue(),
name: credentialGR.getValue('name')
});
}
} else
resultForCredentials.errorDetail = gs.getMessage('No credential(s) found for the given provider');
} else
resultForCredentials.errorDetail = gs.getMessage('No cloud provider found with the given name');
resultForCredentials.credentialsInfo = credentials;
return resultForCredentials;
},
/**
* API fetches the datacenter info based on the provided discovery status sys id and updates 'Datacenter discovery status'
* field of the respective Cloud Service Account
*
* @statusSysId - Sys Id of the Discovery Status created for Discovery Datacenters
* @accountSysId - Sys Id of the Cloud Service Account selected
*/
getDiscoverDatacenterInfoByStatusId: function(statusSysId, accountSysId) {
var datacenterInfo ={};
var date = new GlideDateTime().getDisplayValue();
var statusObj = this.CLOUD_WIZARD_DISCOVERY.getDiscoveryResult(statusSysId);
var accountGR = this.CLOUD_DISCOVERY_UTIL.getServiceAccount(accountSysId+'');
if ((statusObj.ci_list).length > 0) {
accountGR.datacenter_discovery_status = gs.getMessage('{0}: Completed....Reload this form to see an updated datacenter list.', date);
accountGR.comments = '';
accountGR.update();
datacenterInfo = this.getDatacentersForServiceAccount(accountSysId);
}
else {
var statusError = '';
if (statusObj.hasOwnProperty('state') && (statusObj.state).equals('error'))
statusError = statusObj.state;
if ((statusObj.hasOwnProperty('error')) || (statusError.length > 0)) {
accountGR.datacenter_discovery_status = gs.getMessage('{0}: Error....', date);
accountGR.comments = statusError.length > 0 ? statusObj.message : statusObj.error;
}
accountGR.update();
datacenterInfo.statusResult = statusObj;
}
return datacenterInfo;
},
/**
* API to get the data of the fields from CDU's test account input form, whose data need not be validated with the cloud
* provider but still required for cloud service account as the cloud resources discovery patterns require that data
*
* @serviceAccountInfo - Contains information regarding the cloud service account that was intended to insert/update
*
* RESULT: { 'form_field_url' : '/bin/conf/', 'form_field_bucket_name' : 'testBucket' }
*
* form_field_url, form_field_bucket_name - are some fields where customer can add to Cloud Service Account table so we take the
* data of those fields whose name prefixes with "form_field_"
*/
_getFormFieldsDataFromCDUFormData: function(serviceAccountInfo){
var formFieldData = {};
if (this.CLOUD_SERVICE_ACCOUNT_FORM_FIELDS_METADATA instanceof Array)
(this.CLOUD_SERVICE_ACCOUNT_FORM_FIELDS_METADATA).forEach(function(fieldName) {
formFieldData[fieldName] = (serviceAccountInfo[fieldName]) ? serviceAccountInfo[fieldName] : '';
});
return formFieldData;
},
/**
* API validates the account and returns Status Sys Id after triggering Pattern's API for AWS/Azure
*
* @serviceAccountInfo - Contains information regarding the cloud service account that was intended to insert/update
*
* UI provides one more attribute - "isTimeout", if it is TRUE means User requested for Test Account with some details but that operation timed-out
* so upon retry he gets the account information instead of returning the error saying 'Account ID existing..', if pattern API is successful in the
* mean time and account is persisted. If "isTimeout" is false means its either a new request or User has changed the current detail after
* encountering the operation timed-out scenario which is an invalid/pending use case.
*
*/
initializeValidateAccount: function(serviceAccountInfo) {
var accountGR;
var serviceAccount = {};
var accountUrl = serviceAccountInfo.hasOwnProperty('datacenterURL') ? serviceAccountInfo.datacenterURL : '';
var accountName = serviceAccountInfo.hasOwnProperty('name') ? serviceAccountInfo.name : '';
var accountId = serviceAccountInfo.hasOwnProperty('accountId') ? serviceAccountInfo.accountId : '';
var accountClassType = serviceAccountInfo.hasOwnProperty('datacenterClass') ? serviceAccountInfo.datacenterClass : '';
var accountCredentialSysId = serviceAccountInfo.hasOwnProperty('discoveryCredentials') ? serviceAccountInfo.discoveryCredentials : '';
var parentAccount = serviceAccountInfo.hasOwnProperty('parentAccount') ? serviceAccountInfo.parentAccount : '';
var midServer = serviceAccountInfo.hasOwnProperty('selectedMid') ? serviceAccountInfo.selectedMid.name : '';
var accessorAccount = serviceAccountInfo.hasOwnProperty('accessorAccount') ? serviceAccountInfo.accessorAccount : '';
var midCluster = serviceAccountInfo.hasOwnProperty('selectedCluster') ? serviceAccountInfo.selectedCluster.sysId : '';
if(midCluster)
midServer = this.CLOUD_DISCOVERY_UTIL.getRandomMidFromCluster(midCluster);
// Validating Service Account ID is in proper format as per the datacenter type, if any value provided for account id
var validationMessage = 'success';
if (JSUtil.notNil(accountId)) {
validationMessage = this._validateServiceAccountInfo(serviceAccountInfo);
accountGR = this.CLOUD_DISCOVERY_UTIL.getServiceAccountByAccountID(accountId);
if (serviceAccountInfo.isTimeout && accountGR && validationMessage.equals('success') && (accountGR.is_validated == '1')) {
serviceAccount = this.getServiceAccountDetailsFromGR(accountGR);
if (serviceAccount.isMasterAccount) {
serviceAccount['membersInfo'] = [];
var childGR = this.CLOUD_DISCOVERY_UTIL.getChildServiceAccountsByParentsAccountID(accountId);
while (childGR.next())
serviceAccount.membersInfo.push(this.getServiceAccountDetailsFromGR(childGR));
}
return serviceAccount;
}
}
// The data retrieved from the CDU form, if it was provided with role name and accessor account reference and no credentials selected then only
// it's valid to create the below entries in the "cmdb_ci_cloud_service_account" and "cloud_service_account_aws_cross_assume_role_params" table.
// Along with above check we also check if the above validation is success or not because it includes the check if any other account, with same
// account id, already exists in the system or not.
var existingAccessorAccountRef = '', existingAccessRoleName = '', existingCredentialsRef = '';
if (serviceAccountInfo.accessRoleName && accessorAccount && (!accountCredentialSysId || accountCredentialSysId != 'null') && 'success'.equals(validationMessage)) {
// To support the AWS Accessor Account via CDU UI, entries in the Cloud Service Account and "AWS Cross Assume Role Params" are
// expected to be existing already because when the MID tries to validate the cloud service accounts, discover datacenter, etc,
// it uses the role to perform "AssumeRole".
// One of the inputs for the entries in the "AWS Cross Assume Role Params" table is the Service Account that uses the accessor
// account but it's the same one which the customer tries to validate. So its a kind of chicken-egg problem and for that reason,
// we create the entries in respective tables manually.
// If "serviceAccountInfo.sysId" is empty means its an "Add Account" scenario
if (!serviceAccountInfo.sysId) {
var newAccountGR = new GlideRecord('cmdb_ci_cloud_service_account');
newAccountGR.initialize();
newAccountGR.setValue('name', accountName);
newAccountGR.setValue('datacenter_type', accountClassType);
newAccountGR.setValue('account_id', accountId);
newAccountGR.setValue('datacenter_url', accountUrl);
newAccountGR.setValue('accessor_account', accessorAccount);
var newAccountSysID = newAccountGR.insert();
var newAccessRoleGR = new GlideRecord('cloud_service_account_aws_cross_assume_role_params');
newAccessRoleGR.initialize();
newAccessRoleGR.setValue('access_role_name', serviceAccountInfo.accessRoleName);
newAccessRoleGR.setValue('cloud_service_account', newAccountSysID);
newAccessRoleGR.insert();
// Post creation of account and roles, same details are synced up with the MID server so if we try to do the account
// validation same time immediately then there are situations observed where account validation is failing. For that
// reason, we explicitly added the sleep for 2 Secs expecting the sync between MID and Instance would take 1-2 Secs
gs.sleep(2000); // 2 Secs
} else {
// Following code is executed for the "Select Account" scenario
// We take the backup of existing data before we update the records with the new information customer has provided
var existingAccountGR = new GlideRecord('cmdb_ci_cloud_service_account');
if (existingAccountGR.get('sys_id', serviceAccountInfo.sysId)) {
existingAccessorAccountRef = existingAccountGR.getValue('accessor_account');
existingCredentialsRef = existingAccountGR.getValue('discovery_credentials');
existingAccountGR.setValue('accessor_account', accessorAccount);
existingAccountGR.setValue('discovery_credentials', '');
existingAccountGR.update();
}
var existingAccessRoleGR = new GlideRecord('cloud_service_account_aws_cross_assume_role_params');
if (existingAccessRoleGR.get('cloud_service_account', serviceAccountInfo.sysId)) {
// Service account having a role enabled but account is revalidated with new access role provided in the UI
// so we update respective entry
existingAccessRoleName = existingAccessRoleGR.getValue('access_role_name');
existingAccessRoleGR.setValue('access_role_name', serviceAccountInfo.accessRoleName);
existingAccessRoleGR.update();
} else {
// Service account doesn't have any role enabled but account is revalidated with new access role provided in the UI
// so we insert a new entry
existingAccessRoleGR.initialize();
existingAccessRoleGR.setValue('cloud_service_account', serviceAccountInfo.sysId);
existingAccessRoleGR.setValue('access_role_name', serviceAccountInfo.accessRoleName);
existingAccessRoleGR.insert();
}
}
}
if (validationMessage.equals('success')) {
var configObj = {
"accountName" : accountName,
"accountId": accountId,
"accountUrl": accountUrl,
"accountType": accountClassType,
"accountCredentialsId": accountCredentialSysId,
"parentAccount": parentAccount,
"accessorAccount": accessorAccount,
"existingAccessRoleName": existingAccessRoleName,
"existingAccessorAccountRef": existingAccessorAccountRef,
"existingCredentialsRef": existingCredentialsRef
};
// Before we trigger pattern to validate account, lets check if user has provided any form fields data.
// Form Fields data is a fixed/static data that are used by cloud resources discovery pattern(s) and each
// field is the actual column in the cloud service account so we need to pass that data to the patterns
// as they are responsible for inserting/updating cloud service account
var formFieldsData = this._getFormFieldsDataFromCDUFormData(serviceAccountInfo);
if (formFieldsData && (Object.keys(formFieldsData).length))
configObj['formFieldsData'] = JSON.stringify(formFieldsData);
var statusId = this.CLOUD_WIZARD_DISCOVERY.validateAccount(configObj,midServer);
if (statusId) {
serviceAccount.statusName = this.CLOUD_DISCOVERY_UTIL.getDiscoveryStatusNumber(statusId + '');
serviceAccount.statusId = statusId;
}
else
serviceAccount.errorDetail = gs.getMessage('Failed to validate account so please retry');
} else
serviceAccount.errorDetail = validationMessage;
return serviceAccount;
},
/**
* API fetches the cloud account info based on the provided discovery status sys id.
* Used during 'Test Account' and 'Refresh Members'
*
* @statusSysId - Sys Id of the Discovery Status created for Discovery Datacenters
* @accountSysId - Sys Id of the Cloud Service Account selected
*/
getServiceAccountInfoByStatusId: function(statusSysId, accountSysId, midServer) {
var serviceAccount = {};
var accountGR = '';
var statusObj = this.CLOUD_WIZARD_DISCOVERY.getDiscoveryResult(statusSysId);
var usePatternDiscovery = this.CLOUD_DISCOVERY_UTIL.getProviderUseCloudPatternProperty(accountSysId);
var discoveryPhase = this._getPhaseOfTheTriggeredPattern(statusSysId);
if (!statusObj || !statusObj.hasOwnProperty('ci_list')) {
if (!statusObj)
statusObj = {};
statusObj.message = statusObj.message || ("Here are the details of the arguments passed to this script " + JSON.stringify(statusSysId, null, 2));
serviceAccount.statusResult = statusObj;
serviceAccount['valid'] = false;
return serviceAccount;
}
if ((statusObj.ci_list).length == 0) {
var prePatternExecutionData = this._getPrePatternExecutionDataOfTheTriggeredPattern(statusSysId);
if (statusSysId && accountSysId && (discoveryPhase == 1 || discoveryPhase == 2)) {
// Below condition will be true only if the request type is "Account Validation" and "accountSysId" isn't empty
// because that means it's an "Select Account" scenario from the CDU.
// As the account validation failed, the pattern returns no reponse so then we restore the previously working accessor
// accountinformation in the Cloud Service Account table and previously working access role name in the AWS Crosss
// Assume Role Params table.
if (discoveryPhase == 1) {
if (prePatternExecutionData.existing_access_role_name && prePatternExecutionData.existing_accessor_account_ref) {
var existingAccessRoleName = prePatternExecutionData.existing_access_role_name;
var restoreAccessRoleGR = new GlideRecord('cloud_service_account_aws_cross_assume_role_params');
if (restoreAccessRoleGR.get('cloud_service_account', accountSysId) && existingAccessRoleName) {
restoreAccessRoleGR.setValue('access_role_name', existingAccessRoleName);
restoreAccessRoleGR.update();
}
var existingAccessorAccountRef = prePatternExecutionData.existing_accessor_account_ref;
var restoreAccountGR = new GlideRecord('cmdb_ci_cloud_service_account');
if (restoreAccountGR.get('sys_id', accountSysId) && existingAccessorAccountRef) {
restoreAccountGR.setValue('accessor_account', existingAccessorAccountRef);
restoreAccountGR.update();
}
} else if (prePatternExecutionData.existing_credentials_ref) {
// This use case is encountered when user tries with existing accounts, that has credentials associated,
// to use the accessor account path and if at all account validation phase fails then we restore the
// credentials reference and wipe the stub entries created as a part of accessor account validation flow
var existingCredentialsRef = prePatternExecutionData.existing_credentials_ref;
var restoreAccountGR = new GlideRecord('cmdb_ci_cloud_service_account');
if (restoreAccountGR.get('sys_id', accountSysId) && existingCredentialsRef) {
restoreAccountGR.setValue('accessor_account', '');
restoreAccountGR.setValue('discovery_credentials', existingCredentialsRef);
restoreAccountGR.update();
}
var delAccessRoleGR = new GlideRecord('cloud_service_account_aws_cross_assume_role_params');
if (delAccessRoleGR.get('cloud_service_account', accountSysId))
delAccessRoleGR.deleteRecord();
}
}
serviceAccount = this.getServiceAccountDetails(accountSysId);
if (discoveryPhase == 1) {
// It's a test account action made and it failed because of wrong credentials
serviceAccount['valid'] = false;
serviceAccount['membersInfo'] = (this.getMemberServiceAccounts(accountSysId, false, null)).memberAccounts;
} else {
// Discovery status returning no members information when 'Refresh Member Accounts'
// is clicked in the Config UI then we allow the user to proceed with schedule creation
serviceAccount['valid'] = true;
serviceAccount['membersInfo'] = [];
}
serviceAccount.statusResult = statusObj;
return serviceAccount;
}
// Fetches result for given status sys id if anything fails
if (accountSysId) {
accountGR = this.CLOUD_DISCOVERY_UTIL.getServiceAccount(accountSysId+'');
accountGR.is_validated = false;
accountGR.update();
}
// Below condition will be true only if the request type is "Account Validation" and "accountSysId" is empty
// because that means it's an "Add Account" scenario from the CDU.
// As the account validation failed, the pattern returns no reponse so then we need to delete the respective entry
// from the Cloud Service Account which inturn deletes the associated AWS Crosss Assume Role Params entry as well.
if ((discoveryPhase == 1) && !accountSysId && prePatternExecutionData.accessor_account) {
var cloudServiceAccountGR = new GlideRecord("cmdb_ci_cloud_service_account");
if (cloudServiceAccountGR.get("account_id", prePatternExecutionData.account_id))
cloudServiceAccountGR.deleteRecord();
}
serviceAccount.statusResult = statusObj;
serviceAccount['valid'] = false;
} else if ((statusObj.ci_list).length == 1) {
// Fetches result for given status sys id during 'Test Account'
serviceAccount = this.getServiceAccountDetails(statusObj.ci_list[0].sys_id);
accountGR = this.CLOUD_DISCOVERY_UTIL.getServiceAccount(serviceAccount.sysId);
accountGR.is_validated = true;
if (serviceAccount.isMasterAccount || (!serviceAccount.discoveryCredentials && serviceAccount.accessorAccount))
accountGR.parent_account = '';
// If account validation is done via Credentials and if successful then no need of accessor account
// anymore and role entry in "cloud_service_account_aws_cross_assume_role_params" table isn't required
// // so we need to wipe that information
if (accountGR.discovery_credentials) {
accountGR.accessor_account = '';
var deleteAccessRoleGR = new GlideRecord('cloud_service_account_aws_cross_assume_role_params');
if (deleteAccessRoleGR.get('cloud_service_account', serviceAccount.sysId))
deleteAccessRoleGR.deleteRecord();
// Resetting the role and accessor account information in the object which is used in the CDU UI
serviceAccount['accessRoleName'] = '';
serviceAccount['accessorAccount'] = '';
}
accountGR.update();
var isMasterAccount = serviceAccount.isMasterAccount;
var cloudAccountSysId = serviceAccount.sysId;
var gcpMemberAcc = (serviceAccount.datacenterClass == 'cmdb_ci_google_datacenter' && serviceAccount.organizationId);
// Below check avoids the infinite loop when sub-account discovery patterns return only 1 account information in the
// payload which is nothing but the account information provided in the CDU's "Test Account" form itself i.e., if
// AWS Master Account (or) Azure Management Group (or) GCP Proj belonging to Org has no sub-account(s)/related account(s)
//
// The reason why we check for the discovery phase is to validate the account and trigger for members if it's master in
// both "Add Account" and "Select Account" use case in CDU no matter if the system has the member/sub/related account(s)
// already discovered.
if ((isMasterAccount || gcpMemberAcc) && (discoveryPhase == 1)) {
var memberAccsMap = this.initializeMemberAccountDiscovery(serviceAccount, true, midServer);
serviceAccount['statusName'] = this.CLOUD_DISCOVERY_UTIL.getDiscoveryStatusNumber(memberAccsMap.statusId + '');
serviceAccount['statusId'] = memberAccsMap.statusId;
}
serviceAccount['valid'] = true;
} else if ((statusObj.ci_list).length > 1) {
// Fetches result for given status sys id during 'Refresh Members'
var allAccountsList = statusObj.ci_list;
var allAccounts = {
childAccs: [],
masterAcc: []
};
var gcpAccounts = [];
for (var i in allAccountsList) {
var accountData = this.getServiceAccountDetails(allAccountsList[i].sys_id);
if (JSUtil.notNil(accountData) && accountData.sysId != accountSysId) {
if (accountData.datacenterClass == 'cmdb_ci_google_datacenter' && accountData.organizationId)
gcpAccounts.push(accountData);
else
(accountData.isMasterAccount) ? allAccounts.masterAcc.push(accountData) : allAccounts.childAccs.push(accountData);
}
}
gcpAccounts.filter(function(gcpAcc){ return !gcpAcc.exclude_from_discovery; });
//Ignoring the member accounts whose "exclude_from_discovery" is true and show in the slush bucket accordingly
var discoverableChildAccs = [];
allAccounts.childAccs.forEach(function(childAcc) {
if(!childAcc['excludeFromDiscovery'])
discoverableChildAccs.push(childAcc);
});
allAccounts.childAccs = discoverableChildAccs;
// Updating parent_account field of master account to empty as Discover Member Accounts updates parent_account field of master account to refer to itself
if (allAccounts.masterAcc.length) {
accountGR = this.CLOUD_DISCOVERY_UTIL.getServiceAccount(allAccounts.masterAcc[0].sysId);
accountGR.parent_account = '';
accountGR.update();
serviceAccount = allAccounts.masterAcc[0];
}
serviceAccount = allAccounts.masterAcc[0] || this.getServiceAccountDetails(accountSysId) || serviceAccount;
serviceAccount['membersInfo'] = (allAccounts.hasOwnProperty('childAccs') && allAccounts.childAccs.length) ? allAccounts.childAccs : gcpAccounts;
serviceAccount['valid'] = true;
//Mark stale account as retired when property is not true and customer does Refresh Member Accounts from CDU UI
var existingMemberAccounts = (this.getMemberServiceAccounts(serviceAccount.sysId, false, midServer)).memberAccounts;
this.CLOUD_DISCOVERY_UTIL.deleteStaleAccountRecords(existingMemberAccounts, serviceAccount['membersInfo'], true, 'sysId');
//If any account which was marked stale before but is reactivated again, mark it as installed
var existingSubAccountsSysIDs = [];
var reactivatedStaleAccounts = [];
existingMemberAccounts.forEach(function(acc) { existingSubAccountsSysIDs.push(acc.sys_id ? acc.sys_id : acc.sysId); });
reactivatedStaleAccounts = serviceAccount['membersInfo'].filter(function(accObj){ return (existingSubAccountsSysIDs.indexOf(accObj.sysId) == -1); });
reactivatedStaleAccounts.forEach(function(accObj) {
//If old stale account is rediscovered again, first mark them installed
new CloudResourceDiscoveryUtil().markOldStaleInstalled(accObj, 'sysId');
});
}
return serviceAccount;
},
/**
* API initiates the member accounts discovery and returns Status Sys Id after triggering Pattern's API for AWS/Azure
*
* @discoverMemberAccounts - Boolean flag whether to discover member accounts
* @serviceAccount - A map containing the Service Account Info like AccountId, SysId, ObjectId, Name, etc.
*/
initializeMemberAccountDiscovery: function(serviceAccount, discoverMemberAccounts, midServer) {
var memberStatusSysId = '';
var resultForMemberServiceAccounts = {};
var serviceAccounts = [];
var accountSysId = serviceAccount.sysId + '';
var childAccGR = new GlideRecord('cmdb_ci_cloud_service_account');
childAccGR.addQuery('exclude_from_discovery', false);
childAccGR.addQuery('install_status','!=','7');
if (serviceAccount.datacenterClass == 'cmdb_ci_google_datacenter' && serviceAccount.organizationId) {
childAccGR.addQuery('organization_id', serviceAccount.organizationId);
childAccGR.addQuery('sys_id', '!=', accountSysId);
childAccGR.query();
} else {
childAccGR.addQuery('parent_account', accountSysId);
childAccGR.query();
}
if (discoverMemberAccounts) {
memberStatusSysId = this.CLOUD_WIZARD_DISCOVERY.refreshMemberAccounts(accountSysId + '', midServer);
resultForMemberServiceAccounts.statusName = this.CLOUD_DISCOVERY_UTIL.getDiscoveryStatusNumber(memberStatusSysId);
resultForMemberServiceAccounts.statusId = memberStatusSysId;
}
if (JSUtil.nil(memberStatusSysId)) {
//If there are no member accounts present for given service account then discover them else fetch from the table
if (childAccGR.getRowCount() > 0) {
while (childAccGR.next())
serviceAccounts.push(this.getServiceAccountDetailsFromGR(childAccGR));
} else
memberStatusSysId = this.CLOUD_WIZARD_DISCOVERY.refreshMemberAccounts(accountSysId + '', midServer);
if (serviceAccounts.length > 0) {
var cloudAccountGR = new GlideRecord('cmdb_ci_cloud_service_account');
cloudAccountGR.get(accountSysId);
/* GCP is a special case for which discovery supports the related projects via 'organization_id' as of today
* and in the near future, Super-Sub Accounts hierarchy via Master-Member framework of Cloud Service Account.
*
* Below check is to update the master cloud service account's "is_master" flag if at all pattern misses adding that information in any case
*/
if (!cloudAccountGR.is_master_account && !(cloudAccountGR.getValue('organization_id') && (cloudAccountGR.getValue('datacenter_type') == 'cmdb_ci_google_datacenter'))){
cloudAccountGR.is_master_account = true;
cloudAccountGR.update();
}
resultForMemberServiceAccounts.memberAccounts = serviceAccounts;
} else {
resultForMemberServiceAccounts.statusName = this.CLOUD_DISCOVERY_UTIL.getDiscoveryStatusNumber(memberStatusSysId);
resultForMemberServiceAccounts.statusId = memberStatusSysId;
}
}
return resultForMemberServiceAccounts;
},
/*
* When we trigger patterns for the "Test Account" Or "Refresh members" then a Discovery status is created.
* In the ECC Queue's Payload Data, we've the pattern's sys_id responsible for either account validation or
* sub accounts discovery or datacenter discovery.
*
* Once we get the pattern sys_id, we can query "sa_cloud_topology_discovery_pattern" table to know what the
* phase is i.e., if
* phase is "1" then it's "1 - Account Validation"
* phase is "2" then it's "2 - Accounts Discovery"
* phase is "3" then it's "3 - Datacenters Discovery"
*
* @statusSysID - Sys Id of the Discovery Status created for config pattern triggered
*
*/
_getPhaseOfTheTriggeredPattern: function(statusSysID) {
//Get any ECC Queue
var discoveryPhase,
eccQueueProbeParameters = this._getECCQueueProbeParametersForStatus(statusSysID);
eccQueueProbeParameters.forEach(function(probeParamObj) {
if (probeParamObj['@name'] == 'patternId') {
var patternSysID = probeParamObj['@value'];
var topologyGR = new GlideRecord('sa_cloud_topology_discovery_pattern');
if (topologyGR.get('pattern', patternSysID))
discoveryPhase = Number(topologyGR.getValue('discover_topology_type'));
}
});
return discoveryPhase;
},
_getPrePatternExecutionDataOfTheTriggeredPattern: function(statusSysID) {
var patternExecutionInfo,
eccQueueProbeParameters = this._getECCQueueProbeParametersForStatus(statusSysID);
eccQueueProbeParameters.forEach(function(probeParamObj) {
if (probeParamObj['@name'] == 'prePatternExecutionData') {
var prePatternExecutionData = probeParamObj['@value'];
if (prePatternExecutionData) {
patternExecutionInfo = JSON.parse(prePatternExecutionData);
patternExecutionInfo = (patternExecutionInfo.mapOfTables.service_account[0])[1];
}
}
});
return patternExecutionInfo;
},
_getECCQueueProbeParametersForStatus: function(statusSysID) {
var payload, eccQueueProbeParameters = [];
var eccQueueGR = new GlideRecord('ecc_queue');
eccQueueGR.addQuery('agent_correlator', statusSysID);
eccQueueGR.addQuery('queue','output');
eccQueueGR.setLimit(1);
eccQueueGR.query();
if (eccQueueGR.next())
payload = new XMLHelper().toObject('' + eccQueueGR.payload);
if (payload && payload.hasOwnProperty('parameter')) {
var probeParams = payload.parameter;
(probeParams instanceof Array) ? (eccQueueProbeParameters = probeParams) : (eccQueueProbeParameters.push(probeParams));
}
return eccQueueProbeParameters;
},
_validateServiceAccountInfo: function(serviceAccountInfo) {
var accountIDLabel;
var serviceAccountGR = new GlideRecord('cmdb_ci_cloud_service_account');
var accountId = serviceAccountInfo.accountId;
var accountClassType = serviceAccountInfo.datacenterClass;
var recordSysId = serviceAccountInfo.hasOwnProperty('sysId') ? serviceAccountInfo.sysId : '';
if (serviceAccountGR.get('account_id', accountId)) {
if (serviceAccountInfo.isTimeout)
return 'success';
accountIDLabel = this.CLOUD_DISCOVERY_UTIL.fetchLabelForServiceAccountColumnInConfigUI('accountId', accountClassType);
if (JSUtil.notNil(recordSysId)) {
if (!(serviceAccountGR.getUniqueValue()).equals(recordSysId))
return gs.getMessage('Cannot update current record as there exists another record with same {0}', accountIDLabel);
} else
return gs.getMessage('Cannot insert current record as there exists another record with same {0}', accountIDLabel);
}
return 'success';
},
validateVMWareCredentials: function(credentialId, url) {
var credentialGR = new GlideRecord('discovery_credentials');
if (credentialGR.get(credentialId)) {
var credentialData = {};
credentialData['user_name'] = credentialGR.getValue('user_name');
credentialData['password'] = new GlideEncrypter().decrypt(credentialGR.getValue('password'));
credentialData['name'] = credentialGR.getValue('name');
credentialData['type'] = 'vmware';
var ipAddress = this.CLOUD_DISCOVERY_UTIL.fetchIPFromURL(url);
var activeMIDs = this.getActiveMidsByProvider('VMWare');
if (activeMIDs.midsInfo.length == 0)
return gs.getMessage('No Active MIDs found with VMWare Capability to validate credentials.');
var eccQueueId = SNC.CredentialTest.test(JSON.stringify(credentialData), ipAddress, '443', activeMIDs.midsInfo[0].name);
var gr = this.getECCQueueRecord(eccQueueId);
while (gr.getRowCount() == 0)
gr = this.getECCQueueRecord(eccQueueId);
if (gr.next()) {
var parser = new CredentialTestParser(gr.payload);
return parser.getResult();
}
}
},
/*
vCenter URL Expected - "https://10.198.1.13/sdk" or "10.198.1.13/sdk"
Below method does the following checks for "https://10.198.1.13/sdk" format:
1. We split the given string into array so length should be 4 - [ 'https:', '', '10.198.1.13', 'sdk' ]
2. First array should be "https:" but not "https:s", "https:ss", "htttttps:" etc.
3. Last array should be "sdk" but not "sdkkk", "sdk123", etc.
and following checks if URL is provided as "10.198.1.13/sdk" format:
1. We split the given string into array so length should be 2- [ '10.198.1.13', 'sdk' ]
2. Second array should be "sdk" but not "sdk123", "sddk", "sd k:" etc.
*/
validateVMWareURL: function(url) {
var isInvalid;
var arr = url.split('/');
if (url.indexOf('https:') == -1) {
isInvalid = (arr.length != 2) || (arr[1] != 'sdk');
return (isInvalid) ? gs.getMessage('Invalid vCenter URL. Please provide a valid one in " {IP Address}/sdk " format without any braces (or) spaces.') : 'success';
} else {
isInvalid = (arr.length != 4) || (arr[0] != 'https:') || (arr[3] != 'sdk');
return (isInvalid) ? gs.getMessage('Invalid vCenter URL. Please provide a valid one in " https://{IP Address}/sdk " format without any braces (or) spaces.') : 'success';
}
},
getECCQueueRecord: function(eccQueueId) {
var gr = new GlideRecord('ecc_queue');
gr.addQuery('response_to', eccQueueId);
gr.addQuery('state', 'ready');
gr.query();
return gr;
},
saveServiceAccount: function(serviceAccountInfo) {
var accountIDLabel;
var serviceAccountSysId;
var existingServiceAccountGR;
var serviceAccount = {};
var serviceAccountGR = new GlideRecord('cmdb_ci_cloud_service_account');
var itsvCenterAccount = serviceAccountInfo.datacenterClass.equals('cmdb_ci_vcenter_datacenter');
// Validating Service Account ID is in proper format as per the datacenter type
var validationMessage = new ServiceAccountIdValidator().validateAccountId(serviceAccountInfo.accountId, serviceAccountInfo.datacenterClass);
if (validationMessage.equals('success')) {
if (itsvCenterAccount) {
// Check the URL, as datacenter discovery needs in "https://{IP Address}/sdk" format
validationMessage = this.validateVMWareURL(serviceAccountInfo.datacenterURL);
}
if (validationMessage.equals('success')) {
// As datacenter discovery needs URL in the "https://10.198.1.13/sdk" format so we prefix it with the "https://" if user provides in "10.198.1.13/sdk" format
if ((serviceAccountInfo.datacenterURL.indexOf('https:') == -1) && itsvCenterAccount)
serviceAccountInfo.datacenterURL = 'https://' + serviceAccountInfo.datacenterURL;
accountIDLabel = this.CLOUD_DISCOVERY_UTIL.fetchLabelForServiceAccountColumnInConfigUI('accountId', serviceAccountInfo.datacenterClass);
if (JSUtil.notNil(serviceAccountInfo.sysId) && serviceAccountGR.get(serviceAccountInfo.sysId)) {
serviceAccountGR = this.createServiceAccount(serviceAccountGR, serviceAccountGR.account_id, serviceAccountInfo);
existingServiceAccountGR = this.CLOUD_DISCOVERY_UTIL.getServiceAccountByAccountID(serviceAccountInfo.accountId);
if (existingServiceAccountGR && (serviceAccountGR.getUniqueValue() != existingServiceAccountGR.getUniqueValue()) )
serviceAccount.errorDetail = gs.getMessage('Cannot update current record as there exists another record with same {0}', accountIDLabel);
else
serviceAccountSysId = serviceAccountGR.update();
} else {
serviceAccountGR = this.createServiceAccount(serviceAccountGR, '', serviceAccountInfo);
existingServiceAccountGR = this.CLOUD_DISCOVERY_UTIL.getServiceAccountByAccountID(serviceAccountGR.getValue('account_id'));
if (existingServiceAccountGR)
serviceAccount.errorDetail = gs.getMessage('Cannot insert current record as there exists another record with same {0}', accountIDLabel);
else
serviceAccountSysId = serviceAccountGR.insert();
}
if (serviceAccountSysId)
serviceAccount = this.getServiceAccountDetails(serviceAccountSysId);
} else
serviceAccount.errorDetail = validationMessage;
return serviceAccount;
}
},
createServiceAccount: function(serviceAccountGR, accountId, serviceAccountInfo) {
serviceAccountGR.setValue('name', serviceAccountInfo.name);
if (JSUtil.nil(accountId) || !(accountId.equals(serviceAccountInfo.accountId)))
serviceAccountGR.setValue('account_id', serviceAccountInfo.accountId);
if (JSUtil.notNil(serviceAccountInfo.discoveryCredentials))
serviceAccountGR.setValue('discovery_credentials',serviceAccountInfo.discoveryCredentials);
serviceAccountGR.setValue('datacenter_type', serviceAccountInfo.datacenterClass);
if (JSUtil.notNil(serviceAccountInfo.datacenterURL))
serviceAccountGR.setValue('datacenter_url', serviceAccountInfo.datacenterURL);
if (JSUtil.notNil(serviceAccountInfo.isMasterAccount))
serviceAccountGR.setValue('is_master_account', serviceAccountInfo.isMasterAccount);
if (JSUtil.notNil(serviceAccountInfo.parentAccount))
serviceAccountGR.setValue('parent_account', serviceAccountInfo.parentAccount);
return serviceAccountGR;
},
getServiceAccountDetails: function(serviceAccountId) {
var serviceAccount;
var serviceAccountGR = new GlideRecord('cmdb_ci_cloud_service_account');
if (serviceAccountGR.get(serviceAccountId)) {
serviceAccount = this.getServiceAccountDetailsFromGR(serviceAccountGR);
// Fetch access role name information as well for the AWS specific Cloud Service Account
if (serviceAccount.datacenterClass == 'cmdb_ci_aws_datacenter') {
var accessRoleGR = new GlideRecord('cloud_service_account_aws_cross_assume_role_params');
if (accessRoleGR.get('cloud_service_account', serviceAccountId))
serviceAccount['accessRoleName'] = accessRoleGR.getValue('access_role_name');
}
if (this.CLOUD_SERVICE_ACCOUNT_FORM_FIELDS_METADATA instanceof Array)
(this.CLOUD_SERVICE_ACCOUNT_FORM_FIELDS_METADATA).forEach(function(fieldName) {
serviceAccount[fieldName] = serviceAccountGR.getValue(fieldName);
// If at all the form field is an boolean then we get the value as either 1 or 0
// but CDU understands only boolean value so we do the conversion
if (serviceAccount[fieldName] == 1 || serviceAccount[fieldName] == 0)
serviceAccount[fieldName] = (serviceAccount[fieldName] == 1);
});
}
return serviceAccount;
},
getServiceAccountDetailsFromGR: function(serviceAccountGR) {
var serviceAccount;
if (serviceAccountGR)
serviceAccount = {
sysId: serviceAccountGR.getUniqueValue() + '',
name: serviceAccountGR.getValue('name'),
accountId: serviceAccountGR.getValue('account_id'),
discoveryCredentials: serviceAccountGR.getValue('discovery_credentials'),
datacenterURL: serviceAccountGR.getValue('datacenter_url'),
datacenterClass: serviceAccountGR.getValue('datacenter_type'),
isMasterAccount : (serviceAccountGR.getValue('is_master_account') == 1),
parentAccount: serviceAccountGR.getValue('parent_account'),
sysUpdatedOn: serviceAccountGR.getValue('sys_updated_on'),
valid: (serviceAccountGR.getValue('is_validated') == '1'),
validatedOn: serviceAccountGR.getValue('sys_updated_on'),
organizationId: serviceAccountGR.getValue('organization_id'),
excludeFromDiscovery: (serviceAccountGR.getValue('exclude_from_discovery') == 1),
accessorAccount: serviceAccountGR.getValue('accessor_account'),
operational: (serviceAccountGR.getValue('install_status') == 1)
};
if (this.showPullEvent(serviceAccountGR.getValue('datacenter_type')))
serviceAccount.shouldPullEvents = (serviceAccountGR.getValue('should_pull_events') == '1');
return serviceAccount;
},
isServiceAccountDatacenterDiscovered: function(serviceAccount) {
var ldcGR = new GlideRecord('cmdb_ci_logical_datacenter');
this.CLOUD_DISCOVERY_UTIL.queryRelCIBasedOnChild(serviceAccount, 'Hosted on::Hosts', ldcGR);
ldcGR.setLimit(1);
ldcGR.query();
return ldcGR.getRowCount() > 0;
},
getMidSelectionMethods : function() {
var resultForMidSelectionTypes = {};
var selectionTypeList = [];
var choiceGR = new GlideRecord('sys_choice');
choiceGR.addQuery('name', 'discovery_schedule');
choiceGR.addQuery('element', 'mid_select_method');
choiceGR.addQuery('language', gs.getUser().getLanguage());
choiceGR.addQuery('value', "!=", 'behavior');
choiceGR.query();
if (choiceGR.getRowCount() > 0) {
while(choiceGR.next()) {
selectionTypeList.push({
value: choiceGR.getValue('value'),
label: choiceGR.getValue('label'),
helpText: this.midSelectionTypeHelpText[choiceGR.getValue('value')] ? this.midSelectionTypeHelpText[choiceGR.getValue('value')] : ''
});
}
} else
resultForMidSelectionTypes.errorDetail = gs.getMessage('No mid selection method(s) are found');
resultForMidSelectionTypes.midSelectTypes = selectionTypeList;
return resultForMidSelectionTypes;
},
saveCloudSchedule: function(scheduleData) {
// Below is a safety check to stop the schedule creation if a normal cloud service account or a member cloud service
// account is selected whose 'exclude_from_discovery' is "true". If it's a master account or master + member combination
// then irrespective of the flag, we just let the schedule creation progress go further.
var serviceAccInfo = this.getServiceAccountDetails(scheduleData.service_account + '');
if (!serviceAccInfo.isMasterAccount && serviceAccInfo.excludeFromDiscovery)
return { errorDetail : gs.getMessage("Selected account isn't a discoverable one")};
var activeMidsInfo;
var result = {};
var provider = this.CLOUD_DISCOVERY_UTIL.getProviderByServiceAccount(scheduleData.service_account + '');
if (provider) {
activeMidsInfo = this.getActiveMidsByProvider(provider);
if (activeMidsInfo.hasOwnProperty('errorDetail'))
return { errorDetail : activeMidsInfo.errorDetail};
}
if (JSUtil.notNil(this.CLOUD_DISCOVERY_UTIL.getCloudScheduleRecordByName(scheduleData.name, scheduleData.scheduleId))) {
result['success'] = false;
result['errorDetail'] = this.SCHEDULE_NAME_DUPLICATION_ERR_MSG;
return result;
}
if (JSUtil.nil(scheduleData.scheduleId))
result = this._createCloudSchedule(scheduleData);
else
result = this._updateCloudSchedule(scheduleData);
if (result.success) {
if (scheduleData.finishAndRun) {
var scheduleGR = this.CLOUD_DISCOVERY_UTIL.getCloudScheduleRecord(result.scheduleId);
if (scheduleGR)
var statusID = new Discovery().discoverNow(scheduleGR);
}
} else
result.errorDetail = result.message;
return result;
},
_createCloudSchedule: function(scheduleData) {
var ciScheduleId = '';
if (scheduleData.runType.equals('periodically') && JSUtil.nil(scheduleData.runPeriod)) {
return {
success: false,
message: gs.getMessage('Run period must not be empty')
};
}
var accelConfig = this._saveAcceleratorConfig(scheduleData);
var scheduleRecord = new GlideRecord('discovery_schedule');
scheduleRecord.initialize();
scheduleRecord = this._createScheduleGlideRecord(scheduleRecord, scheduleData);
scheduleRecord.setValue('discover', 'Cloud Resources');
scheduleRecord.setValue('accel_config', accelConfig);
if (scheduleData.is_Discover_VM) {
ciScheduleId = this._createCISchedule(scheduleData);
scheduleRecord.setValue('vm_run', ciScheduleId);
}
var scheduleId = scheduleRecord.insert();
scheduleData['scheduleId'] = scheduleId;
this._createCloudDiscoveryLDCConfig(scheduleData);
if (JSUtil.notNil(ciScheduleId))
this._updateCISchedule(ciScheduleId, scheduleId);
return {
success: true,
scheduleId:scheduleId,
message: ''
};
},
_updateCloudSchedule: function(scheduleData) {
var scheduleId;
var scheduleRecord = this.CLOUD_DISCOVERY_UTIL.getCloudScheduleRecord(scheduleData.scheduleId);
scheduleRecord = this._createScheduleGlideRecord(scheduleRecord, scheduleData);
this._updateAcceleratorConfig(scheduleData, scheduleRecord.getValue('accel_config'));
if (scheduleData.is_Discover_VM) {
if (JSUtil.notNil(scheduleRecord.getValue('vm_run')))
this._updateMidCISchedule(scheduleData, scheduleRecord.getValue('vm_run'));
else {
var ciScheduleId = this._createCISchedule(scheduleData);
scheduleRecord.setValue('vm_run', ciScheduleId);
if (JSUtil.notNil(ciScheduleId))
this._updateCISchedule(ciScheduleId, scheduleData.scheduleId);
}
} else {
if (JSUtil.notNil(scheduleRecord.getValue('vm_run'))) {
this._removeSchedule(scheduleRecord.getValue('vm_run'));
scheduleRecord.setValue('vm_run', null);
}
}
scheduleId = scheduleRecord.update();
// To Do we need to run clean up operation based on flag
this._removeCloudDiscoveryLDCConfig(scheduleData.scheduleId);
this._createCloudDiscoveryLDCConfig(scheduleData);
return {
success: true,
scheduleId:scheduleId,
message: ''
};
},
_saveAcceleratorConfig: function(scheduleData) {
var accelRunGlideRecord = new GlideRecord('discovery_accel_config');
accelRunGlideRecord.initialize();
accelRunGlideRecord = this._createAcceleratorConfigGlideRecord(accelRunGlideRecord, scheduleData);
return accelRunGlideRecord.insert();
},
_updateAcceleratorConfig: function(scheduleData, accel_config) {
var accelRunGlideRecord = new GlideRecord('discovery_accel_config');
accelRunGlideRecord.get(accel_config);
accelRunGlideRecord = this._createAcceleratorConfigGlideRecord(accelRunGlideRecord, scheduleData);
return accelRunGlideRecord.update();
},
_createScheduleGlideRecord: function(scheduleRecord, scheduleData) {
scheduleRecord.setValue('name', scheduleData.name);
scheduleRecord.setValue('disco_run_type',scheduleData.runType);
scheduleRecord.setValue('active', scheduleData.active);
var midSelectMethod = scheduleData.mid_select_method_for_cloud;
if(JSUtil.notNil(midSelectMethod)) {
scheduleRecord.setValue('mid_select_method',midSelectMethod);
if ( midSelectMethod.equals('specific_mid') && JSUtil.notNil(scheduleData.mid_server_for_cloud))
scheduleRecord.setValue('mid_server', scheduleData.mid_server_for_cloud);
else if(midSelectMethod.equals('specific_cluster') && JSUtil.notNil(scheduleData.mid_cluster_for_cloud))
scheduleRecord.setValue('mid_cluster', scheduleData.mid_cluster_for_cloud);
else
scheduleRecord.setValue('mid_server', '');
}
if (JSUtil.notNil(scheduleData.script))
scheduleRecord.setValue('script', scheduleData.script);
if (JSUtil.notNil(scheduleData.runPeriod))
scheduleRecord.setValue('run_period', new GlideDateTime(scheduleData.runPeriod));
else
scheduleRecord.setValue('run_period', '');
if (JSUtil.notNil(scheduleData.runStart))
scheduleRecord.setValue('run_start', new GlideDateTime(scheduleData.runStart));
if (JSUtil.notNil(scheduleData.runTime))
scheduleRecord.setValue('run_time', scheduleData.runTime);
if (JSUtil.notNil(scheduleData.runDayOfWeek))
scheduleRecord.setValue('run_dayofweek', scheduleData.runDayOfWeek);
if (JSUtil.notNil(scheduleData.runDayOfMonth))
scheduleRecord.setValue('run_dayofmonth', scheduleData.runDayOfMonth);
if (JSUtil.notNil(scheduleData.maxRun))
scheduleRecord.setValue('max_run', new GlideDateTime(scheduleData.maxRun));
else
scheduleRecord.setValue('max_run', new GlideDateTime(new Date(0)));
return scheduleRecord;
},
_createAcceleratorConfigGlideRecord: function(accelRunGlideRecord, scheduleData) {
accelRunGlideRecord.setValue('active', scheduleData.active);
accelRunGlideRecord.setValue('run_type',scheduleData.runType);
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
accelRunGlideRecord.setValue('max_run', new GlideDateTime(new Date(0)));
return accelRunGlideRecord;
},
_createCloudDiscoveryLDCConfig: function(scheduleData) {
var service_accounts = [];
service_accounts.push({
sysId: scheduleData.service_account + ''
});
if (scheduleData.all_accounts_for_master) {
var usePatternDiscovery = this.CLOUD_DISCOVERY_UTIL.getProviderUseCloudPatternProperty(scheduleData.service_account);
if (usePatternDiscovery) {
var members = (this.getMemberServiceAccounts(scheduleData.service_account, false, null)).memberAccounts;
service_accounts = service_accounts.concat(members);
}
} else if (scheduleData.member_accounts)
service_accounts = service_accounts.concat(scheduleData.member_accounts);
if (scheduleData.all_datacenter) {
for (var accountIndex in service_accounts)
this._saveCloudDiscoveryLDCConfig(service_accounts[accountIndex].sysId, scheduleData.scheduleId, "", scheduleData.all_accounts_for_master);
} else {
for (var account in service_accounts) {
for (var ldc in scheduleData.datacenters) {
if (scheduleData.datacenters[ldc].selected)
this._saveCloudDiscoveryLDCConfig(service_accounts[account].sysId, scheduleData.scheduleId, scheduleData.datacenters[ldc].name, scheduleData.all_accounts_for_master);
}
}
}
},
_saveCloudDiscoveryLDCConfig: function(service_account, scheduleId, ldc, all_accounts_for_master) {
// Returning as we don't want to create ldc config with empty account details.
if(!JSUtil.notNil(service_account))
return;
var ldcId = "";
if(JSUtil.notNil(ldc))
ldcId = this.CLOUD_DISCOVERY_UTIL.getLogicalDatacentersByNameAndServiceAccount(service_account, ldc);
var gr = new GlideRecord('cmp_discovery_ldc_config');
gr.initialize();
gr.setValue('service_account', service_account);
gr.setValue('discovery_schedule', scheduleId);
if (JSUtil.notNil(ldcId))
gr.setValue('ldc', ldcId);
if (JSUtil.notNil(all_accounts_for_master))
gr.setValue('all_accounts_for_master', all_accounts_for_master);
return gr.insert();
},
_removeCloudDiscoveryLDCConfig: function(scheduleId) {
var gr = new GlideRecord('cmp_discovery_ldc_config');
gr.query('discovery_schedule', scheduleId);
gr.deleteMultiple();
},
_createCISchedule: function(scheduleData) {
var gr = new GlideRecord('discovery_schedule');
gr.initialize();
gr.setValue('discover', 'CIs');
gr.setValue('disco_run_type', 'after_discovery');
gr = this._createCIScheduleGlideRecord(gr, scheduleData);
return gr.insert();
},
_updateCISchedule: function(ciScheduleId, scheduleId) {
var gr = new GlideRecord('discovery_schedule');
if (ciScheduleId && gr.get('sys_id', ciScheduleId)) {
gr.setValue('run_after', scheduleId);
return gr.update();
}
},
_updateMidCISchedule: function(scheduleData, scheduleId) {
var gr = new GlideRecord('discovery_schedule');
if (scheduleId)
gr.get('sys_id', scheduleId);
gr = this._createCIScheduleGlideRecord(gr, scheduleData);
return gr.update();
},
_createCIScheduleGlideRecord: function(gr, scheduleData) {
gr.setValue('name', scheduleData.name+'- VM schedule');
gr.setValue('mid_select_method', scheduleData.mid_select_method);
if ( scheduleData.mid_select_method.equals('specific_cluster') && JSUtil.notNil(scheduleData.mid_cluster) )
gr.setValue('mid_cluster', scheduleData.mid_cluster);
else if ( scheduleData.mid_select_method.equals('specific_mid') && JSUtil.notNil(scheduleData.mid_server) )
gr.setValue('mid_server', scheduleData.mid_server);
return gr;
},
_removeSchedule: function(scheduleId) {
var gr = new GlideRecord('discovery_schedule');
if (scheduleId && gr.get('sys_id', scheduleId))
gr.deleteRecord();
},
getCloudSchedule: function(scheduleId) {
var cloudScheduleInfo = {};
var accelGlideRecord;
var is_Discover_VM = false;
var mid_select_type = '';
var mid_cluster = '';
var mid_server = '';
var provider = '';
var mid_select_method_for_cloud = '';
var mid_server_for_cloud = '';
var mid_cluster_for_cloud = '';
var scheduleRecord = this.CLOUD_DISCOVERY_UTIL.getCloudScheduleRecord(scheduleId);
if (scheduleRecord) {
var configData = new DiscoveryCloudConfig().getConfig(scheduleId);
if (JSUtil.notNil(scheduleRecord.getValue('accel_config')))
accelGlideRecord = this.CLOUD_DISCOVERY_UTIL.getAcceleratorConfigRecord(scheduleRecord.getValue('accel_config'));
if (JSUtil.notNil(scheduleRecord.getValue('vm_run'))) {
is_Discover_VM = true;
var ipScheduleRecord = this.CLOUD_DISCOVERY_UTIL.getCloudScheduleRecord(scheduleRecord.getValue('vm_run'));
mid_select_type = ipScheduleRecord.getValue('mid_select_method');
mid_cluster = ipScheduleRecord.getValue('mid_cluster');
mid_server = ipScheduleRecord.getValue('mid_server');
}
if(JSUtil.notNil(scheduleRecord.getValue('mid_select_method'))) {
mid_select_method_for_cloud = scheduleRecord.getValue('mid_select_method');
mid_server_for_cloud = scheduleRecord.getValue('mid_server');
mid_cluster_for_cloud = scheduleRecord.getValue('mid_cluster');
}
if (configData.service_account)
provider = this.CLOUD_DISCOVERY_UTIL.getProviderByServiceAccount(configData.service_account.sys_id);
//Building the data as a response to the API call
cloudScheduleInfo.scheduleId = scheduleId;
cloudScheduleInfo.name = scheduleRecord.getValue('name');
cloudScheduleInfo.provider = provider;
cloudScheduleInfo.service_account = configData.service_account;
cloudScheduleInfo.all_datacenter = configData.all_datacenters;
cloudScheduleInfo.all_accounts_for_master = configData.all_accounts_for_master;
cloudScheduleInfo.member_accounts = configData.member_accounts;
cloudScheduleInfo.datacenters = configData.datacenters;
cloudScheduleInfo.is_Discover_VM = is_Discover_VM;
cloudScheduleInfo.vm_run = scheduleRecord.getValue('vm_run');
cloudScheduleInfo.runAfter = scheduleRecord.getValue('run_after');
cloudScheduleInfo.mid_selection_type = mid_select_type;
cloudScheduleInfo.mid_cluster = mid_cluster;
cloudScheduleInfo.mid_server = mid_server;
cloudScheduleInfo.mid_select_method_for_cloud = mid_select_method_for_cloud;
cloudScheduleInfo.mid_server_for_cloud = mid_server_for_cloud;
cloudScheduleInfo.mid_cluster_for_cloud = mid_cluster_for_cloud;
if (accelGlideRecord) {
cloudScheduleInfo.active = accelGlideRecord.active + '';
cloudScheduleInfo.runType = accelGlideRecord.run_type + '';
cloudScheduleInfo.runTime = accelGlideRecord.run_time + '';
cloudScheduleInfo.runPeriod = accelGlideRecord.run_period + '';
cloudScheduleInfo.runStart = accelGlideRecord.run_start + '';
cloudScheduleInfo.runDayOfWeek = parseInt(accelGlideRecord.run_dayofweek, 10) || 1;
cloudScheduleInfo.runDayOfMonth = parseInt(accelGlideRecord.run_dayofmonth, 10) || 1;
cloudScheduleInfo.maxRun = accelGlideRecord.max_run + '';
}
} else
cloudScheduleInfo.errorDetail = 'No discovery schedule found for the given sys id';
return cloudScheduleInfo;
},
_resolveCloudType: function(dcType) {
// locate the cloud provider type from the datacenter class name
var cloudProvider = new GlideRecord('sn_capi_provider');
var cloudType = cloudProvider.get('datacenter_class', dcType) ? cloudProvider.getValue('name') : '';
return cloudType;
},
_getOrderStatus: function(orderSysID) {
var orderGR = new GlideRecord('sn_cmp_order');
if (orderGR.get(orderSysID))
return Number(orderGR.getValue('status'));
return null;
},
// Scripted REST APIs util functions for backward compatibility
getMemberAccountsRESTUtil : function(parentAccount, discoverMembers, selectedMidServer, isClusterSelected) {
var selectedMid = this.getMidForDiscoveryJob(selectedMidServer, isClusterSelected);
return this.getMemberServiceAccounts(parentAccount, JSUtil.toBoolean(discoverMembers), selectedMid);
},
getDiscoveredDataCenterRESTUtil : function(serviceAccountSysId, discoverDatacenters, selectedMidServer, clusterSelected) {
var midServer = this.getMidForDiscoveryJob(selectedMidServer, clusterSelected);
return this.getOrRefreshDatacenters(serviceAccountSysId, discoverDatacenters, midServer);
},
getMasterAccountRESTUtil : function(parentAccount, selectedMidServer, clusterSelected) {
var serviceAccountObj = this.getServiceAccountDetails(parentAccount);
var midServer = this.getMidForDiscoveryJob(selectedMidServer, clusterSelected);
return this.initializeMemberAccountDiscovery(serviceAccountObj, true, midServer);
},
getMidForDiscoveryJob : function(selectedMidServer, clusterSelected) {
var midServer = selectedMidServer != 'null'? selectedMidServer : null;
if (clusterSelected)
midServer = new CloudResourceDiscoveryUtil().getRandomMidFromCluster(midServer);
return midServer;
},
// TODO: THIS METHOD HAS TO BE DELETED ONCE IT'S USAGE in 'sys_ui_action_01c24d9ceb01320047f6a5115206fe93' FILE, IS REPLACED WITH 'getOrRefreshDatacenters'
discoverDatacenters: function(serviceAccountSysId) {
if (!serviceAccountSysId)
throw gs.getMessage('Missing mandatory parameter service account id');
var accountGr = new GlideRecord('cmdb_ci_cloud_service_account');
accountGr.get(serviceAccountSysId);
if (!accountGr.isValidRecord())
throw gs.getMessage('Invalid service account Id - {0}', serviceAccountSysId);
return this.discoverDatacentersViaCapi(serviceAccountSysId);
},
/*
* As the usage of 'discoverDatacentersViaPattern' method is deprecated and datacenter discovery for all clouds except vmware
* should go with patterns, this method takes care of discovering datacenters
*/
getOrRefreshDatacenters: function(serviceAccountSysId, discoverDatacenters, midServer, subAccounts) {
var accountGr = new GlideRecord('cmdb_ci_cloud_service_account');
if (!(accountGr.get(serviceAccountSysId)))
return { errorDetail : gs.getMessage('Provided account with SysId-{0} does not exist', serviceAccountSysId) };
var dcType = accountGr.datacenter_type;
var datacentersDetails = this.getDatacentersForServiceAccount(serviceAccountSysId, '');
if ( discoverDatacenters || (datacentersDetails.datacentersList.length == 0)) {
try {
if (dcType.equals('cmdb_ci_vcenter_datacenter')) {
datacentersDetails = this.discoverDatacentersViaCapi(serviceAccountSysId);
if (datacentersDetails.hasOwnProperty('error'))
return { errorDetail : datacentersDetails.error};
} else {
var statusId = this.CLOUD_WIZARD_DISCOVERY.refreshDatacenters(serviceAccountSysId, midServer, subAccounts);
return {
resultData : {
statusName: this.CLOUD_DISCOVERY_UTIL.getDiscoveryStatusNumber(statusId),
statusId: statusId
}
};
}
} catch (err) {
return { errorDetail : err};
}
}
if (datacentersDetails.hasOwnProperty('datacentersList'))
return { resultData : datacentersDetails.datacentersList };
else
return { resultData : datacentersDetails };
},
_waitTillDiscoveryCompletes: function(statusId) {
var resultObj = this.CLOUD_WIZARD_DISCOVERY.getDiscoveryResult(statusId);
while (resultObj.state == 'processing') {
this.sleep(2000);
resultObj = this.CLOUD_WIZARD_DISCOVERY.getDiscoveryResult(statusId);
}
return resultObj;
},
/**
* API discovers and fetches all the datacenters via CAPI, for the given service account
*
* @serviceAccountSysID – service account for which discovery has to be triggered and respective datacenters have to be fetched.
*/
discoverDatacentersViaCapi: function(serviceAccountSysID) {
var result = {};
var serviceAccountGR = new GlideRecord('cmdb_ci_cloud_service_account');
if (serviceAccountGR.get(serviceAccountSysID)) {
//let's check if we have a valid mid server
var capiSvrScript = new sn_cloud_api.CAPIOrchestratorServiceScript();
try {
var cloudType = this._resolveCloudType(serviceAccountGR.datacenter_type);
capiSvrScript.resolveMid('', cloudType, '');
} catch(e) {
result.error = e.message;
return result;
}
//Querying resourceblock for the specific datacenter type
var resource = '';
var resourceblockGR = new GlideRecord('sn_cmp_rb_resourceblock');
if (resourceblockGR.get('refcitype', serviceAccountGR.datacenter_type))
resource = resourceblockGR.name+'';
if (!resource) {
result.error = gs.getMessage('Cannot find resource type for {0}', serviceAccountGR.datacenter_type);
return result;
}
//Placing an order to discover the datacenters
var orderScript = new sn_cmp_api.OrderServiceScript();
var order = {'resource':resource, 'entityType':'Resource', 'operationName':'Discovery Interface.ListDatacenters',
orderFormData:{'CloudServiceAccountId':serviceAccountGR.account_id+'',
'Credential':serviceAccountGR.discovery_credentials.sys_id+''}};
var orderJson = orderScript.submitOrder(new global.JSON().encode(order));
//Checking status of the order recursivly until order's state is "Rejected" / "Cancelled" / "Completed" / "Error"
var orderObj = new global.JSON().decode(orderJson);
var status = this._getOrderStatus(orderObj.id);
while (!(status == 4 || status == 5 || status == 7 || status == 8)) {
this.sleep(2000);
status = this._getOrderStatus(orderObj.id);
}
result = this.getDatacentersForServiceAccount(serviceAccountSysID);
result.order = orderObj;
return result;
}
},
getListofIPAddressesForVMSchedule: function(vmScheduleId) {
var ipAddressList = [];
//fetch service account for the given vm schedule based on the parent cloud schedule
var scheduleGR = new GlideRecord('discovery_schedule');
scheduleGR.addQuery('vm_run', vmScheduleId);
scheduleGR.addQuery('discover', 'Cloud Resources');
scheduleGR.query();
if (scheduleGR.next()) {
var parentScheduleId = scheduleGR.getUniqueValue();
var configData = new DiscoveryCloudConfig().getConfig(parentScheduleId);
var datacenterType = configData.service_account.datacenter_type;
var serviceAccountId = configData.service_account.sys_id;
this.fetchIPByLDC(serviceAccountId, configData.datacenters, ipAddressList, datacenterType);
//is_master_account will always be false for the GCP cloud discovery schedule though it has siblings account.
//Hence, an additional check is included for GCP cloud discovery in order to fetch the IP addresses of the VMs
//that are in all the projects
if (configData.is_master_account || (datacenterType == 'cmdb_ci_google_datacenter' && configData.service_account.organization_id)) {
var membersAccounts = configData.all_accounts_for_master ? this.getMemberServiceAccounts(serviceAccountId, false, null).memberAccounts : configData.member_accounts;
for (var i in membersAccounts) {
var memberServiceAccountId = membersAccounts[i].sys_id ? membersAccounts[i].sys_id : membersAccounts[i].sysId;
this.fetchIPByLDC(memberServiceAccountId, configData.datacenters, ipAddressList, datacenterType);
}
}
}
// Final check for removing the duplicates before so that IPs, added for the deep discovery, aren't redundant.
ipAddressList = ipAddressList.filter(function(ip, index){
return (ipAddressList.indexOf(ip) == index);
});
return ipAddressList;
},
fetchIPByLDC: function(serviceAccountId, selectedDCs, ipAddressList, datacenterType) {
if (selectedDCs) {
var ldcNames = [];
for (var i in selectedDCs)
ldcNames.push(selectedDCs[i].name + '');
// Apart from Normal Schedule, In the combination of Master Member especially when exclude_from_discovery=true
// for master accountThe Datacenters provided
var relGR = new GlideRecord('cmdb_rel_ci');
relGR.addQuery('child', serviceAccountId);
relGR.addQuery('type', this.CLOUD_DISCOVERY_UTIL.getRelTypeId('Hosted on::Hosts'));
relGR.addQuery('parent.name', 'IN', ldcNames);
relGR.query();
while (relGR.next())
this.populateIPAddressList(relGR.getValue('parent'), ipAddressList, datacenterType);
} else {
var ldcGR = new GlideRecord('cmdb_ci_logical_datacenter');
this.CLOUD_DISCOVERY_UTIL.queryRelCIBasedOnChild(serviceAccountId, 'Hosted on::Hosts', ldcGR);
ldcGR.query();
while (ldcGR.next())
this.populateIPAddressList(ldcGR.getUniqueValue(), ipAddressList, datacenterType);
}
},
populateIPAddressList: function(ldcId, ipAddressList, datacenterType) {
if (datacenterType.equals('cmdb_ci_vcenter_datacenter'))
this.fetchIPAddressesForVMWare(ldcId, ipAddressList);
else {
var nicGR,
vmSysIDsList = [],
nicIdList = [];
//get all vms hosted on given LDC and feth the public_ip of the selected vm.
var vmGR = new GlideRecord('cmdb_ci_vm_instance');
vmGR.addQuery('state', 'on');
this.CLOUD_DISCOVERY_UTIL.queryRelCIBasedOnChild(ldcId, 'Hosted on::Hosts', vmGR);
vmGR.query();
while (vmGR.next()) {
vmSysIDsList.push(vmGR.getUniqueValue());
var enic= new GlideRecord('cmdb_ci_endpoint_vnic');
this.CLOUD_DISCOVERY_UTIL.queryRelCIBasedOnParent(vmGR.getUniqueValue(), 'Use End Point To::Use End Point From', enic);
enic.query();
while (enic.next())
enic.getValue('object_id') ? nicIdList.push(enic.getValue('object_id')) : '';
}
if (nicIdList.length) {
nicGR = new GlideRecord('cmdb_ci_nic');
nicGR.addQuery('object_id', 'IN', nicIdList);
nicGR.addNullQuery('cmdb_ci');
nicGR.query();
this._addIPsToTheList(nicGR, ipAddressList);
}
if (vmSysIDsList.length) {
nicGR = new GlideRecord('cmdb_ci_nic');
nicGR.addQuery('cmdb_ci', 'IN', vmSysIDsList);
nicGR.query();
this._addIPsToTheList(nicGR, ipAddressList);
}
}
},
_addIPsToTheList: function(nicGR, ipAddressList) {
while (nicGR.next()) {
if (JSUtil.notNil(nicGR.public_ip))
ipAddressList.push(nicGR.getValue('public_ip'));
if (JSUtil.notNil(nicGR.ip_address))
ipAddressList.push(nicGR.getValue('ip_address'));
if (JSUtil.notNil(nicGR.private_ip))
ipAddressList.push(nicGR.getValue('private_ip'));
}
},
fetchIPAddressesForVMWare: function(ldcId, ipAddressList) {
var vmSysIDsList = [];
var datastoreGR = new GlideRecord('cmdb_ci_vcenter_datastore');
this.CLOUD_DISCOVERY_UTIL.queryRelCIBasedOnParent(ldcId, 'Contains::Contained by', datastoreGR);
datastoreGR.query();
while (datastoreGR.next()) {
var vmGR = new GlideRecord('cmdb_ci_vm_instance');
this.CLOUD_DISCOVERY_UTIL.queryRelCIBasedOnParent(datastoreGR.sys_id, 'Provides storage for::Stored on', vmGR);
vmGR.query();
while (vmGR.next())
vmSysIDsList.push(vmGR.getUniqueValue());
}
var nicGR = new GlideRecord('cmdb_ci_nic');
nicGR.addQuery('cmdb_ci', 'IN', vmSysIDsList);
nicGR.query();
this._addIPsToTheList(nicGR, ipAddressList);
// Remove the duplicates
return new DiscoArrayUtil().unique(ipAddressList);
},
sleep : function (ms) {
Packages.java.lang.Thread.sleep(ms);
},
/**
* BELOW API IS A TEMPORARY API FOR BACKUP PURPOSE AND CONTINUOUS SUPPORT BY OWNER CANNOT BE GUARANTEED
* SO IT'S RECOMMENDED NOT TO BE USED
*
* FUNCTIONALITY: Validate Cloud Service Account via Pattern's API
*/
validateAndSaveServiceAccountViaPattern: function(serviceAccountInfo) {
var recordSysId = serviceAccountInfo.hasOwnProperty('sysId') ? serviceAccountInfo.sysId : '';
var cloudAccountValidateRequest = this.initializeValidateAccount(serviceAccountInfo);
if (cloudAccountValidateRequest.hasOwnProperty('statusId')) {
var discoveryStatusId = cloudAccountValidateRequest.statusId;
this._waitTillDiscoveryCompletes(discoveryStatusId);
var resultObj = this.getServiceAccountInfoByStatusId(discoveryStatusId, recordSysId, null);
if ((!resultObj.valid) || resultObj.hasOwnProperty('membersInfo'))
return resultObj;
if (resultObj.hasOwnProperty('statusId')) {
var tempDiscoveryStatusId = resultObj.statusId;
this._waitTillDiscoveryCompletes(tempDiscoveryStatusId);
var resultObj2 = this.getServiceAccountInfoByStatusId(discoveryStatusId, recordSysId, null);
if (resultObj2.hasOwnProperty('membersInfo'))
return resultObj2;
}
} else
return cloudAccountValidateRequest;
},
/**
* BELOW API IS A TEMPORARY API FOR BACKUP PURPOSE AND CONTINUOUS SUPPORT BY OWNER CANNOT BE GUARANTEED
* SO IT'S RECOMMENDED NOT TO BE USED
*
* FUNCTIONALITY: Discovers and fetches all the datacenters via Patterns, for the given service account
*/
discoverDatacentersViaPattern: function(accountSysId) {
var datacentersList = [];
var statusId = this.CLOUD_WIZARD_DISCOVERY.refreshDatacenters(accountSysId);
var resultObj = this._waitTillDiscoveryCompletes(statusId);
if (resultObj.ci_list.length > 0)
return this.getDatacentersForServiceAccount(accountSysId);
else
return resultObj;
},
/**
* BELOW API IS A TEMPORARY API FOR BACKUP PURPOSE AND CONTINUOUS SUPPORT BY OWNER CANNOT BE GUARANTEED
* SO IT'S RECOMMENDED NOT TO BE USED
*
* FUNCTIONALITY: Discovers the member accounts via Patterns, for the given master account.
*/
getMemberAccountsForMasterViaPattern: function(accountSysId, midServer) {
var resultForMemberAccounts = {};
var serviceAccount = this.getServiceAccountDetails(accountSysId);
var discoveryStatusSysId = (this.initializeMemberAccountDiscovery(serviceAccount, true, midServer)).statusId;
this._waitTillDiscoveryCompletes(discoveryStatusSysId);
var statusResult = this.getServiceAccountInfoByStatusId(discoveryStatusSysId, accountSysId, midServer);
resultForMemberAccounts.memberAccountDetails = statusResult.membersInfo;
return resultForMemberAccounts;
},
isMigrated : function(provider) {
var result = false;
if(provider == 'Google') {
result = true;
}
else {
var patternSysIdObj = {
'AWS' : '23881e159fc5320048111f80a57fcfde',
'Azure' : 'b3e27695d730320097eb6ccf6e61034e'
};
if(Object.keys(patternSysIdObj).indexOf(provider) != -1) {
var gr = new GlideRecord('sn_cmp_rb_op_impl_step');
gr.addQuery('sys_id', patternSysIdObj[provider]);
gr.query()
if(gr.next())
result = gr.getValue('enabled') == "0" ? true : false;
}
}
return {result : result}
},
/**
The following condition should be matching for showing GCP pull event option in the service account form
1.'Discovery and Service Mapping' plugin is installed and its version should be '1.0.42'/more
2.CI class is equal to CMDB_CI_GOOGLE_DATACENTER
3.Field name is equal to shouldPullEvents(This field is showing in the service account form, once installed the discovery and service mapping plugin)
@Arg1 -> Datacenter CI class
**/
showPullEvent: function(datacenterClass) {
var isShowPullEventInServiceAccForm = (datacenterClass == this.CLOUD_DISCOVERY_UTIL.CMDB_CI_GOOGLE_DATACENTER && this.VALID_GCP_PULL_EVENT_ITOM_PATTERN_VERSION) || (datacenterClass != this.CLOUD_DISCOVERY_UTIL.CMDB_CI_GOOGLE_DATACENTER);
if (isShowPullEventInServiceAccForm)
this.showPullEventInServiceAccForm = true;
return isShowPullEventInServiceAccForm;
},
updateServiceAccount: function(cloudAccountData) {
var serviceAccountGR = new GlideRecord('cmdb_ci_cloud_service_account');
serviceAccountGR.query('datacenter_type', cloudAccountData.datacenterClass);
serviceAccountGR.query('sys_id', cloudAccountData.sysId);
if (serviceAccountGR.next()) {
serviceAccountGR.setValue('should_pull_events', cloudAccountData.shouldPullEvents);
serviceAccountGR.update();
}
},
type: 'CloudDiscoveryScheduleConfig'
};
Sys ID
96891f3953f313007f3c48f153dc348b