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