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