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