File:
1.13.3b/server/base/freenats.inc.php (
View as Code)
1: 2: /* -------------------------------------------------------------
3: This file is part of FreeNATS
4:
5: FreeNATS is (C) Copyright 2008-2011 PurplePixie Systems
6:
7: FreeNATS is free software: you can redistribute it and/or modify
8: it under the terms of the GNU General Public License as published by
9: the Free Software Foundation, either version 3 of the License, or
10: (at your option) any later version.
11:
12: FreeNATS is distributed in the hope that it will be useful,
13: but WITHOUT ANY WARRANTY; without even the implied warranty of
14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15: GNU General Public License for more details.
16:
17: You should have received a copy of the GNU General Public License
18: along with FreeNATS. If not, see www.gnu.org/licenses
19:
20: For more information see www.purplepixie.org/freenats
21: -------------------------------------------------------------- */
22:
23: class TFreeNATS
24: {
25: var $init=false;
26: var $DB;
27: var $Cfg;
28: var $Tests;
29: var $Lang;
30: var $RSS;
31: var $Version="1.13.3";
32: var $Release="b";
33: var $EventHandlers=array();
34:
35: var $PageErrors=array();
36:
37: function TFreeNATS()
38: {
39: $this->Tests=new TNATS_Tests(); // need this available during the include phase pre-start
40: }
41:
42: function Start()
43: {
44: if ($this->init) return 0;
45: global $BaseDir,$fnSkipSiteIncludes;
46: if ( (!isset($BaseDir)) || ($BaseDir=="") ) $BaseDir="./";
47: $this->DB=new TNATS_DB();
48: $this->Cfg=new TNATS_Cfg();
49: $this->DB->Connect();
50: $this->Cfg->Load($this->DB);
51: // Site Includes
52: // Tests
53: if ( (!isset($fnSkipSiteIncludes)) || ($fnSkipSiteIncludes === false) )
54: {
55:
56: if ($this->Cfg->Get("site.include.tests",0)==1)
57: {
58: foreach(glob($BaseDir."site/tests/*.php") as $phpfile)
59: {
60: $this->Event("Including ".$phpfile,10,"NATS","Start");
61: include_once($phpfile);
62: }
63: }
64: // Events
65: if ($this->Cfg->Get("site.include.events",0)==1)
66: {
67: foreach(glob($BaseDir."site/events/*.php") as $phpfile)
68: {
69: $this->Event("Including ".$phpfile,10,"NATS","Start");
70: include_once($phpfile);
71: }
72: }
73: }
74:
75: // RSS
76: $this->RSS = new NATS_RSS();
77:
78: // Language
79: $this->Lang=new TNATS_Lang();
80: if (isset($_COOKIE['fn_lang']) && ($_COOKIE['fn_lang']!="") ) $l=$_COOKIE['fn_lang'];
81: else $l=$this->Cfg->Get("site.language","");
82: $this->Lang->Load($l);
83:
84:
85: $this->init=true;
86: }
87:
88: function Stop()
89: {
90: $t=$this->Cfg->Get("freenats.tracker","");
91: if ( ($t>0) && ($t!="") )
92: {
93: $day=date("Ymd");
94: if ($this->Cfg->Get("freenats.tracker.last","")!=$day)
95: {
96: $this->Cfg->Set("freenats.tracker.last",$day);
97: $this->PhoneHome();
98: }
99: }
100:
101: $this->DB->Disconnect();
102: $this->init=false;
103: }
104:
105: function Event($logevent,$loglevel=1,$modid="NONE",$catid="NONE")
106: {
107: global $NATS_Session;
108: if ((isset($NATS_Session))&&($NATS_Session->auth)) $username=$NATS_Session->username;
109: else $username="";
110: $l=$this->Cfg->Get("log.level");
111: //echo "** $l **\n";
112: if ( $l=="" ) $l=10; // debug logging if no variable
113: if ( $l < $loglevel ) return false;
114: if (strlen($logevent)>249) $logevent=substr($logevent,0,245)."...";
115: $q="INSERT INTO fnlog(postedx,modid,catid,loglevel,logevent,username) VALUES(".time().",";
116: $q.="\"".ss($modid)."\",\"".ss($catid)."\",".ss($loglevel).",\"".ss($logevent)."\",\"".ss($username)."\")";
117: //echo $q;
118: $this->DB->Query($q,false);
119: }
120:
121: function AlertAction($nodeid,$alertlevel,$change,$alerttext)
122: {
123: //echo "Called for node: ".$nodeid."\n";
124: if ($change==0) return false; // no change
125: if (trim($alerttext)=="") return false; // no text so a bogus event i.e. -1 to 0
126: //echo $nodeid.":".$alertlevel.":".$change.":".$alerttext."\n";
127: // get all the alertactions for this node id
128: $q="SELECT aaid FROM fnnalink WHERE nodeid=\"".ss($nodeid)."\"";
129: $r=$this->DB->Query($q);
130: while ($arow=$this->DB->Fetch_Array($r))
131: {
132: // get details for this alert action
133: $aq="SELECT * FROM fnalertaction WHERE aaid=".$arow['aaid']." LIMIT 0,1";
134:
135: $ar=$this->DB->Query($aq);
136: $aa=$this->DB->Fetch_Array($ar);
137: $this->DB->Free($ar);
138:
139: // UGGGGGGGG continue!!
140: // if the type is blank or disabled skip
141: if ( ($aa['atype']=="") || ($aa['atype']=="Disabled") ) continue;
142: // if warnings aren't set and it is a warning skip
143: if ( ($aa['awarnings']==0) && ($alertlevel==1) ) continue;
144: // if decreases aren't set and it is a decrease skip
145: if ( ($aa['adecrease']==0) && ($change<1) ) continue;
146: // if has a schedule and it dictates not to run now then skip
147: if (($aa['scheduleid']!=0)&&(!run_x_in_schedule(time(),$aa['scheduleid']))) continue;
148:
149: // made it this far
150:
151: $ndata=$nodeid.": ".$alerttext;
152: $this->ActionAddData($arow['aaid'],$ndata);
153:
154: /* // spun to ActionAddData
155: if ($aa['mdata']!="") $ndata=$aa['mdata']."\n".$nodeid.": ".$alerttext;
156: else $ndata=$nodeid.": ".$alerttext;
157: $uq="UPDATE fnalertaction SET mdata=\"".ss($ndata)."\" WHERE aaid=".$arow['aaid'];
158: //echo $uq."\n";
159: $this->DB->Query($uq);
160: */
161: }
162: }
163:
164: function ActionAddData($aaid, $newmdata)
165: {
166: $q="SELECT aaid,mdata FROM fnalertaction WHERE aaid=".ss($aaid)." LIMIT 0,1";
167: $r=$this->DB->Query($q);
168: if (!$row=$this->DB->Fetch_Array($r)) return false;
169: $this->DB->Free($r);
170:
171: if ($row['mdata']!="") $ndata=$row['mdata']."\n".$newmdata;
172: else $ndata=$newmdata;
173:
174: $uq="UPDATE fnalertaction SET mdata=\"".ss($ndata)."\" WHERE aaid=".$row['aaid'];
175: $this->DB->Query($uq);
176: return true;
177: }
178:
179: function ActionFlush()
180: {
181: global $allowed,$BaseDir; // allowed chars from screen in YA BODGE
182: $q="SELECT * FROM fnalertaction WHERE mdata!=\"\"";
183: $r=$this->DB->Query($q);
184: while ($row=$this->DB->Fetch_Array($r))
185: {
186:
187: $doalert=true;
188:
189: // clear mdata right at the start to get around duplicate emails whilst processing
190: $q="UPDATE fnalertaction SET mdata=\"\" WHERE aaid=".$row['aaid'];
191: $this->DB->Query($q);
192:
193: if ($this->DB->Affected_Rows()<=0) // already flushed or failed to flush
194: {
195: $doalert=false;
196: $this->Event("Alert Action Already Flushed - Skipping",8,"Flush","Action");
197: }
198:
199: // alert counter
200: $td=date("Ymd");
201: if ($td!=$row['ctrdate']) // new day or no flush record
202: {
203: $q="UPDATE fnalertaction SET ctrdate=\"".$td."\",ctrtoday=1 WHERE aaid=".$row['aaid'];
204: $this->DB->Query($q);
205: }
206: else
207: {
208:
209: if ( ($row['ctrlimit']==0) || ($row['ctrlimit']>$row['ctrtoday']) ) // no limit or below
210: {
211: $q="UPDATE fnalertaction SET ctrtoday=ctrtoday+1 WHERE aaid=".$row['aaid'];
212: $this->DB->Query($q);
213: }
214: else // at or over limit
215: {
216: $this->Event("Alert Action Limit Reached - Skipping",2,"Flush","Action");
217: $doalert=false;
218: }
219:
220: }
221:
222:
223: if ($row['atype']=="email")
224: {
225: if ($row['esubject']==0) $sub="";
226: else if ($row['esubject']==1) $sub=$this->Cfg->Get("alert.subject.short","FreeNATS Alert");
227: else $sub=$this->Cfg->Get("alert.subject.long","** FreeNATS Alert **");
228: $body="";
229: if ($row['etype']==0) $body=$row['mdata'];
230: else
231: {
232: $body=$this->Cfg->Get("alert.body.header","FreeNATS Alert,");
233: $body.="\r\n\r\n".$row['mdata']."\r\n\r\n";
234: $body.=$this->Cfg->Get("alert.body.footer","");
235: $body.="\r\n-- FreeNATS @ ".nicedt(time());
236: }
237: //$tolist=preg_split("[\n\r]",$row['etolist']);
238: $tolist=array();
239: $f=0;
240: $tolist[0]="";
241: for ($a=0; $a242: {
243: $chr=$row['etolist'][$a];
244: //echo $chr;
245: if (strpos($allowed,$chr)===false) // special char
246: {
247: $f++;
248: $tolist[$f]="";
249: }
250: else
251: {
252: $tolist[$f].=$chr;
253: }
254: }
255:
256: foreach($tolist as $toaddr)
257: {
258: $toaddr=nices($toaddr);
259: if ($toaddr!="")
260: {
261: $smtpserver=$this->Cfg->Get("mail.smtpserver","");
262: if ($smtpserver=="")
263: {
264: // mail() method - local delivery
265: $header="From: ".$row['efrom']."\r\n";
266: if ($doalert)
267: {
268: mail($toaddr,$sub,$body,$header);
269: $this->Event("Sent alert email to ".$toaddr,4,"Flush","Email");
270: }
271: }
272: else // use phpmailer direct SMTP delivery
273: {
274: include_once($BaseDir."phpmailer/class.phpmailer.php");
275: $fromname=$this->Cfg->Get("mail.fromname","");
276: if ($fromname=="") $fromname="FreeNATS";
277: $smtpusername=$this->Cfg->Get("mail.smtpusername",""); // removed .
278: if ($smtpusername!="") $smtpauth=true;
279: else $smtpauth=false;
280: $smtppassword=$this->Cfg->Get("mail.smtppassword",""); // removed .
281: $smtphostname=$this->Cfg->Get("mail.smtphostname",""); // removed .
282: $smtpsec=$this->Cfg->Get("mail.smtpsecure","");
283: $mail=new PHPMailer();
284: $mail->IsSMTP();
285: $mail->Host=$smtpserver;
286: $mail->From=$row['efrom'];
287: $mail->FromName=$fromname;
288: $mail->AddAddress($toaddr);
289: $mail->Subject=$sub;
290: $mail->Body=$body;
291: $mail->WordWrap=50;
292: if ($smtphostname!="") $mail->Hostname=$smtphostname;
293: if ($smtpauth)
294: {
295: $mail->SMTPAuth=true;
296: $mail->Username=$smtpusername;
297: $mail->Password=$smtppassword;
298: }
299: if ($smtpsec!="") $mail->SMTPSecure=$smtpsec;
300: if (!$mail->Send())
301: { // failed
302: $this->Event("phpMailer to ".$toaddr." failed",1,"Flush","Email");
303: $this->Event("phpMailer Error: ".$mail->ErrorInfo,1,"Flush","Email");
304: }
305: else
306: {
307: $this->Event("phpMailer Sent Email To ".$toaddr,4,"Flush","Email");
308: }
309: }
310:
311: }
312: }
313:
314:
315:
316: }
317: else if ($row['atype']=="url")
318: {
319: // url send
320: if ($row['etype']==0) $body=$row['mdata'];
321: else $body="FreeNATS Alert,\r\n".$row['mdata']."\r\n--FreeNATS @ ".nicedt(time());
322:
323: $body=urlencode($body);
324: $tolist=array();
325: $f=0;
326: $tolist[0]="";
327: for ($a=0; $a328: {
329: $chr=$row['etolist'][$a];
330: //echo $chr;
331: if (strpos($allowed,$chr)===false) // special char
332: {
333: $f++;
334: $tolist[$f]="";
335: }
336: else
337: {
338: $tolist[$f].=$chr;
339: }
340: }
341:
342: foreach($tolist as $tourl)
343: {
344: if ($doalert)
345: {
346: $url=$tourl.$body;
347: $fp=@fopen($url,"r");
348: if ($fp>0) fclose($fp);
349: else $this->Event("URL Alert Failed ".$url,1,"Flush","URL");
350: $this->Event("URL Alert ".$url,4,"Flush","URL");
351: }
352: }
353:
354:
355: }
356: else if ($row['atype']=="mqueue")
357: {
358: // message queue
359: $eventdata=array("aaid"=>$row['aaid'],"name"=>$row['aname'],"data"=>$row['mdata']);
360: $result=$this->EventHandler("alert_action",$eventdata);
361: if ($result===false) // put the data back into the queue
362: {
363: $q="UPDATE fnalertaction SET mdata=\"".$row['mdata']."\"+mdata WHERE aaid=".$row['aaid'];
364: $this->DB->Query($q);
365: if ($this->DB->Affected_Rows()<=0)
366: $this->Event("Persist MDATA Failed for AAID ".$row['aaid'],2,"Flush","MQueue");
367: }
368: else $this->Event("Queue Cleared for AAID ".$row['aaid']." by Handler",4,"Flush","MQueue");
369: }
370:
371: }
372: }
373:
374: function GetAlerts()
375: {
376: $q="SELECT nodeid,alertlevel FROM fnalert WHERE closedx=0";
377: $r=$this->DB->Query($q);
378: $c=0;
379: $al=array();
380: while ($row=$this->DB->Fetch_Array($r))
381: {
382: $al[$c]['nodeid']=$row['nodeid'];
383: $al[$c]['alertlevel']=$row['alertlevel'];
384: $c++;
385: }
386: if ($c>0) return $al;
387: else return false;
388: }
389:
390: function SetAlerts($nodeid,$alertlevel,$alerts="")
391: {
392: if ($alerts=="") $alerts=array();
393: // get current alert level
394: $q="SELECT alertlevel,nodealert FROM fnnode WHERE nodeid=\"".ss($nodeid)."\"";
395: $r=$this->DB->Query($q);
396: $row=$this->DB->Fetch_Array($r);
397: $this->DB->Free($r);
398: $cal=$row['alertlevel'];
399:
400: $eventdata=array("nodeid"=>$nodeid,"alertlevel"=>$alertlevel,
401: "oldalertlevel"=>$cal);
402: $this->EventHandler("set_alerts",$eventdata);
403:
404: if ($alertlevel!=$cal)
405: {
406: // update table
407: $q="UPDATE fnnode SET alertlevel=".ss($alertlevel)." WHERE nodeid=\"".ss($nodeid)."\"";
408: $this->DB->Query($q);
409: }
410:
411: // do not continue if node alert isn't set
412: if ($row['nodealert']!=1) return 0;
413: // or if untested
414: if ($alertlevel<0) return 0;
415:
416: // ALERTS
417: // is there an existing alert for this node
418: $q="SELECT alertid,alertlevel FROM fnalert WHERE nodeid=\"".ss($nodeid)."\" AND closedx=0";
419: $r=$this->DB->Query($q);
420: if ($row=$this->DB->Fetch_Array($r))
421: { // yes there is
422: // if new alert level is 0 let's close it
423: if ($alertlevel==0)
424: {
425: $alertid=$row['alertid'];
426: $q="UPDATE fnalert SET closedx=".time()." WHERE alertid=".$row['alertid'];
427: $this->DB->Query($q);
428: $closetext=$this->Cfg->Get("site.text.closed","Alert Closed");
429: if (is_array($alerts)) $alerts[]=$closetext;
430: else
431: {
432: $alerts=array($alerts); // add as first element to new array
433: $alerts[]=$closetext;
434: }
435: $eventdata=array("nodeid"=>$nodeid);
436: $this->EventHandler("alert_close",$eventdata);
437: }
438: else
439: {
440: $alertid=$row['alertid'];
441: // otherwise update the alert to the new value (was: regardless, now just if not a 0)
442: $q="UPDATE fnalert SET alertlevel=".ss($alertlevel)." WHERE alertid=".$alertid;
443: $this->DB->Query($q);
444: }
445: }
446: else
447: { // no there's not
448: $cal=0; // the cal (current alert level) goes to zero if it's a new alert so alert_actions fire ok
449: if ($alertlevel>0) // only if an actual alert
450: {
451: $q="INSERT INTO fnalert(nodeid,alertlevel,openedx) VALUES(";
452: $q.="\"".ss($nodeid)."\",".ss($alertlevel).",".time().")";
453: $this->DB->Query($q);
454: $alertid=$this->DB->Insert_Id();
455: $eventdata=array("nodeid"=>$nodeid);
456: $this->EventHandler("alert_open",$eventdata);
457: }
458: }
459: // ALERT LOG with $alertid
460: $t=time();
461: $at="";
462: if (is_array($alerts))
463: {
464: foreach($alerts as $alert)
465: {
466: if (isset($alertid)) // misses on manual runs methinx
467: {
468: if ($at!="") $at.=", ";
469: $at.=$alert;
470: //echo $at."\n";
471: $iq="INSERT INTO fnalertlog(alertid,postedx,logentry) VALUES(";
472: $iq.=$alertid.",".$t.",\"".ss($alert)."\")";
473: //echo $iq;
474: $this->DB->Query($iq);
475: }
476: }
477: }
478:
479: $this->AlertAction($nodeid,$alertlevel,$alertlevel-$cal,$at);
480:
481:
482:
483: }
484:
485: function NodeAlertLevel($nodeid)
486: {
487: $q="SELECT alertlevel FROM fnnode WHERE nodeid=\"".ss($nodeid)."\"";
488: $r=$this->DB->Query($q);
489: if ($row=$this->DB->Fetch_Array($r)) return $row['alertlevel'];
490: else return -1;
491: }
492:
493: function GroupAlertLevel($groupid)
494: {
495: $lvl=-1;
496: $q="SELECT nodeid FROM fngrouplink WHERE groupid=\"".ss($groupid)."\"";
497: $r=$this->DB->Query($q);
498: while ($row=$this->DB->Fetch_Array($r))
499: {
500: $nl=$this->NodeAlertLevel($row['nodeid']);
501: if ($nl>$lvl) $lvl=$nl;
502: }
503: $this->DB->Free($r);
504: return $lvl;
505: }
506:
507: function PhoneHome($mode=0,$type="ping") // 0 - php, 1 - html, 2 - data
508: {
509: if ($mode<2)
510: {
511: $qs="?type=".$type."&data=v=".$this->Version;
512: if (isset($_SERVER['REMOTE_ADDR']))
513: $qs.=",ip=".$_SERVER['REMOTE_ADDR'];
514: $ploc="http://www.purplepixie.org/freenats/report/";
515: if ($mode==1) $ploc.="ping.html";
516: else $ploc.="ping.php";
517:
518: $ploc.=$qs;
519:
520: $lp=@fopen($ploc,"r");
521: if ($lp>0) @fclose($lp);
522: }
523: else
524: {
525: // data post -- !!
526: }
527: }
528:
529: function GetNode($nodeid)
530: {
531: $return_row=false;
532: $q="SELECT * FROM fnnode WHERE nodeid=\"".ss($nodeid)."\" LIMIT 0,1";
533: $r=$this->DB->Query($q);
534: if ($row=$this->DB->Fetch_Array($r))
535: $return_row=true;
536:
537: $this->DB->Free($r);
538: if ($return_row) // found a valid
539: {
540: if ($row['nodename']!="") $row['name']=$row['nodename']; // make a "nice" name for it
541: else $row['name']=$row['nodeid'];
542:
543: $row['alerttext']=oText($row['alertlevel']); // textual alert status
544:
545: $row['lastrundt']=nicedt($row['lastrunx']); // text date-time last run
546: $row['lastrunago']=dtago($row['lastrunx'],false); // last run ago
547:
548: // protection
549: $row['nskey']="";
550:
551: return $row;
552: }
553: else
554: return false; // or failed
555: }
556:
557: function GetNodes()
558: {
559: $out=array();
560: $q="SELECT * FROM fnnode";
561: $r=$this->DB->Query($q);
562:
563: while ($row=$this->DB->Fetch_Array($r))
564: {
565: if ($row['nodename']!="") $row['name']=$row['nodename']; // make a "nice" name for it
566: else $row['name']=$row['nodeid'];
567:
568: $row['alerttext']=oText($row['alertlevel']); // textual alert status
569:
570: $row['lastrundt']=nicedt($row['lastrunx']); // text date-time last run
571: $row['lastrunago']=dtago($row['lastrunx'],false); // last run ago
572:
573: // protection
574: $row['nskey']="";
575:
576: $out[$row['nodeid']]=$row;
577: }
578: $this->DB->Free($r);
579:
580: return $out;
581: }
582:
583:
584: function GetNodeTests($nodeid)
585: { // returns an array of testids for the node (enabled tests only)
586: $tests=array();
587:
588: // local tests
589: $q="SELECT localtestid FROM fnlocaltest WHERE testenabled=1 AND nodeid=\"".ss($nodeid)."\" ORDER BY localtestid ASC";
590: $r=$this->DB->Query($q);
591: while ($row=$this->DB->Fetch_Array($r))
592: {
593: $tests[]="L".$row['localtestid'];
594: }
595: $this->DB->Free($r);
596:
597: // nodeside
598: $q="SELECT nstestid FROM fnnstest WHERE testenabled=1 AND nodeid=\"".ss($nodeid)."\" ORDER BY testtype ASC";
599: $r=$this->DB->Query($q);
600: while ($row=$this->DB->Fetch_Array($r))
601: {
602: $tests[]="N".$row['nstestid'];
603: }
604: $this->DB->Free($r);
605:
606: return $tests;
607: }
608:
609: function SetNode($nodeid,$data)
610: {
611: $q="UPDATE fnnode SET ";
612: $first=true;
613: foreach($data as $key => $val)
614: {
615: if ($first) $first=false;
616: else $q.=",";
617: $q.=ss($key)."=\"".ss($val)."\"";
618: }
619: $q.=" WHERE nodeid=\"".ss($nodeid)."\"";
620: $this->DB->Query($q);
621: if ($this->DB->Affected_Rows()>0) return true;
622:
623: if ($this->DB->Error()) // query failed
624: {
625: $errstr1="Query Failed: ".$q;
626: $errstr2="Query Failed: ".$this->DB->Error_String();
627: $this->Event($errstr1,2,"Node","Set");
628: $this->Event($errstr1,2,"Node","Set");
629: return false;
630: }
631: return true; // query succeeded but nothing was updated
632: }
633:
634: function EnableNode($nodeid,$enabled=true)
635: {
636: if ($enabled) $ne=1;
637: else $ne=0;
638: $data=array("nodeenabled"=>$ne);
639: return $this->SetNode($nodeid,$data);
640: }
641:
642: function DisableNode($nodeid)
643: {
644: return $this->EnableNode($nodeid,false);
645: }
646:
647: function SetNodeSchedule($nodeid,$scheduleid)
648: {
649: $data=array("scheduleid"=>$scheduleid);
650: return $this->SetNode($nodeid,$data);
651: }
652:
653: function GetGroup($groupid)
654: {
655: $q="SELECT * FROM fngroup WHERE groupid=".ss($groupid)." LIMIT 0,1";
656: $r=$this->DB->Query($q);
657: if (!$row=$this->DB->Fetch_Array($r)) return false;
658:
659: $this->DB->Free($r);
660: $row['alertlevel']=$this->GroupAlertLevel($groupid);
661: $row['alerttext']=oText($row['alertlevel']);
662: return $row;
663: }
664:
665: function GetGroups()
666: {
667: $out=array();
668: $q="SELECT * FROM fngroup";
669: $r=$this->DB->Query($q);
670:
671: while ($row=$this->DB->Fetch_Array($r))
672: {
673: $row['alertlevel']=$this->GroupAlertLevel($row['groupid']);
674: $row['alerttext']=oText($row['alertlevel']);
675: $out[$row['groupid']]=$row;
676: }
677:
678: $this->DB->Free($r);
679: return $out;
680: }
681:
682: function GetTest($testid,$protect=false)
683: {
684: if ($testid=="") return false;
685: $class=$testid[0];
686: if (is_numeric($class))
687: {
688: // test ID will stay the same
689: $class="L";
690: $anytestid=$testid;
691: }
692: else
693: {
694: //$testid=substr($testid,1); // as it will here also so direct use to graphs can be made
695: $anytestid=substr($testid,1); // the classless version
696: }
697:
698: $q="";
699: switch($class)
700: {
701: case "L": // local tests
702: $q="SELECT * FROM fnlocaltest WHERE localtestid=".ss($anytestid)." LIMIT 0,1";
703: break;
704: case "N": // node-side test
705: $q="SELECT * FROM fnnstest WHERE nstestid=".ss($anytestid)." LIMIT 0,1";
706: break;
707: default:
708: return false; // can't lookup this class
709: }
710:
711: if ($q=="") return false;
712:
713: $r=$this->DB->Query($q);
714:
715: if (!$row=$this->DB->Fetch_Array($r)) return false;
716:
717: $row['class']=$class;
718: $row['testid']=$testid;
719: $row['anytestid']=$anytestid;
720: $row['alerttext']=oText($row['alertlevel']);
721: $row['lastrundt']=nicedt($row['lastrunx']);
722: $row['lastrunago']=dtago($row['lastrunx'],false);
723:
724: if ($row['testname']!="") $row['name']=$row['testname'];
725: else
726: {
727: if ($class=="L")
728: {
729: $row['name']=lText($row['testtype']); // TODO OTHER TESTS
730: if ($row['testparam']!="") $row['name'].=" (".$row['testparam'].")";
731: }
732: else if ($class=="N")
733: {
734: if ($row['testdesc']!="") $row['name']=$row['testdesc'];
735: else $row['name']=$row['testtype'];
736: }
737: }
738:
739: if ($protect&&($class=="L")) // module test protection
740: {
741: if ($this->Tests->Exists($row['testtype'])) // in the module register
742: {
743: $this->Tests->Tests[$row['testtype']]->Create();
744: $this->Tests->Tests[$row['testtype']]->instance->ProtectOutput($row);
745: }
746: }
747:
748: $this->DB->Free($r);
749:
750: return $row;
751: }
752:
753:
754: function DeleteTest($testid)
755: {
756: if ($testid=="") return false;
757: $class=$testid[0];
758: if (is_numeric($class))
759: {
760: // test ID will stay the same
761: $class="L";
762: $anytestid=$testid;
763: }
764: else
765: {
766: $anytestid=substr($testid,1); // the classless version
767: }
768:
769: $q="";
770: switch($class)
771: {
772: case "L": // local tests
773: $q="DELETE FROM fnlocaltest WHERE localtestid=".ss($anytestid);
774: break;
775: case "N": // node-side test
776: $q="DELETE FROM fnnstest WHERE nstestid=".ss($anytestid);
777: break;
778: default:
779: return false; // can't lookup this class
780: }
781:
782: if ($q=="") return false;
783:
784: $this->DB->Query($q);
785: $tests=$this->DB->Affected_Rows();
786:
787: $rq="DELETE FROM fnrecord WHERE testid=\"".ss($testid)."\"";
788: $this->DB->Query($rq);
789: $records=$this->DB->Affected_Rows();
790:
791: $eq="DELETE FROM fneval WHERE testid=\"".ss($testid)."\"";
792: $this->DB->Query($eq);
793: $eval=$this->DB->Affected_Rows();
794:
795: $s="Deleted test ".$testid." (".$tests." tests, ".$records." records, ".$eval." evaluators)";
796: $this->Event($s,6,"Test","Delete");
797: }
798:
799:
800:
801: function InvalidateTest($testid,$rightnow=false)
802: {
803: $class=$testid[0];
804: if (is_numeric($class)) $class="L";
805: else $testid=substr($testid,1);
806: if ($rightnow)
807: {
808: $nextx=time();
809: $q="UPDATE ";
810: if ($class=="L") $q.="fnlocaltest";
811: // other ones here
812:
813: $q.=" SET nextrunx=".$nextx." WHERE ";
814:
815: if ($class=="L") $q.="localtestid=".$testid;
816: // other ones here
817:
818: $this->DB->Query($q);
819: return true;
820: }
821: // otherwise use it's interval
822: $q="SELECT testinterval FROM ";
823:
824: if ($class=="L") $q.="fnlocaltest WHERE localtestid=";
825: // other ones here
826:
827: $q.=$testid;
828: $r=$this->DB->Query($q);
829: if ($row=$this->DB->Fetch_Array($r))
830: {
831: $this->DB->Free($r);
832: $nextx=next_run_x($row['testinterval']);
833: $q="UPDATE ";
834: if ($class=="L") $q.="fnlocaltest";
835: // other ones here
836:
837: $q.=" SET nextrunx=".$nextx." WHERE ";
838:
839: if ($class=="L") $q.="localtestid=".$testid;
840: // other ones here
841:
842: $this->DB->Query($q);
843: return true;
844: }
845: return false;
846: }
847:
848: function InvalidateNode($nodeid,$rightnow=false,$testsaswell=false)
849: {
850: if ($rightnow)
851: {
852: $nextx=time();
853: $q="UPDATE fnnode SET nextrunx=".$nextx." WHERE nodeid=\"".ss($nodeid)."\"";
854: $this->DB->Query($q);
855: if ($testsaswell)
856: {
857: $q="UPDATE fnlocaltest SET nextrunx=".$nextx." WHERE nodeid=\"".ss($nodeid)."\"";
858: $this->DB->Query($q);
859: }
860: return true;
861: }
862: // otherwise set to it's interval
863: $q="SELECT testinterval FROM fnnode WHERE nodeid=\"".ss($nodeid)."\"";
864: $r=$this->DB->Query($q);
865: if ($row=$this->DB->Fetch_Array($r))
866: {
867: $nextx=next_run_x($row['testinterval']);
868: $uq="UPDATE fnnode SET nextrunx=".$nextx." WHERE nodeid=\"".ss($nodeid)."\"";
869: $this->DB->Query($uq);
870: $this->DB->Free($r);
871: if ($testsaswell)
872: {
873: $uq="UPDATE fnlocaltest SET nextrunx=".$nextx." WHERE nodeid=\"".ss($nodeid)."\"";
874: $this->DB->Query($uq);
875: }
876: return true;
877: }
878: return false;
879: }
880:
881:
882: function NodeSide_Pull($nodeid)
883: {
884: $eventdata=array("nodeid"=>$nodeid,"success"=>false);
885: $q="SELECT nsenabled,nspullenabled,nsurl,nskey,nsinterval FROM fnnode WHERE nodeid=\"".ss($nodeid)."\" LIMIT 0,1";
886: $r=$this->DB->Query($q);
887: if (!$row=$this->DB->Fetch_Array($r)) return false;
888:
889: $this->DB->Free($r);
890:
891: $url=$row['nsurl'];
892: if ($row['nskey']!="") $url.="?nodekey=".$row['nskey'];
893: //echo $url."\n";
894: $this->Event("NodeSide_Pull Started for ".$nodeid,10,"Node","Pull");
895:
896: $xmlobj=new TNodeXML();
897:
898: $fp=@fopen($url,"r");
899: if ($fp<=0)
900: {
901: $this->Event("Pull Failed URL ".$url,1,"Node","Pull");
902: $this->EventHandler("nodeside_pull",$eventdata);
903: return false;
904: }
905: $xml="";
906: while (!feof($fp))
907: {
908: $xml.=fgets($fp,4096);
909: }
910: if ($xml=="")
911: {
912: $this->EventHandler("nodeside_pull",$eventdata);
913: return false;
914: }
915:
916: //echo $xml;
917:
918: $result=$xmlobj->Parse($xml);
919:
920: if ($xmlobj->Error()!="")
921: {
922: $this->Event("NodeXML Error: ".$xmlobj->Error(),1,"Node","Pull");
923: $this->EventHandler("nodeside_pull",$eventdata);
924: return false;
925: }
926: $this->Event("NodeSide_Pull Fetched ".$xmlobj->Tests." tests for ".$nodeid,10,"Node","Pull");
927: // Now just to actually process it...
928: $eventdata['success']=true;
929: $this->EventHandler("nodeside_pull",$eventdata);
930: $this->NodeSide_Process($nodeid,$xmlobj);
931: return true;
932: }
933:
934: function NodeSide_Process($nodeid,&$xmlobj)
935: { // nodeid + takes a TNodeXML Object
936: $alvl=0;
937: $this->Event("NodeSide_Process for ".$nodeid,10,"Node","Pull");
938: $q="SELECT * FROM fnnstest WHERE nodeid=\"".ss($nodeid)."\"";
939: $r=$this->DB->Query($q);
940: $tests=array();
941: while ($row=$this->DB->Fetch_Array($r))
942: {
943: $tests[$row['testtype']]=$row;
944: if (isset($xmlobj->Catalogue[$row['testtype']]))
945: { // this test is in the DB and catalogue
946: $tests[$row['testtype']]['incat']=true;
947: if ($row['testenabled']==1) // it is enabled - so we test it
948: {
949: if ($row['simpleeval']==1) $level=$xmlobj->Catalogue[$row['testtype']]['ALERTLEVEL']; // use provided level
950: else $level=nats_eval("N".$row['nstestid'],$xmlobj->Catalogue[$row['testtype']]['VALUE']);
951: $dbs="Nodeside ".$row['testtype']." on ".$row['nodeid']." = ".$level;
952: if ($level==0) $debuglev=8;
953: else if ($level>0) $debuglev=5;
954: else $debuglev=2;
955: $this->Event($dbs,$debuglev,"Node","Process");
956:
957: if ($level>$alvl) $alvl=$level;
958:
959: if ($row['testrecord']==1) // record it
960: {
961: $testvalue=$xmlobj->Catalogue[$row['testtype']]['VALUE'];
962: $testvalue=str_replace(",",".",$testvalue);
963: if (!is_numeric($testvalue)) $testvalue=0;
964: $iq="INSERT INTO fnrecord(testid,alertlevel,recordx,nodeid,testvalue) VALUES(";
965: $iq.="\"N".$row['nstestid']."\",".$level.",".time().",\"".$row['nodeid']."\",".$testvalue.")";
966: $this->DB->Query($iq);
967: if ($this->DB->Affected_Rows()<=0)
968: $this->Event("Nodeside ".$row['testtype']." Failed to Record",1,"Node","Process");
969: }
970:
971: // We don't do any alerting here - the tester will do that for us!
972: $uq="UPDATE fnnstest SET lastrunx=".time().",lastvalue=\"".ss($xmlobj->Catalogue[$row['testtype']]['VALUE'])."\",alertlevel=".$level." ";
973: $uq.="WHERE nstestid=".$row['nstestid'];
974: $this->DB->Query($uq);
975: if ($this->DB->Affected_Rows()<=0)
976: $this->Event("Nodeside ".$row['testtype']." Failed to Update or Same Values",5,"Node","Process");
977:
978: }
979:
980: // check to see if the desc has changed
981: if ($row['testdesc']!=$xmlobj->Catalogue[$row['testtype']]['DESC'])
982: {
983: $duq="UPDATE fnnstest SET testdesc=\"".ss($xmlobj->Catalogue[$row['testtype']]['DESC'])."\" WHERE nstestid=".$row['nstestid'];
984: $this->DB->Query($duq);
985: }
986:
987: }
988: else
989: {
990: // test in the DB but NOT in the catalogue
991: //$xmlobj->Catalogue[$row['testtype']]['incat']=false;
992: if ($row['testenabled']==1)
993: { // enabled so shown in lists etc
994: // Update it to show failed status
995: $this->Event("No nodeside data for test N".$row['nstestid'],3,"Node","Process");
996: $uq="UPDATE fnnstest SET alertlevel=2,lastvalue=-1 WHERE nstestid=".$row['nstestid'];
997: $this->DB->Query($uq);
998: $alvl=2;
999: if ($row['testrecord']==1) // record it
1000: {
1001: $testvalue=-1;
1002: $iq="INSERT INTO fnrecord(testid,alertlevel,recordx,nodeid,testvalue) VALUES(";
1003: $iq.="\"N".$row['nstestid']."\",2,".time().",\"".$row['nodeid']."\",".$testvalue.")";
1004: $this->DB->Query($iq);
1005: if ($this->DB->Affected_Rows()<=0)
1006: $this->Event("Nodeside ".$row['testtype']." Failed to Record",1,"Node","Process");
1007: }
1008: }
1009: else // not enabled so simply delete
1010: {
1011: $this->DeleteTest("N".$row['nstestid']);
1012: }
1013: }
1014: }
1015: $this->DB->Free($r);
1016:
1017:
1018: // and finally we look for new tests i.e. in the cat but not in the DB
1019: foreach($xmlobj->Catalogue as $val)
1020: {
1021: $key=$val['NAME'];
1022: if (!isset($tests[$key])) // not in the DB
1023: {
1024: $q="INSERT INTO fnnstest(nodeid,testtype,testdesc,lastvalue,lastrunx,alertlevel) ";
1025: $q.="VALUES(\"".ss($nodeid)."\",\"".$key."\",\"".ss($val['DESC'])."\",\"".ss($val['VALUE'])."\",".time().",".ss($val['ALERTLEVEL']).")";
1026: //echo $q."
";
1027: $this->DB->Query($q);
1028: }
1029: }
1030:
1031: $eventdata=array("nodeid"=>$nodeid,"alertlevel"=>$alvl);
1032: $this->EventHandler("nodeside_process",$eventdata);
1033:
1034:
1035: }
1036:
1037:
1038: function AddEventHandler($event,$function)
1039: {
1040: if (!isset($this->EventHandlers[$event])) $this->EventHandlers[$event]=array();
1041: $this->EventHandlers[$event][]=$function;
1042: }
1043:
1044: function EventHandler($event,$data)
1045: {
1046: $res=false;
1047: if ( isset($data) && is_array($data) ) $data['event']=$event;
1048:
1049: if (isset($this->EventHandlers[$event])) // handler(s) exist
1050: {
1051: for($a=0; $aEventHandlers[$event]); $a++)
1052: {
1053: if (function_exists($this->EventHandlers[$event][$a]))
1054: {
1055: $this->Event("Event ".$event." -> ".$this->EventHandlers[$event][$a],6,"Event","Handler");
1056: if($this->EventHandlers[$event][$a]($data)) $res=true; // persist true only
1057: }
1058: else
1059: {
1060: $t="Illegal Handler ".$this->EventHandlers[$event][$a]." for ".$event;
1061: $this->Event($t,2,"Event","Handler");
1062: //return false;
1063: }
1064: }
1065: }
1066: else return $res;
1067: }
1068:
1069: function StripGPC($data)
1070: {
1071: if (get_magic_quotes_gpc()) return stripslashes($data);
1072: else return $data;
1073: }
1074:
1075: function PageError($code,$desc)
1076: {
1077: $this->PageErrors[]=array( "code" => $code, "desc" => $desc );
1078: }
1079:
1080: }
1081: ?>
1082: