Custom API - Run Check Command
Posted: Fri Feb 26, 2021 3:27 am
Running command tests from the UI is great, it allows you to confirm the command not works on the target host but it also allows you to get the result and make sure things are ok on the host too.
But of course you know that already. However it would be nice to run this as code. Sure you could remotely connect to the Nagios server and execute the check directly. Not very clean.
This is something I wanted to be able to run from the API, so I've created a custom commandtest API call. This cobbles together the code actually used by the command_test.php script that Nagios uses. One thing this does offer that the current Run check command doesn't is the ability to use $HOSTNAME$ as well as $HOSTADDRESS$. Oddly the actual command_test.php does grab the parameter/argument for $host, but it doesn't do anything with it.
This now allows me to (automatically via code) test check commands before applying them to hosts.
How to use it
This is the API call:
https://<NAGIOS_XI_SERVER>/nagiosxi/api/v1/custom/commandtest
If you run this command without any parameters you will be able to retrieve the complete list of the commands available. This is like the existing API config/command function but with one added bonus, it displays the command Id (cid).
Run a check command
To run one of your commands using arguments you need to supply the following:
apikey= [required, this is your API key which you use for all standard API calls]
cid= [required, this the command id]
address= [XOR, either use address or host]
host= [XOR, either use address or host]
argn= [e.g. arg1, arg2, arg3 etc. optional]
The args are of course optional depending on the requirements of your command arg1 to arg8.
e.g.
The code can of course be written better, I had a few issues with relative paths to include existing functions so to resolve this (albeit temporarily to get the function working) I copied what I needed into this function; it's a start and can be improved upon. The response you get back is as Nagios provides. I've not written anything in the function yet to format the output any better.
I guess as a final thought, it would be nice as a feature request to include this function into the official API.
If anyone is interested, I also have two other custom API functions created to retrieve audit logs and event logs; which could be another feature request for the developers
But of course you know that already. However it would be nice to run this as code. Sure you could remotely connect to the Nagios server and execute the check directly. Not very clean.
This is something I wanted to be able to run from the API, so I've created a custom commandtest API call. This cobbles together the code actually used by the command_test.php script that Nagios uses. One thing this does offer that the current Run check command doesn't is the ability to use $HOSTNAME$ as well as $HOSTADDRESS$. Oddly the actual command_test.php does grab the parameter/argument for $host, but it doesn't do anything with it.
This now allows me to (automatically via code) test check commands before applying them to hosts.
How to use it
This is the API call:
https://<NAGIOS_XI_SERVER>/nagiosxi/api/v1/custom/commandtest
If you run this command without any parameters you will be able to retrieve the complete list of the commands available. This is like the existing API config/command function but with one added bonus, it displays the command Id (cid).
Run a check command
To run one of your commands using arguments you need to supply the following:
apikey= [required, this is your API key which you use for all standard API calls]
cid= [required, this the command id]
address= [XOR, either use address or host]
host= [XOR, either use address or host]
argn= [e.g. arg1, arg2, arg3 etc. optional]
The args are of course optional depending on the requirements of your command arg1 to arg8.
e.g.
Here's the extract of the custom API php needed for your own nagiosxicustomendpoints.inc.php file:
Code: Select all
register_custom_api_callback('custom', 'commandtest', 'custom_commandtest');
function custom_commandtest($args) {
global $cfg;
global $ccm;
// Initialization stuff
pre_init();
// Grab GET or POST variables and check pre-reqs
grab_request_vars();
check_prereqs();
// Verify access
if (!user_can_access_ccm()) {
die(_('You do not have access to this page.'));
}
// Main includes
require_once(dirname(__FILE__).'/../ccm/includes/common_functions.inc.php');
require_once(dirname(__FILE__).'/../ccm/includes/language.inc.php');
require_once(dirname(__FILE__).'/../ccm/includes/auth.inc.php');
require_once(dirname(__FILE__).'/../ccm/includes/hidden_overlay_functions.inc.php');
// CCM classes
require_once(dirname(__FILE__).'/../ccm/classes/config.class.php');
require_once(dirname(__FILE__).'/../ccm/classes/data.class.php');
require_once(dirname(__FILE__).'/../ccm/classes/import.class.php');
require_once(dirname(__FILE__).'/../ccm/classes/db.class.php');
require_once(dirname(__FILE__).'/../ccm/classes/form.class.php');
// CCM main includes
require_once(dirname(__FILE__).'/../ccm/page_templates/ccm_table.php');
require_once(dirname(__FILE__).'/../ccm/includes/page_router.inc.php');
// Currently we only support single domain configs
$_SESSION['domain'] = 1;
// Create connections
$ccm = new stdClass();
$ccm->db = new DB($cfg['db_info']['nagiosql']);
$ccm->import = new Import();
$ccm->config = new Config();
$ccm->data = new Data();
// Get all necessary parameters for a check command
$cid = intval(ccm_grab_request_var('cid'));
$address = ccm_grab_request_var('address', '');
$host = ccm_grab_array_var($_REQUEST, 'host', '');
$arg1 = ccm_grab_array_var($_REQUEST, 'arg1', '');
$arg2 = ccm_grab_array_var($_REQUEST, 'arg2', '');
$arg3 = ccm_grab_array_var($_REQUEST, 'arg3', '');
$arg4 = ccm_grab_array_var($_REQUEST, 'arg4', '');
$arg5 = ccm_grab_array_var($_REQUEST, 'arg5', '');
$arg6 = ccm_grab_array_var($_REQUEST, 'arg6', '');
$arg7 = ccm_grab_array_var($_REQUEST, 'arg7', '');
$arg8 = ccm_grab_array_var($_REQUEST, 'arg8', '');
// Grab the command we were sent from the database
if ($cid != "") {
$query = "SELECT `command_name`, `command_line` FROM tbl_command WHERE `id` = '$cid' && command_type = 1 LIMIT 1";
}
else {
$query = "SELECT `id`, `command_type`, `active`, `command_name`, `command_line` FROM tbl_command WHERE command_type = 1";
}
$command = $ccm->db->query($query);
if ($cid != "") {
// If the command isn't in the database then fail now
if (!isset($command[0]['command_name'])) {
print "ERROR: Unable to locate the command in the database";
exit();
}
// Create all the database variables and then replace all variables that need to be replaced
// before running the actual command and echoing the output to the screen.
$name = $command[0]['command_name'];
$cmd_line = $command[0]['command_line'];
$haystack = array($cfg['component_info']['nagioscore']['plugin_dir'], $host, $address, $arg1, $arg2, $arg3, $arg4, $arg5, $arg6, $arg7, $arg8);
$needles = array('$USER1$', '$HOSTNAME$', '$HOSTADDRESS$', '$ARG1$', '$ARG2$', '$ARG3$', '$ARG4$', '$ARG5$', '$ARG6$', '$ARG7$', '$ARG8$');
$fullcommand = str_replace($needles, $haystack, $cmd_line);
// break apart everything after an unescaped semi-colon
$fullcommand = str_replace("\;", "%%%%%", $fullcommand);
$fullcommand_array = explode(';', $fullcommand);
$fullcommand = $fullcommand_array[0];
$fullcommand = str_replace("%%%%%", "\;", $fullcommand);
// Grab the current value of $fullcommand and store it to display in the run check command results box in order to maintain obfuscation
$displaycommand = $fullcommand;
$fullcommand = nagiosccm_replace_user_macros($fullcommand);
$id = submit_command(COMMAND_RUN_CHECK_CMD, $fullcommand);
if ($id <= 0) {
$output = _("Error submitting command.");
}
else {
for ($x = 0; $x < 40; $x++) {
usleep(500000);
$args = array(
"command_id" => $id
);
$xml = get_command_status_xml($args);
if ($xml) {
if ($xml->command[0]) {
if (intval($xml->command[0]->status_code) == 2) {
$output = $xml->command[0]->result;
break;
}
}
}
}
}
$hn = (function_exists('gethostname')) ? gethostname() : php_uname('n');
if (stripos('.', $hn)) {
$hna = explode('.', $hn);
$hn = $hna[0];
}
$response = $output;
}
else {
$response = $command;
}
return $response;
}
I guess as a final thought, it would be nice as a feature request to include this function into the official API.
If anyone is interested, I also have two other custom API functions created to retrieve audit logs and event logs; which could be another feature request for the developers