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