Name
sn_cmp.CMPCIRelationshipUtil
Description
No description available
Script
var CMPCIRelationshipUtil = Class.create();
CMPCIRelationshipUtil.prototype = {
initialize: function () {
},
/**
* Infers an eventual LDC on which a particular CI is hosted.
* A general approach is to follow a bunch of HostedOn:Hosts relationships all the way from the top and locate the
* eventual LDC. However for some CIs/Resource Blocks , this might not be the case. For example: Subnets have a
* Contains:ContainedBy relationship with Network.
* This script implements the general method to reach the LDC given a CI, however customizations can be made for
* specific CIs here.
**/
ldcIdForConfigurationItem: function (ciId) {
gs.info("Debugging for CI: " + ciId);
var ldcId = this._getLDCForCI(ciId);
//Not directly inferred - which means the CI does not have a direct 'Hosted On::Hosts'
//relationship with a LDC.
if (gs.nil(ldcId)) {
var ciClassName = this.getCIClass(ciId);
if (!gs.nil(ciClassName) && ciClassName == "cmdb_ci_cloud_subnet")
ldcId = this._getContainedBy(ciId);
// To deduce LDCs for specific ci types, add more else if blocks.
// ex. else if(!gs.nil(ciClassName) && ciClassName == "cmdb_ci_compute_security_group")
}
return ldcId;
},
/**
* Each CI shall ultimatly relates to a given serviceAccount.
* This method traverses the hierarchy of these relationships and finds the service account.
* @param ciId
* @returns serviceAccountId for which this CI belongs to.
*/
getLdcAndServiceAccount: function (ciId) {
gs.info("Debugging for CI: " + ciId);
// if ciId is nil, it means discovery on service account, exiting early
if(gs.nil(ciId))
return null;
var response = this._getRelationshipGraph(ciId,false);
gs.info('Graph :'+JSON.stringify(response));
var result = this._buildResults(response);
if (result!=null && result.trim() != '') {
return result;
} else {
response = this._getRelationshipGraph(ciId, true);
gs.info('Graph :'+JSON.stringify(response));
return this._buildResults(response);
}
},
/**
* builds the results from payload containing graph. checks for SA and Ldc
*/
_buildResults: function(payload) {
var result = '';
var resultObj = {};
if (payload && payload.length > 0 && payload[payload.length - 1].type == 'cmdb_ci_cloud_service_account') {
resultObj.serviceAccount = payload[payload.length - 1].sys_id;
//last but one is LDC
if (payload.length > 1 && this._isLdcInstance(payload[payload.length - 2].type)) {
resultObj.ldc = payload[payload.length - 2].sys_id;
}
result = JSON.stringify(resultObj);
}
return result;
},
/**
* Take the ci type name and checks if it extends from Logical Datacenter ( directly or indirectly),
* there by we can say if its instance of Logical Datacenter.
* @param name of the type
*/
_isLdcInstance: function(type) {
if(!type)
return false;
if (type == 'cmdb_ci_logical_datacenter')
return true;
var gr = new GlideRecord('sys_db_object');
gr.addQuery('name', type);
gr.query();
if (gr.next()) {
if (gr.super_class.name && gr.super_class.name == 'cmdb_ci_logical_datacenter')
return true;
else if (gr.super_class.name)
return this._isLdcInstance(gr.super_class.name);
else
return false;
} else
return false;
},
_getResourceBlock: function (type) {
var rbGR = new GlideRecord('sn_cmp_rb_resourceblock');
rbGR.get('refcitype', type);
return rbGR.getUniqueValue();
},
/**
* gets parent to chid hierarchy recursively from cmdb_rel_ci
* @param childSysId
* @param graph
* @param level
* @param isReversalAllowed
*/
_getParentFromChild: function (childSysId, graph, level, isReversalAllowed) {
if (level == -1) return;
var relCIGr = new GlideRecord('cmdb_rel_ci');
relCIGr.addQuery('child', childSysId);
relCIGr.addQuery('type.name', '!=', 'Hosted on::Hosts');
relCIGr.addQuery('parent.sys_class_name', '!=', 'sn_cmp_stack');
relCIGr.query();
if (relCIGr.getRowCount() == 0) {
//dont let it come back and cause recursion
if (isReversalAllowed) this._getChildFromParent(childSysId, graph, level - 1, false);
return;
}
if (relCIGr.next()) {
var parent = relCIGr.getValue('parent');
var details = this._buildDetails(parent, relCIGr.parent.name, relCIGr.parent.sys_class_name);
graph.push(details);
if (details.type === 'cmdb_ci_cloud_service_account') {
//prune recursion
return;
}
this._getParentFromChild(parent, graph, level - 1, true);
}
},
/**
* gets child to parent hierarchy recursively from cmdb_rel_ci
* @param parentSysId
* @param graph
* @param level
* @param isReversalAllowed
*/
_getChildFromParent: function (parentSysId, graph, level, isReversalAllowed) {
if (level == -1) return;
relCIGr = new GlideRecord('cmdb_rel_ci');
relCIGr.addQuery('parent', parentSysId);
relCIGr.addQuery('type.name', 'IN', 'Hosted on::Hosts,Manages::Managed by');
relCIGr.addQuery('child.sys_class_name', '!=', 'sn_cmp_stack');
relCIGr.query();
if (relCIGr.getRowCount() == 0) {
//dont let it come back and cause recursion
if (isReversalAllowed) this._getParentFromChild(parentSysId, graph, level - 1, false);
return;
}
if (relCIGr.next()) {
var parent = relCIGr.getValue('child');
var details = this._buildDetails(relCIGr.child, relCIGr.child.name, relCIGr.child.sys_class_name);
graph.push(details);
if (details.type === 'cmdb_ci_cloud_service_account') {
//prune recursion
return;
}
this._getChildFromParent(parent, graph, level - 1, true);
}
},
_getRelationshipGraph: function (ciId, getChildFirst, level) {
//in case not provided, by default navigate to service account, this also guards against infinite recursion
if (!level) level = 20;
var details = this._getDetails(ciId);
var graph = [];
graph.push(details);
//current level added, hence -1
if (getChildFirst) {
this._getChildFromParent(ciId, graph, level - 1, true);
} else {
this._getParentFromChild(ciId, graph, level - 1, true);
}
return graph;
},
_getDetails: function (ciId) {
var cmdbCIGr = new GlideRecord('cmdb_ci');
cmdbCIGr.get(ciId);
return this._buildDetails(cmdbCIGr.sys_id, cmdbCIGr.name, cmdbCIGr.sys_class_name);
},
_buildDetails: function (sysId, name, type) {
return {
'name': name + '',
'sys_id': sysId + '',
'type': type + ''
};
},
/**
* Since Resource Block Operations support operation delegation, its important to know what the parent resource is
* for a particular CI, if a delegation operation is encountered.
* Custom handling for different CIs can be added here.
**/
parentForConfigurationItem: function (ciId) {
var parentCIId = this._getParentForCI(ciId);
var parentRB = '';
// To deduce LDCs for specific ci types, add more else if blocks.
// ex. else if(!gs.nil(ciClassName) && ciClassName == "cmdb_ci_compute_security_group")
if (!gs.nil(parentCIId)) {
//Get mapped Resource Block
var ciGR = new GlideRecord('cmdb_ci');
if (ciGR.get(parentCIId)) {
parentRB = this._getResourceBlock(ciGR.sys_class_name);
}
}
var parentConfigInfo = { parentCI: parentCIId, parentResource: parentRB };
return new global.JSON().encode(parentConfigInfo);
},
getCIClass: function (ciId) {
var attributeClass = null;
var cmdbRecord = new GlideRecord("cmdb");
cmdbRecord.addQuery("sys_id", ciId);
cmdbRecord.query();
if (cmdbRecord.next()) {
attributeClass = cmdbRecord.getValue("sys_class_name");
}
return attributeClass;
},
_getContainedBy: function (instanceId) {
var relCIGr = new GlideRecord('cmdb_rel_ci');
relCIGr.addQuery('child', instanceId);
relCIGr.addQuery('type.name', 'Contains::Contained by');
relCIGr.query();
while (relCIGr.next()) {
var ldcId = this._getLDCForCI(relCIGr.getValue('parent'));//network
if (!gs.nil(ldcId)) {
return ldcId;
}
}
},
_getLDCForCI: function (ciId) {
var parentCI = this._getParentForCI(ciId);
if (parentCI && this._isLDC(parentCI)) {
return parentCI;
}
},
_getParentForCI: function (parent) {
var relCIGr = new GlideRecord('cmdb_rel_ci');
relCIGr.addQuery('type.name', 'Hosted on::Hosts');
relCIGr.addQuery('parent', parent);
relCIGr.query();
if (relCIGr.next()) {
return relCIGr.getValue('child');
}
},
_isLDC: function (ldcId) {
var ldcGr = new GlideRecord("cmdb_ci_logical_datacenter");
return ldcGr.get(ldcId);
},
type: 'CMPCIRelationshipUtil'
};
Sys ID
46ab25900b216300ac950bcb15673a95