+#!/usr/bin/php
<?PHP
/**********************************************************************************
** (c) Copyright 2002, Brenno J.S.A.A.F. de Winter, De Winter Information Solutions
***********************************************************************************/
-/*
- NAME : gcm_daemon
- AUTHOR : Brenno J.S.A.A.F. de Winter
- De Winter Information Solutions
- COPYRIGHT : 2002 - De Winter Information Solutions,
- Brenno J.S.A.A.F. de Winter
-
- * DATES *
- First : November 8th 2002
+/*
+ NAME : gcm_daemon
+ AUTHOR : Brenno J.S.A.A.F. de Winter
+ De Winter Information Solutions
+ COPYRIGHT : 2002 - De Winter Information Solutions,
+ Brenno J.S.A.A.F. de Winter
+
+ * DATES *
+ First : November 8th 2002
+ Gnucomo-0.0.3: December 6th 2002
+ Gnucomo-0.0.8: September 4th 2003
+
+ $Log: gcm_daemon.php,v $
+ Revision 1.17 2003-10-29 09:58:29 arjen
+ Create separate notifications for different objects in service_check().
+
+ Revision 1.16 2003/09/03 12:48:48 arjen
+ Check the log table against the servies running on an object and
+ create notifications if a service is not supposed to be available
+ or is not known at all.
+
+ Revision 1.15 2003/09/02 12:48:09 arjen
+ BUGFIX: Secondary indices on log_notification were unique.
+ Additional information in the 'usr' table: 'display_name' and 'email'.
+ Added new issues and services.
+
+ Revision 1.14 2003/09/01 06:51:07 arjen
+ Accept command argument '-c config' to use an alternate
+ gnucomo configuration.
+
+ Revision 1.13 2003/08/14 10:22:42 arjen
+ Disabled DEBUG output
+
+ Revision 1.12 2003/08/05 07:46:37 arjen
+ BUGFIX: Print an error message if a parameter does not have
+ any history.
+
+ Revision 1.11 2003/07/09 07:25:02 arjen
+ Gcm_daemon gathers statistics on parameters, notifications, etc. for all objects.
+
+ Revision 1.10 2003/03/29 08:33:58 arjen
+ In phpclasses/db.class.php: Added the database connection string as
+ an argument to the function copy_db_class.
+ Fixed the PHP member function db::db_connect(). The Postgres connection
+ string is now passed as an argument to that function.
+
+ Revision 1.9 2003/02/21 08:37:59 arjen
+ Added new table to the database: log_adv_daemon_email.
+
*/
+// $Id: gcm_daemon.php,v 1.17 2003-10-29 09:58:29 arjen Exp $
+
+ini_set('include_path', '.:./classes:../phpclasses');
+ini_set('html_errors', 'false');
+
//Tell the log that we're up.
define_syslog_variables();
-openlog("gnucomo", LOG_PID, LOG_DAEMON);
-syslog(LOG_INFO, "gcm_daemon started");
-require_once "classes/gnucomo_config.class.php";
-require_once "classes/db.class.php";
-require_once "classes/gnucomo.process_log.php";
+require_once "gnucomo_config.php";
+require_once "db.class.php";
+require_once "gnucomo.process_log.php";
// Set the standard variables //
-$project_name = "gnucomo"; //name of the entire project
-$app_name = "gcm_daemon"; //name of the application running
-$db_version = 13; //The db_version indicates what the level of
- //the database should be. If the database is
- //old an update will be generated.
-$gcmd_version = 2; //This value indicates the active version of the gcm_daemon,
- //which is saved in the database. Log records that were not
- //recognized before will now be recognized. The version doesn't
- //mean anything in the overall gnucomo project.
+
+$project_name = "gnucomo"; // name of the entire project
+$app_name = "gcm_daemon"; // name of the application running
+$developrelease = "FALSE"; // Indicates if special debug settings are needed
+$db_version = 43; // The db_version indicates what the level of
+ // the database should be. If the database is
+ // old an update will be generated.
+$gcmd_version = 5; // This value indicates the active version of
+ // the gcm_daemon, which is saved in the database.
+ // Log records that were not recognized before
+ // will now be recognized. The version doesn't
+ // mean anything in the overall gnucomo project.
+
+//Avoid time-limit issues
+set_time_limit(0);
+
+// Scan the command arguments
+
+for ($argi = 1; $argi < $argc; $argi++)
+{
+ switch ($argv[$argi])
+ {
+ case "-c":
+ $argi++;
+ $project_name = $argv[$argi];
+ break;
+
+ default:
+ echo "Usage: gcm_daemon [-c configname]\n";
+ exit();
+ break;
+ }
+}
// Read the database settings //
$class_settings = new gnucomo_config();
-$class_settings->read($project_name);
-$class_settings->database();
+if (!$class_settings->read($project_name))
+{
+ echo "Can not read Gnucomo configuration file for $project_name.\n";
+ exit();
+}
+
+openlog("gnucomo", LOG_PID, LOG_DAEMON);
+syslog(LOG_INFO, "gcm_daemon started");
//Open an connection to the database
$dbms_type = $class_settings->find_parameter("database", "type");
$dbms->db_name = $dbms_name;
$dbms->db_user = $dbms_user;
$dbms->db_password = $dbms_password;
-$dbms->db_connect();
+$dbms->db_connect($class_settings->database());
-if ($dbms->have_db_connection() == "FALSE") {
- exit ("Database connection failed.");
+if ($dbms->have_db_connection() == "FALSE")
+{
+ exit ("Database connection failed.");
+}
+else
+{
+ // The database connection has been made.
+ $dbms_working = copy_db_class($dbms, $class_settings->database());
}
-//The database connection has been made.
-//Verify if the database is up-to-date by checking the versionnumber
-$local_sql = "SELECT setting_value FROM db_value WHERE setting = 'db_version'";
+// Verify if the database is up-to-date by checking the versionnumber
+
+$local_sql = "SELECT setting_value FROM db_value WHERE setting = 'db_version' ";
$dbms->query($local_sql);
-if ($dbms->fetch_row() == "TRUE") {
+if ($dbms->fetch_row() == "TRUE")
+{
$active_version = $dbms->db_result_row[0];
-
- //Update the database to the most recent version.
- if ($active_version < $db_version) {
- include ("classes/gnucomo_db_version.php");
+
+ // Update the database to the most recent version.
+
+ if ($active_version < $db_version)
+ {
+ include ("gnucomo_db_version.php");
}
-} else {
+}
+else
+{
syslog (LOG_INFO, "Couldn't initialize database version. Is this a gnucomo database?");
die ("Couldn't initialize database version.\n");
}
-//If there is a new gcm_daemon_version the logrecords that couldn't be understood can be
-//reprocessed. For this reason processed is now changed to false again for not recognized
-//records.
-$local_sql = " SELECT setting_value FROM db_value WHERE setting = 'gcm_daemon_version'";
+// If there is a new gcm_daemon_version the logrecords that couldn't be
+// understood can be reprocessed. For this reason processed is now changed
+// to false again for not recognized records.
+
+$local_sql = "SELECT setting_value FROM db_value
+ WHERE setting = 'gcm_daemon_version'";
$dbms->query($local_sql);
-if ($dbms->fetch_row() == "TRUE") {
- if ($dbms->db_result_row[0] < $gcmd_version) {
+if ($dbms->fetch_row() == "TRUE")
+{
+ if ($dbms->db_result_row[0] < $gcmd_version)
+ {
//Reactive log-records that weren't understood earlier.
- $local_sql = "UPDATE log SET processed = false WHERE recognized = false";
+
+ $local_sql = "UPDATE log SET processed = false
+ WHERE logid NOT IN (SELECT DISTINCT logid FROM log_adv)";
$dbms->query($local_sql);
//Update de gcm_daemon version in the database
$dbms->query($local_sql);
}
-
+
}
+// Now we loop the tasks that we have to do.
+
+
+do
+{
+
+ //At this place we start processing new log-lines
+
+ process_log ();
+ service_check();
+ find_notifications();
+
+ // Gather the statistics for each object
-
-//At this place we start processing new log-lines
-process_log ();
+ $obj_result = $dbms->query("SELECT objectid FROM object");
+ for ($obj = 0; $obj < $dbms->num_rows($obj_result); $obj++)
+ {
+ $object = $dbms->fetch_object($obj_result, $obj);
+ echo "Gathering statistics for object " . $object->objectid . "\n";
+ GatherStatistics($object->objectid);
+ }
+
+ $keep_running = false;
+
+} while ($keep_running == true);
//Tell the log that we're ending our efforts in a nice way
+
syslog (LOG_INFO, "gcm_daemon ended nicely");
-function process_log () {
-
+function process_log ()
+{
+
/* This function will walk through the log-records that haven't been processed
- * first a snapshot will be created of a the non-processed records.
+ * first a snapshot will be created of a the non-processed records.
* sequentially each record will dealt with. By doing that changes will be made
* in several log_adv_xxx tables
* INPUT : NONE
* OUTPUT : NONE
*/
+
global $dbms;
-
- //Find open records.
- $local_sql = "SELECT * FROM log WHERE processed = FALSE";
+ global $dbms_working;
+ global $class_settings;
+
+ $last_log = 0;
+
+ // Find records in log that still have to be processed.
+
+ $local_sql = "SELECT setting_value FROM db_value WHERE setting = 'log_processing'";
$dbms->query($local_sql);
+
+ if ($dbms->fetch_row() == "TRUE")
+ {
+ $last_log = $dbms->db_result_row[0];
+ }
+
+ //Query the log-table
+ $local_sql = "SELECT * FROM log WHERE logid > CAST(".$last_log." AS BIGINT)
+ ORDER BY logid";
+ $dbms->query($local_sql);
+
+ //Update the log-statistics in the object-table
+ $local_statistics_db = copy_db_class($dbms, $class_settings->database());
+ $local_findobject_db = copy_db_class($dbms, $class_settings->database());
+
+ //Make totals
+ $local_upper_row = $dbms->num_rows() + $last_log + 1;
+ $local_sql = "SELECT COUNT(logid), objectid from log WHERE logid > CAST(". $last_log .
+ " AS BIGINT) AND logid < CAST (" . $local_upper_row . " AS BIGINT) GROUP BY objectid";
+ $local_statistics_db->query ($local_sql);
+
+ // Loop the objects
+ for ($i = 1; $i <= $local_statistics_db->num_rows(); $i++)
+ {
+ $local_object_row = $local_statistics_db->fetch_row();
+
+ $local_sql = "UPDATE object SET log_count = log_count + " .
+ $local_statistics_db->db_result_row[0] . " WHERE objectid = '" .
+ $local_statistics_db->db_result_row[1] . "'";
+
+ $local_findobject_db->query($local_sql);
+ }
+
$local_counter = 0;
- if ($dbms->num_rows() > 0) {
+ if ($dbms->num_rows() > 0)
+ {
//Create a database connection for changes in the database.
- $dbms_changes = copy_db_class($dbms);
- if ($dbms_changes->have_db_connection() == 'TRUE') {
+ $dbms_changes = copy_db_class($dbms, $class_settings->database());
+ if ($dbms_changes->have_db_connection() == 'TRUE')
+ {
- $local_sql = 0;
+ $local_sql = 0 ;
+ $local_sql_statistics = "";
$local_object_os = "";
$local_object_os_version = "";
- //Walk through all the log-records.
+ while ($local_counter < $dbms->num_rows())
+ {
- while ($local_counter < $dbms->num_rows()) {
$local_return_row = $dbms->fetch_row();
- if ($local_return_row == 'TRUE') {
- //Work on active rows
+ if ($local_return_row == 'TRUE')
+ {
+ // Work on active rows
$local_log_id = $dbms->db_result_row[0];
- //If this is the first time get information about the object
- if ($local_object_os == "") {
- //No OS has been given yet, so let's find the objectid.
- $local_findobject_db = copy_db_class($dbms);
+ $local_sql_findobject = "SELECT os, os_version FROM object
+ WHERE objectid = '".$dbms->db_result_row[1]."'";
+ $local_findobject_db->query($local_sql_findobject);
+ $local_findobject_result = $local_findobject_db->fetch_row();
+ if ($local_findobject_result == 'TRUE')
+ {
- $local_sql_findobject = "SELECT os, os_version FROM object WHERE objectid = '".$dbms->db_result_row[0]."'";
- $local_findobject_db->query($local_sql_findobject);
- $local_findobject_result = $local_findobject_db->fetch_row();
- if ($local_findobject_result == 'TRUE') {
+ // Now work on the OS again
$local_object_os = $local_findobject_db->db_result_row[0];
- if ($local_object_os == "") {
+ if ($local_object_os == "")
+ {
$local_object_os = "Linux";
$local_object_os_version = "Unknown assuming Linux";
- } else {
+ }
+ else
+ {
$local_object_os_version = $local_findobject_db->db_result_row[1];
}
- } else {
- syslog (LOG_INFO, "Couldn't find object for log-records");
- die("Couldn't match log-records to any existing object");
- }
}
- switch (strtolower($local_object_os)) {
- case "linux":
+ switch (strtolower($local_object_os))
+ {
+ case "linux":
$local_process_return = linux_log ();
break;
- default:
+ default:
syslog (LOG_INFO, "Couldn't find suitable OS for processing the logline");
break;
- }
+ }
- //Now that the processing took place change the processing state if processing was
- //completed successfully.
- if ($local_process_return == 'TRUE') {
- $local_sql_processed = "UPDATE log SET recognized = TRUE where logid = $local_log_id";
- $dbms_changes->query($local_sql_processed);
+ if ($local_process_return != 'TRUE')
+ {
+ $local_process_return = 'FALSE';
}
-
- //Change the status of the log-record to processed.
- $local_sql_processed = "UPDATE log SET processed = TRUE WHERE logid = $local_log_id";
- $dbms_changes->query($local_sql_processed);
- } else {
+ }
+ else
+ {
break;
}
$local_counter++;
- }
- } else {
+ }
+
+ // Register that the logrecords have been processed.
+ $local_sql = "UPDATE db_value SET setting_value = '"
+ .$local_log_id."' where setting = 'log_processing'";
+ $dbms->query($local_sql);
+
+
+ // Update the statistics for the object-table
+
+
+ }
+ else
+ {
syslog (LOG_INFO, "Couldn't clone database connection.");
die ("Couldn't reconnect to the database.\n");
- }
+ }
+ }
+
+}
+
+/*
+ * Update a single statistic for some object.
+ * If it does not yet exist, it will be created.
+ */
+
+function UpdateStatistic($objectid, $name, $value)
+{
+ global $dbms;
+
+ $result = $dbms->query("SELECT objectid FROM object_statistics WHERE
+ objectid='$objectid' AND statname='$name'");
+ if ($dbms->num_rows() == 0)
+ {
+ $dbms->query("INSERT INTO object_statistics VALUES
+ ('$objectid', '$name', '$value')");
+ }
+ else
+ {
+ $dbms->query("UPDATE object_statistics SET statvalue='$value' WHERE
+ statname='$name' AND objectid='$objectid'");
}
}
-?>
+/*
+ * Gather the statistics for a single object ($objectid).
+ * We count the number of parameters, removed parameters, notifications
+ * closed notifications and log entries. The totals of these are
+ * maintained in a separate table: object_statistics.
+ */
+
+function GatherStatistics($objectid)
+{
+ global $dbms;
+
+ // Gather statistics on parameters
+
+ $r = $dbms->query("SELECT paramid FROM parameter WHERE objectid=CAST('"
+ . $objectid . "' AS BIGINT)");
+ $nr_parameters = $dbms->num_rows($r);
+
+ $removed_parameters = 0;
+ for ($p = 0; $p < $nr_parameters; $p++)
+ {
+ $param = pg_fetch_object($r, $p);
+ $qry ="select change_nature from history where paramid= CAST('";
+ $qry .= $param->paramid . "' AS BIGINT) order by modified desc";
+ $rhist = $dbms->query($qry);
+ if ($dbms->num_rows($rhist) == 0)
+ {
+ echo "ERROR: No history for parameter id " . $param->paramid . "\n";
+ }
+ else
+ {
+ $hist = $dbms->fetch_object($rhist, 0);
+ if ($hist->change_nature == "REMOVED")
+ {
+ $removed_parameters++;
+ }
+ }
+ }
+
+ UpdateStatistic($objectid, 'parameters', $nr_parameters);
+ UpdateStatistic($objectid, 'removed_parameters', $removed_parameters);
+
+ // Gather statistics on notifications
+
+ $r = $dbms->query("SELECT count(notificationid) FROM notification WHERE
+ objectid = CAST('" . $objectid . "' AS BIGINT)");
+ $cnt = $dbms->fetch_object($r, 0);
+ UpdateStatistic($objectid, 'notifications', $cnt->count);
+
+ $r = $dbms->query("SELECT count(notificationid) FROM notification WHERE
+ objectid = CAST('" . $objectid . "' AS BIGINT) AND statuscode ='cls'");
+ $cnt = $dbms->fetch_object($r, 0);
+ UpdateStatistic($objectid, 'closed_notifications', $cnt->count);
+
+ // Gather statistics on log entries
+
+ $r = $dbms->query("SELECT count(logid) FROM log WHERE
+ objectid = CAST('" . $objectid . "' AS BIGINT)");
+ $cnt = $dbms->fetch_object($r, 0);
+ UpdateStatistic($objectid, 'logs', $cnt->count);
+}
+
+/*
+ * Service_check - Check the log entries if there are any unknown
+ * services.
+ */
+
+function service_check()
+{
+ global $dbms;
+
+ $unknown_notification = array();
+ $unused_notification = array();
+ $last_log = 0;
+
+ // How far did we get last time ?
+
+ $lastlogres = $dbms->query("SELECT setting_value FROM db_value
+ WHERE setting = 'log_servicecheck'");
+ if ($dbms->num_rows($lastlogres) == 1)
+ {
+ $last_log = $dbms->Field($lastlogres, 0, 'setting_value');
+ }
+ else
+ {
+ $dbms->query("INSERT INTO db_value (setting, setting_value)
+ VALUES ('log_servicecheck', '0')");
+ }
+
+ // Query the log-table
+
+ $qry = "SELECT logid, objectid, servicecode FROM log
+ WHERE logid > CAST(".$last_log." AS BIGINT) ORDER BY logid";
+ $log_res = $dbms->query($qry);
+ //$log_res = $dbms->query("SELECT logid, objectid, servicecode,rawdata FROM log");
+
+ for ($log_row = 0; $log_row < $dbms->num_rows($log_res); $log_row++)
+ {
+ $log_entry = $dbms->fetch_object($log_res, $log_row);
+ $last_log = $log_entry->logid;
+
+ // Check if the service is used on the object.
+
+ $qry = "SELECT * FROM object_service WHERE objectid='";
+ $qry .= $log_entry->objectid . "' AND servicecode='";
+ $qry .= $log_entry->servicecode . "'";
+
+ $os_res = $dbms->query($qry);
+ if ($dbms->num_rows($os_res) == 0)
+ {
+ // Service is not found for the object, check if the service
+ // exists at all.
+
+ $qry = "SELECT * FROM service WHERE servicecode='";
+ $qry .= $log_entry->servicecode . "'";
+
+ if ($dbms->num_rows($dbms->query($qry)) == 0)
+ {
+ if (!isset($unknown_notification[$log_entry->objectid]))
+ {
+ $remark = "One or more log entries from a service that is not in the database";
+ $unknown_notification[$log_entry->objectid] =
+ $dbms->new_notification($log_entry->objectid, 'service unknown', $remark);
+ }
+ if (isset($unknown_notification[$log_entry->objectid]))
+ {
+ $insertion = "INSERT INTO log_notification (notificationid, logid) VALUES ('";
+ $insertion .= $unknown_notification[$log_entry->objectid] . "', '";
+ $insertion .= $log_entry->logid . "')";
+ $dbms->query($insertion);
+ }
+ }
+ else
+ {
+ if (!isset($unused_notification[$log_entry->objectid]))
+ {
+ $remark = "One or more log entries from a service not running on this object";
+ $unused_notification[$log_entry->objectid] =
+ $dbms->new_notification($log_entry->objectid, 'service not used', $remark);
+ }
+ if (isset($unused_notification[$log_entry->objectid]))
+ {
+ $insertion = "INSERT INTO log_notification (notificationid, logid) VALUES ('";
+ $insertion .= $unused_notification[$log_entry->objectid] . "', '";
+ $insertion .= $log_entry->logid . "')";
+ $dbms->query($insertion);
+ }
+ }
+ }
+ }
+
+ $qry = "UPDATE db_value SET setting_value = '"
+ . $last_log . "' WHERE setting = 'log_servicecheck'";
+ $dbms->query($qry);
+}
+
+function find_notifications ()
+{
+
+/*
+ * Do something with notification checks.
+ *
+ * INPUT : NONE
+ * OUTPUT : NONE
+ */
+
+ global $dbms;
+
+ // Find checks that have to be executed.
+ $local_sql = "select * from notification_check where
+ age(last_execution) > time_between_executions";
+ $dbms->query($local_sql);
+
+ for ($i=0; $i<$dbms->num_rows(); $i++)
+ {
+ // A check has been found that has to be executed
+ $dbms->fetch_row();
+ }
+}
+
+?>