BUGFIX: Print an error message if a parameter does not have
[gnucomo.git] / src / gcm_daemon / gcm_daemon.php
1 #!/usr/bin/php
2 <?PHP
3 /**********************************************************************************
4 **  (c) Copyright 2002, Brenno J.S.A.A.F. de Winter, De Winter Information Solutions
5 ** This is free software; you can redistribute it and/or modify it under the
6 ** terms of the GNU General Public License, see the file COPYING.
7 ***********************************************************************************/
8
9
10 /* 
11    NAME         : gcm_daemon
12    AUTHOR       : Brenno J.S.A.A.F. de Winter
13                   De Winter Information Solutions
14    COPYRIGHT    : 2002 - De Winter Information Solutions, 
15                   Brenno J.S.A.A.F. de Winter
16    
17    * DATES * 
18    First        : November 8th 2002
19    Gnucomo-0.0.3: December 6th 2002
20
21  $Log: gcm_daemon.php,v $
22  Revision 1.12  2003-08-05 07:46:37  arjen
23  BUGFIX: Print an error message if a parameter does not have
24  any history.
25
26  Revision 1.11  2003/07/09 07:25:02  arjen
27  Gcm_daemon gathers statistics on parameters, notifications, etc. for all objects.
28
29  Revision 1.10  2003/03/29 08:33:58  arjen
30  In phpclasses/db.class.php: Added the database connection string as
31  an argument to the function copy_db_class.
32  Fixed the PHP member function db::db_connect(). The Postgres connection
33  string is now passed as an argument to that function.
34
35  Revision 1.9  2003/02/21 08:37:59  arjen
36  Added new table to the database: log_adv_daemon_email.
37
38
39 */
40
41 // $Id: gcm_daemon.php,v 1.12 2003-08-05 07:46:37 arjen Exp $
42
43 ini_set('include_path', '.:./classes:../phpclasses');
44
45 //Tell the log that we're up.
46 define_syslog_variables();
47 openlog("gnucomo", LOG_PID, LOG_DAEMON);
48 syslog(LOG_INFO, "gcm_daemon started");
49
50 require_once "gnucomo_config.php";
51 require_once "db.class.php";
52 require_once "gnucomo.process_log.php";
53
54 // Set the standard variables //
55 $project_name   = "gnucomo";    //name of the entire project
56 $app_name       = "gcm_daemon"; //name of the application running
57 $developrelease = "TRUE";      //Indicates if special debug settings are needed
58 $db_version     = 42;           //The db_version indicates what the level of 
59                                 //the database should be. If the database is 
60                                 //old an update will be generated.
61 $gcmd_version   = 5;            //This value indicates the active version of the gcm_daemon,
62                                 //which is saved in the database. Log records that were not
63                                 //recognized before will now be recognized. The version doesn't
64                                 //mean anything in the overall gnucomo project.
65
66 //Avoid time-limit issues
67 set_time_limit(0);
68
69
70 // Read the database settings //
71 $class_settings = new gnucomo_config();
72 $class_settings->read($project_name);
73
74 //Open an connection to the database
75 $dbms_type = $class_settings->find_parameter("database", "type");
76 $dbms_host = $class_settings->find_parameter("database", "host");
77 $dbms_name = $class_settings->find_parameter("database", "name");
78 $dbms_user = $class_settings->find_parameter("gcm_daemon", "user");
79 $dbms_password = $class_settings->find_parameter("gcm_daemon", "password");
80
81 db_select($dbms_type);
82 $dbms = new db();
83 $dbms->db_host = $dbms_host;
84 $dbms->db_name = $dbms_name;
85 $dbms->db_user = $dbms_user;
86 $dbms->db_password = $dbms_password;
87 $dbms->db_connect($class_settings->database());
88
89 if ($dbms->have_db_connection() == "FALSE") {
90   exit ("Database connection failed.");
91 } else {
92   //The database connection has been made.
93   $dbms_working = copy_db_class($dbms, $class_settings->database());
94 }
95
96 //Verify if the database is up-to-date by checking the versionnumber
97 $local_sql = "SELECT setting_value FROM db_value WHERE setting = 'db_version' ";
98 $dbms->query($local_sql);
99
100 if ($dbms->fetch_row() == "TRUE") {
101   $active_version = $dbms->db_result_row[0];
102  
103   //Update the database to the most recent version.
104   if ($active_version < $db_version) { 
105      include ("gnucomo_db_version.php");
106   }
107 } else {
108   syslog (LOG_INFO, "Couldn't initialize database version. Is this a gnucomo database?");
109   die ("Couldn't initialize database version.\n");
110 }
111
112 //If there is a new gcm_daemon_version the logrecords that couldn't be understood can be
113 //reprocessed. For this reason processed is now changed to false again for not recognized
114 //records.
115 $local_sql = "SELECT setting_value FROM db_value WHERE setting = 'gcm_daemon_version'";
116 $dbms->query($local_sql);
117
118 if ($dbms->fetch_row() == "TRUE") {
119    if ($dbms->db_result_row[0] < $gcmd_version) {
120       //Reactive log-records that weren't understood earlier.
121       $local_sql = "UPDATE log SET processed = false WHERE logid NOT IN (SELECT DISTINCT logid FROM log_adv)";
122       $dbms->query($local_sql);
123
124       //Update de gcm_daemon version in the database
125       $local_sql = "UPDATE db_value SET setting_value = '".$gcmd_version;
126       $local_sql .= "' WHERE setting = 'gcm_daemon_version'";
127       $dbms->query($local_sql);
128
129    }
130       
131 }
132
133 //Now we loop the tasks that we have to do.
134
135
136 do {
137
138    //  Gather the statistics for each object
139
140    $obj_result = $dbms->query("SELECT objectid FROM object");
141    for ($obj = 0; $obj < $dbms->num_rows($obj_result); $obj++)
142    {
143       $object = $dbms->fetch_object($obj_result, $obj);
144       echo "Gathering statistics for object " . $object->objectid . "\n";
145       GatherStatistics($object->objectid);
146    }
147
148   //At this place we start processing new log-lines 
149   process_log ();
150   //notificationstats();  //  This function is obsolete
151   find_notifications();
152
153   $keep_running = 'FALSE';
154
155 } while ($keep_running == 'TRUE');
156
157 //Tell the log that we're ending our efforts in a nice way
158 syslog (LOG_INFO, "gcm_daemon ended nicely");
159
160 function process_log () {
161  
162  /* This function will walk through the log-records that haven't been processed
163   * first a snapshot will be created of a the non-processed records. 
164   * sequentially each record will dealt with. By doing that changes will be made
165   * in several log_adv_xxx tables
166   * INPUT  : NONE
167   * OUTPUT : NONE
168   */
169   global $dbms;
170   global $dbms_working;
171   global $class_settings;
172
173   //Find records in log that still have to be processed.
174
175   $local_sql = "SELECT setting_value FROM db_value WHERE setting = 'log_processing'";
176   $dbms->query($local_sql);
177
178   if ($dbms->fetch_row() == "TRUE") {
179      $last_log = $dbms->db_result_row[0];
180   }
181   
182   //Query the log-table
183   $local_sql = "SELECT * FROM log WHERE logid > CAST(".$last_log." AS BIGINT) order by logid";
184   $dbms->query($local_sql);
185
186   //Update the log-statistics in the object-table 
187   $local_statistics_db = copy_db_class($dbms, $class_settings->database());
188   $local_findobject_db = copy_db_class($dbms, $class_settings->database());
189
190   //Make totals 
191   $local_upper_row = $dbms->num_rows() + $last_log + 1;
192   $local_sql = "SELECT COUNT(logid), objectid from log WHERE logid > CAST(". $last_log .
193       " AS BIGINT) AND logid < CAST (" . $local_upper_row . " AS BIGINT) GROUP BY objectid";
194   $local_statistics_db->query ($local_sql);
195
196   //Loop the objects
197   for ($i = 1; $i <= $local_statistics_db->num_rows(); $i++) {
198       $local_object_row = $local_statistics_db->fetch_row();
199       $local_sql = "UPDATE object SET log_count = log_count + " . 
200           $local_statistics_db->db_result_row[0] . " WHERE objectid = '" .
201           $local_statistics_db->db_result_row[1] . "'";
202       $local_findobject_db->query($local_sql);  
203   }
204
205   $local_counter = 0;
206
207   if ($dbms->num_rows() > 0) {
208
209     //Create a database connection for changes in the database.
210     $dbms_changes = copy_db_class($dbms, $class_settings->database());
211     if ($dbms_changes->have_db_connection() == 'TRUE') {
212
213        $local_sql               = 0 ;     
214        $local_sql_statistics    = "";
215        $local_object_os         = "";
216        $local_object_os_version = "";
217
218        while ($local_counter < $dbms->num_rows()) {
219
220          $local_return_row = $dbms->fetch_row();
221          if ($local_return_row == 'TRUE') {
222             //Work on active rows
223             $local_log_id = $dbms->db_result_row[0];
224
225             $local_sql_findobject = "SELECT os, os_version FROM object WHERE objectid = '".$dbms->db_result_row[1]."'";
226             $local_findobject_db->query($local_sql_findobject);
227             $local_findobject_result = $local_findobject_db->fetch_row();
228             if ($local_findobject_result == 'TRUE') {
229                 
230                 //Now work on the OS again
231                 $local_object_os = $local_findobject_db->db_result_row[0];
232                 if  ($local_object_os == "") {
233                     $local_object_os = "Linux";
234                     $local_object_os_version = "Unknown assuming Linux";
235                 } else {
236                   $local_object_os_version = $local_findobject_db->db_result_row[1];
237                 }
238              }
239
240             switch (strtolower($local_object_os)) {
241               case "linux":
242                 $local_process_return = linux_log ();
243                 break;
244               default:
245                 syslog (LOG_INFO, "Couldn't find suitable OS for processing the logline");
246                 break;
247              }
248             
249             if ($local_process_return <> 'TRUE') {
250                $local_process_return = 'FALSE';
251             }
252
253          } else {
254
255            break;
256
257          }
258          $local_counter++;
259        } 
260        
261        //Register that the logrecords have been processed.
262        $local_sql = "UPDATE db_value SET setting_value = '".$local_log_id."' where setting = 'log_processing'";
263        $dbms->query($local_sql);
264        
265
266        //Update the statistics for the object-table
267        
268
269      } else {
270        syslog (LOG_INFO, "Couldn't clone database connection.");
271        die ("Couldn't reconnect to the database.\n");
272     }     
273    }
274
275 }
276
277 /*
278  *   Update a single statistic for some object.
279  *   If it does not yet exist, it will be created.
280  */
281
282 function UpdateStatistic($objectid, $name, $value)
283 {
284    global $dbms;
285
286    $result = $dbms->query("SELECT objectid FROM object_statistics WHERE
287              objectid='$objectid' AND statname='$name'");
288    if ($dbms->num_rows() == 0)
289    {
290       $dbms->query("INSERT INTO object_statistics VALUES
291                     ('$objectid', '$name', '$value')");
292    }
293    else
294    {
295       $dbms->query("UPDATE object_statistics SET statvalue='$value' WHERE
296            statname='$name' AND objectid='$objectid'");
297    }
298 }
299
300 /*
301  *   Gather the statistics for a single object ($objectid).
302  *   We count the number of parameters, removed parameters, notifications
303  *   closed notifications and log entries. The totals of these are
304  *   maintained in a separate table: object_statistics.
305  */
306
307 function GatherStatistics($objectid)
308 {
309    global $dbms;
310
311    //  Gather statistics on parameters
312
313    $r = $dbms->query("SELECT paramid FROM parameter WHERE objectid=CAST('"
314                         . $objectid . "' AS BIGINT)");
315    $nr_parameters = $dbms->num_rows($r);
316
317    $removed_parameters = 0;
318    for ($p = 0; $p < $nr_parameters; $p++)
319    {
320       $param = pg_fetch_object($r, $p);
321       $qry ="select change_nature from history where paramid= CAST('";
322       $qry .= $param->paramid . "' AS BIGINT) order by modified desc";
323       $rhist = $dbms->query($qry);
324       if ($dbms->num_rows($rhist) == 0)
325       {
326          echo "ERROR: No history for parameter id " . $param->paramid . "\n";
327       }
328       else
329       {
330          $hist = $dbms->fetch_object($rhist, 0);
331          if ($hist->change_nature == "REMOVED")
332          {
333             $removed_parameters++;
334          }
335       }
336    }
337
338    UpdateStatistic($objectid, 'parameters', $nr_parameters);
339    UpdateStatistic($objectid, 'removed_parameters', $removed_parameters);
340
341    //  Gather statistics on notifications
342
343    $r = $dbms->query("SELECT count(notificationid) FROM notification WHERE
344                        objectid = CAST('" . $objectid . "' AS BIGINT)");
345    $cnt = $dbms->fetch_object($r, 0);
346    UpdateStatistic($objectid, 'notifications', $cnt->count);
347
348    $r = $dbms->query("SELECT count(notificationid) FROM notification WHERE
349                        objectid = CAST('" . $objectid . "' AS BIGINT) AND statuscode ='cls'");
350    $cnt = $dbms->fetch_object($r, 0);
351    UpdateStatistic($objectid, 'closed_notifications', $cnt->count);
352
353    //  Gather statistics on log entries
354
355    $r = $dbms->query("SELECT count(logid) FROM log WHERE
356                        objectid = CAST('" . $objectid . "' AS BIGINT)");
357    $cnt = $dbms->fetch_object($r, 0);
358    UpdateStatistic($objectid, 'logs', $cnt->count);
359 }
360
361 function notificationstats ()
362 {
363
364   //    OBSOLETE   //
365
366 /* This routine will determine how many new notifications have arrived and will
367  * update the statistics in the object-table to keep the performance acceptable
368  * INPUT  : NONE
369  * OUTPUT : NONE
370  */
371             
372  global $dbms, $class_settings;
373
374  //Find records in log that still have to be processed.
375  $local_sql = "SELECT setting_value FROM db_value WHERE setting = 'last_notification'";
376  $dbms->query($local_sql);
377  $local_dbms = copy_db_class($dbms, $class_settings->database());
378
379  //Determine the last notification
380  if ($dbms->fetch_row() == "TRUE") {
381     $last_notification = $dbms->db_result_row[0];
382  }
383  
384  //Determine how many records we are going to analyse.
385  $local_sql = "SELECT MAX(notificationid) FROM notification " .
386    "WHERE notificationid > CAST ('" . $last_notification . "' AS BIGINT)";
387  $dbms->query($local_sql);  
388
389  //Only process data if there are new notifications
390  if ($dbms->fetch_row() == "TRUE") {
391   if (intval($dbms->db_result_row[0])>0) {
392      $local_upper = $dbms->db_result_row[0] + 1;
393      $local_max   = $dbms->db_result_row[0];
394      $local_sql   = "SELECT COUNT(objectid), objectid FROM notification " .
395        "WHERE notificationid > CAST ('" .  $last_notification ."' AS BIGINT) " .
396        "AND   notificationid < CAST ('" .  $local_upper .
397        "' AS BIGINT) GROUP BY objectid";
398      $dbms->query($local_sql);
399
400
401      for ($i=0; $i < $dbms->num_rows(); $i++) {
402        $dbms->fetch_row();
403     
404        $local_sql = "UPDATE object SET notification_count = notification_count + " . $dbms->db_result_row[0] .
405          " WHERE objectid = '" . $dbms->db_result_row[1] . "'";
406       $local_dbms->query($local_sql); 
407      }  
408
409      $local_sql = "UPDATE db_value SET setting_value = '" . $local_max . 
410        "' WHERE setting = 'last_notification'";
411      $dbms->query($local_sql);  
412   }   
413  } 
414 }
415
416 function find_notifications () {
417
418 /*
419  *  Do something with notification checks.
420  *
421  * INPUT  : NONE
422  * OUTPUT : NONE
423  */
424     
425  global $dbms;
426
427  //Find checks that have to be executed.
428  $local_sql = "select * from notification_check where age(last_execution) > time_between_executions";
429  $dbms->query($local_sql);
430  for ($i=0; $i<$dbms->num_rows(); $i++) {
431      //A check has been found that has to be executed 
432      $dbms->fetch_row();
433  }
434 }
435
436 ?>
437