Name
sn_agent.AccAgentsAPI
Description
API for managing Agent Client Collectors.
Script
var AccAgentsAPI = Class.create();
AccAgentsAPI.prototype = {
initialize: function() {},
AGENTS_CI_TABLE: "sn_agent_cmdb_ci_agent",
AGENTS_INFO_TABLE: "sn_agent_ci_extended_info",
// "Agent_".length == 6
AGENT_NAME_PREFIX_LEN: 6,
CHECK_READ_LOG_SYS_ID: "028fcd5067c80010b7b72dbd2685ef4f",
// Map agent statuses to their numeric values
STATUS: {
UP: 0,
WARNING: 1,
DOWN: 2,
RESTARTING: 3,
},
// Map grab log request statuses to their numeric values
GRAB_LOG_REQUEST_STATUS: {
DONE: 0,
IN_PROGRESS: 1,
TIMED_OUT: 2,
ERROR: 3,
REQUEST_NOT_FOUND: 4
},
// Data collection enabled value
DATA_COLLECTION_ENABLED: "0",
// 2 minutes = 1000 ms * 60 * 2
GRAB_LOG_REQUEST_TIMEOUT_MS: 120000,
// Maximum limit for agents list
DEFAULT_AGENTS_LIST_LIMIT: 20000,
getAgentGr: function(agentId, table) {
var gr = new GlideRecord(table);
gr.addQuery("agent_id", agentId);
gr.setLimit(1);
gr.query();
return gr;
},
agentCIExists: function(agentId) {
return this.getAgentGr(agentId, this.AGENTS_CI_TABLE).hasNext();
},
isRestartEnabledForAgent: function(agentGr) {
if (agentGr.getTableName() != this.AGENTS_INFO_TABLE)
agentGr = agentGr.getElement("agent_extended_info").getRefRecord();
return agentGr.getValue("is_windows") == "1" || agentGr.getValue("is_using_systemd") == "1";
},
getGrabbedLogFromRecord: function(eccRecord) {
var xmlDoc = new XMLDocument2();
xmlDoc.parseXML(new AgentNowHandler().getEccPayload(eccRecord));
return xmlDoc.getFirstNode("//results/result/output").getTextContent();
},
getAgentRelatedCis: function(agentId) {
var gr = new GlideRecord("sn_agent_computers_connected_to_agent");
gr.addQuery("agent_agent_id", agentId);
gr.query();
if (!gr.next()) {
gs.error(gs.getMessage("AccAgentsAPI.getAgentRelatedCis: no computers connected to agent with id == {0}", agentId));
return null;
}
var relatedCis = {
host: {
name: gr.getValue("comp_name"),
class_name: gr.getValue("comp_sys_class_name"),
sys_id: gr.getValue("comp_sys_id")
},
apps: []
};
gr = new GlideRecord("sn_agent_applications_connected_to_agent");
gr.addQuery("agent_agent_id", agentId);
gr.query();
while (gr.next())
relatedCis.apps.push({
name: gr.getValue("appl_name"),
class_name: gr.getValue("appl_sys_class_name"),
sys_id: gr.getValue("appl_sys_id")
});
return relatedCis;
},
getAgentJson: function(agentInfoGr, withRelatedCis) {
var agent = {
name: agentInfoGr.getValue("name").slice(this.AGENT_NAME_PREFIX_LEN),
status: parseInt(agentInfoGr.getValue("status")),
agent_id: agentInfoGr.getValue("agent_id"),
ip_address: agentInfoGr.getValue("ip_address"),
number_of_running_checks: parseInt(agentInfoGr.getValue("running_checks_num")),
data_collection: parseInt(agentInfoGr.getValue("data_collection")),
is_restart_enabled: this.isRestartEnabledForAgent(agentInfoGr),
is_duplicate: agentInfoGr.getValue("is_duplicate") == "1",
up_since: agentInfoGr.getValue("up_since"),
version: agentInfoGr.getValue("agent_version")
};
if (withRelatedCis)
agent.related_cis = this.getAgentRelatedCis(agent.agent_id);
return agent;
},
// Returns an array of JSONs, each one containing the following information about the agent:
// name, status, agent id, ip address, number of running checks, data collection status,
// if restart is enabled, if the agent is a duplicate one, UTC time since agent is up and the
// version of the agent.
//
// An encoded query and a limit of agents can be given. Use null or undefined for both if they
// are not required. If no limit is given or the given limit is above 20,000, then the maximum
// limit of 20,000 will be used.
//
// The 3rd argument to this method, withRelatedCis, specifies if to return, per agent, a JSON
// ("related_cis") containing information about the agent host CI and app CIs (if any).
//
// Output example:
//
// [
// {
// "name": "MREM6A2F8DB2",
// "status": 0,
// "agent_id": "e894145d704d4445",
// "ip_address": "192.168.0.219",
// "number_of_running_checks": 0,
// "data_collection": 0,
// "is_restart_enabled": false,
// "is_duplicate": false,
// "up_since": "2020-12-20 11:19:41",
// "version": "2.2.0"
// }
// ]
getAgentsList: function(encodedQuery, limit, withRelatedCis) {
var agents = [];
// query the agent ci table to enable encoded query on that table
var agentsGr = new GlideRecord(this.AGENTS_CI_TABLE);
if (!gs.nil(encodedQuery))
agentsGr.addEncodedQuery(encodedQuery);
if (gs.nil(limit) || limit < 1)
agentsGr.setLimit(this.DEFAULT_AGENTS_LIST_LIMIT);
else
agentsGr.setLimit(limit);
agentsGr.query();
while (agentsGr.next())
agents.push(this.getAgentJson(agentsGr.getElement("agent_extended_info").getRefRecord(), withRelatedCis));
return agents;
},
// Given an agent id, return the following information about the agent with that id:
// name, status, agent id, ip address, number of running checks, data collection status,
// if restart is enabled, if the agent is a duplicate one, UTC time since agent is up and the
// version of the agent.
//
// This method returns a JSON with 2 attributes: an error message ("error") and a JSON with the above information
// about the requested agent ("agent"). if no agent exists with the given agent id then the error message will not
// be null and the agent JSON will be null. if it does exist than output.error == null and output.agent != null.
//
// The 2nd argument to this method, withRelatedCis, specifies if to return a JSON ("related_cis") containing information
// about the agent host CI and app CIs (if any).
//
// Output example:
//
// {
// "error": null,
// "agent": {
// "name": "MREM6A2F8DB2",
// "status": 0,
// "agent_id": "e894145d704d4445",
// "ip_address": "192.168.0.219",
// "number_of_running_checks": 0,
// "data_collection": 0,
// "is_restart_enabled": false,
// "is_duplicate": false,
// "up_since": "2020-12-20 11:19:41",
// "version": "(devel)"
// }
// }
getAgent: function(agentId, withRelatedCis) {
var agentInfoGr = this.getAgentGr(agentId, this.AGENTS_INFO_TABLE);
if (!agentInfoGr.next()) {
return {
error: "No Agent With ID: " + agentId,
agent: null
};
}
return {
error: null,
agent: this.getAgentJson(agentInfoGr, withRelatedCis)
};
},
// Submit a grab log request to grab the log of the agent with the given agent id.
//
// returns a JSON with the request id and a possible error message (null when no error).
// The returned request id should be passed to AccAgentsAPI.checkGrabLogRequestProgress
// in order to check the progress of the request and get the log itself.
//
// Output example:
//
// {
// "error": null,
// "request_id": "028fcd5067c8201057b72dgd2685ff4f"
// }
submitGrabLogRequest: function(agentId) {
var agentGr = this.getAgentGr(agentId, this.AGENTS_CI_TABLE);
if (!agentGr.next()) {
gs.error("sn_agent.AccAgentsAPI.submitGrabLogRequest: no live agent with id: " + agentId);
return {
error: "No Agent With ID: " + agentId,
request_id: null
};
}
if (agentGr.agent_extended_info.status != this.STATUS.UP) {
return {
error: "Agent With ID: " + agentId + " Is Not Up",
request_id: null
};
}
return {
error: null,
request_id: new AgentNowCapabilities().grabAgentLog(agentGr)
};
},
// Given a request id obtained from AccAgentsAPI.submitGrabLogRequest,
// this method checks the status of the request with the given sys id.
//
// Returns null in case no request exists with the given sys id and
// otherwise returns a JSON with 2 attributes: status and output,
// where status is one of the values in AccAgentsAPI.GRAB_LOG_REQUEST_STATUS
// and output is the grabbed log itelf when the status is DONE or a message
// describing any of the other statuses.
//
// Output example:
//
// {
// "status": 0, // AccAgentsAPI.GRAB_LOG_REQUEST_STATUS.DONE
// "output": "...", // the grabbed log
// }
checkGrabLogRequestProgress: function(requestId) {
var requestGr = new GlideRecord("sn_agent_request");
if (!requestGr.get(requestId)) {
return {
status: this.GRAB_LOG_REQUEST_STATUS.REQUEST_NOT_FOUND,
output: "No Grab Log Agent Request With sys_id: " + requestId
};
}
if (requestGr.getValue("check_def") != this.CHECK_READ_LOG_SYS_ID) {
return {
status: this.GRAB_LOG_REQUEST_STATUS.REQUEST_NOT_FOUND,
output: "Agent Request With sys_id: " + requestId + " Is Not A Grab Log Request"
};
}
// flow invoked by grab log functionality is a bit different than running regular checks
// so lets check if the ecc queue contains a response for the request
var eccQ = new GlideRecord("ecc_queue");
eccQ.addQuery("agent_correlator", requestId);
eccQ.addQuery("queue", "input");
eccQ.setLimit(1);
eccQ.query();
var status, output;
if (!eccQ.next()) {
var requestCreationTime = new GlideDateTime(requestGr.getValue("sys_created_on"));
var now = new GlideDateTime();
// agent requests for log grabbing are not getting marked as timeout
// so lets consider the request as timed out if more than 2 minutes
// passed since it was created (resembling the logic in
// AgentNowHandler.handleRequestChecksTable)
if (now.getNumericValue() - requestCreationTime.getNumericValue() > this.GRAB_LOG_REQUEST_TIMEOUT_MS) {
status = this.GRAB_LOG_REQUEST_STATUS.TIMED_OUT;
output = "Grab Log Request Timed Out";
} else {
status = this.GRAB_LOG_REQUEST_STATUS.IN_PROGRESS;
output = "Grab Log Request Still In Progress";
}
} else {
if (eccQ.getValue("state") == "error") {
status = this.GRAB_LOG_REQUEST_STATUS.ERROR;
output = "Error Executing Grab Log Request";
} else {
status = this.GRAB_LOG_REQUEST_STATUS.DONE;
output = this.getGrabbedLogFromRecord(eccQ);
}
}
return {
status: status,
output: output
};
},
// Run discovery for the agent with the given agent id.
//
// returns a string containing an error message which is null
// if no error happened.
runDiscovery: function(agentId) {
var agentGr = this.getAgentGr(agentId, this.AGENTS_CI_TABLE);
if (!agentGr.next())
return "No Agent With ID: " + agentId;
if (agentGr.agent_extended_info.status != this.STATUS.UP)
return "Agent With ID: " + agentId + " Is Not Up";
new RunDiscoveryCheck().runCheck(agentGr.getUniqueValue());
return null;
},
// Set the given data collection status (true/false if enabled or not)
// for the agent with the given agent id.
//
// returns a string containing an error message which is null
// if no error happened.
setDataCollectionStatus: function(agentId, status) {
var agentGr = this.getAgentGr(agentId, this.AGENTS_CI_TABLE);
if (!agentGr.next())
return "No Agent With ID: " + agentId;
if (agentGr.agent_extended_info.status != this.STATUS.UP)
return "Agent With ID: " + agentId + " Is Not Up";
var dataCollectionStatus = agentGr.agent_extended_info.data_collection;
if (status && dataCollectionStatus != this.DATA_COLLECTION_ENABLED)
new AgentSilentModeUtils().unsilentAgents(agentGr.getUniqueValue());
else if (!status && dataCollectionStatus == this.DATA_COLLECTION_ENABLED)
new AgentSilentModeUtils().silentAgents(agentGr.getUniqueValue());
return null;
},
// Restart the agent with the given agent id.
//
// returns a string containing an error message which is null
// if no error happened.
restartAgent: function(agentId) {
var agentGr = this.getAgentGr(agentId, this.AGENTS_CI_TABLE);
if (!agentGr.next())
return "No Agent With ID: " + agentId;
if (agentGr.agent_extended_info.status != this.STATUS.UP)
return "Agent With ID: " + agentId + " Is Not Up";
if (!this.isRestartEnabledForAgent(agentGr))
return "Agent With ID: " + agentId + " Does Not Support Restart";
new AgentRestartUtil().restartAgent([agentGr.getUniqueValue()]);
return null;
},
type: 'AccAgentsAPI'
};
Sys ID
315044c4531120106d9bddeeff7b122e