source: branches/0.4/web/addons/job_monarch/libtoga.php @ 748

Last change on this file since 748 was 748, checked in by ramonb, 11 years ago
  • cleaned out stopElement XML parsing
  • Property svn:keywords set to Id
File size: 68.9 KB
Line 
1<?php
2/*
3 *
4 * This file is part of Jobmonarch
5 *
6 * Copyright (C) 2006-2013  Ramon Bastiaans
7 *
8 * Jobmonarch is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * Jobmonarch is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21 *
22 * SVN $Id: libtoga.php 748 2013-03-25 16:58:46Z ramonb $
23 *
24 */
25
26
27class HTTPVariables
28{
29    var $clustername, $metricname;
30    var $restvars, $httpvars;
31
32    function HTTPVariables( $httpvars, $getvars )
33    {
34        $this->restvars        = array();
35
36        $this->clustername    = isset( $httpvars["c"] ) ? $httpvars["c"] : $getvars["c"];
37        $this->metricname    = isset( $httpvars["m"] ) ? $httpvars["m"] : $getvars["m"];
38
39        if( count( $httpvars ) > 0 )
40        {
41            foreach( $httpvars as $httpvar => $httpval )
42            {
43                if( $httpval )
44                {
45                    $this->restvars[$httpvar] = $httpval;
46                }
47            }
48        }
49
50        if( count( $getvars ) > 0 )
51        {
52            foreach( $getvars as $getvar => $getval )
53            {
54                if( $getval )
55                {
56                    $this->restvars[$getvar] = $getval;
57                }
58            }
59        }
60    }
61
62    function getClusterName()
63    {
64        return $this->clustername;
65    }
66
67    function getMetricName()
68    {
69        return $this->metricname;
70    }
71
72    function getHttpVar( $var )
73    {
74        if( isset( $this->restvars[$var] ) )
75        {
76            return $this->restvars[$var];
77        }
78        else
79        {
80            return null;
81        }
82    }
83}
84
85$CLUSTER_CONFS    = array();
86
87ini_set("memory_limit","500M");
88set_time_limit(0);
89
90// Monarch's conf
91//
92include_once "./conf.php";
93include_once "./version.php";
94
95global $GANGLIA_PATH;
96global $RRDTOOL;
97global $JOB_ARCHIVE_DIR;
98global $JOB_ARCHIVE_DBASE;
99global $skan_str;
100global $x_first, $y_first;
101global $CLUSTER_CONFS;
102
103$my_dir = getcwd();
104
105// Load Ganglia's PHP
106chdir( $GANGLIA_PATH );
107
108include_once "./eval_conf.php";
109include_once "./functions.php";
110include_once "./ganglia.php";
111include_once "./get_context.php";
112
113$context = 'cluster';
114include_once "./get_ganglia.php";
115
116// Back to our PHP
117chdir( $my_dir );
118
119global $SMALL_CLUSTERIMAGE_MAXWIDTH, $SMALL_CLUSTERIMAGE_NODEWIDTH, $DATA_SOURCE, $HTTP_GET_VARS, $_GET;
120$httpvars = new HTTPVariables( $HTTP_GET_VARS, $_GET );
121
122// Set cluster context so that Ganglia will
123// provide us with the correct metrics array
124//
125global $context, $clustername, $reports;
126
127global $default_metric;
128
129// Ganglia's array of host metrics
130//
131global $metrics, $hosts_up;
132global $start;
133
134global $DATETIME_FORMAT;
135
136function makeDate( $time )
137{
138    global $DATETIME_FORMAT;
139    return strftime( $DATETIME_FORMAT, $time );
140}
141
142
143class TarchDbase
144{
145    var $ip, $dbase, $conn;
146
147    function TarchDbase( $ip = null, $dbase = null )
148    {
149        global $CLUSTER_CONFS, $clustername;
150        global $JOB_ARCHIVE_DBASE;
151
152        // Import cluster specific settings
153        //
154        foreach( $CLUSTER_CONFS as $confcluster => $conffile )
155        {
156            if( strtolower( trim($this->clustername) ) == strtolower(trim($confcluster)) )
157            {
158                include_once $conffile;
159            }
160        }
161
162        $db_fields = explode( '/', $JOB_ARCHIVE_DBASE );
163
164        $this->ip    = $db_fields[0];
165        $this->dbase    = $db_fields[1];
166        $this->conn    = null;
167    }
168
169    function connect()
170    {
171        if( $this->ip == null )
172            $this->conn = pg_connect( "dbname=".$this->dbase );
173        else
174            $this->conn = pg_connect( "host=".$this->ip." dbname=".$this->dbase );
175    }
176
177    function searchDbase( $id = null, $queue = null, $owner = null, $name = null, $start_from_time = null, $start_to_time = null, $end_from_time = null, $end_to_time = null )
178    {
179        global $SEARCH_RESULT_LIMIT;
180
181        if( $id )
182        {
183            $select_query = "SELECT job_id FROM jobs WHERE job_id = '$id' AND job_status = 'F'";
184            $this->resultcount = 1;
185        }
186        else
187        {
188            $query_args = array();
189           
190            if( $queue )
191            {
192                $query_args[] = "job_queue ='$queue'";
193            }
194            if( $owner )
195            {
196                $query_args[] = "job_owner ='$owner'";
197            }
198            if( $name )
199            {
200                $query_args[] = "job_name = '$name'";
201            }
202            if( $start_from_time )
203            {
204                $query_args[] = "job_start_timestamp >= $start_from_time";
205            }
206            if( $start_to_time )
207            {
208                $query_args[] = "job_start_timestamp <= $start_to_time";
209            }
210            if( $end_from_time )
211            {
212                $query_args[] = "job_stop_timestamp >= $end_from_time";
213            }
214            if( $end_to_time )
215            {
216                $query_args[] = "job_stop_timestamp <= $end_to_time";
217            }
218
219            $query = "FROM jobs WHERE job_status = 'F' AND ";
220            $extra_query_args = '';
221
222            foreach( $query_args as $myquery )
223            {
224                if( $extra_query_args == '' )
225                {
226                    $extra_query_args = $myquery;
227                }
228                else
229                {
230                    $extra_query_args .= " AND ".$myquery;
231                }
232            }
233            $query .= $extra_query_args;
234
235            $count_result_idname = "COUNT(job_id)";
236            $select_result_idname = "job_id";
237
238            $count_query = "SELECT " . $count_result_idname . " " . $query;
239
240            $count_result = $this->queryDbase( $count_query );
241            $this->resultcount = (int) $count_result[0]['count'];
242
243            $select_query = "SELECT " . $select_result_idname . " " . $query . " ORDER BY job_id DESC LIMIT " . $SEARCH_RESULT_LIMIT;
244        }
245
246        $ids = $this->queryDbase( $select_query );
247
248        $ret = array();
249
250        foreach( $ids as $crow)
251        {
252            $ret[] = $crow['job_id'];
253        }
254
255        return $ret;
256    }
257
258    function getNodesForJob( $jobid )
259    {
260        $result = $this->queryDbase( "SELECT node_id FROM job_nodes WHERE job_id = '$jobid'" );
261
262        $nodes = array();
263
264        foreach( $result as $result_row ) 
265        {
266            $nodes[] = $this->getNodeArray( $result_row['node_id'] );
267        }
268
269        return $nodes;
270    }
271
272    function getJobsForNode( $nodeid )
273    {
274        $result = $this->queryDbase( "SELECT job_id FROM job_nodes WHERE node_id = '$nodeid'" );
275
276        $jobs = array();
277
278        foreach( $result as $result_row )
279        {
280            $jobs[] = $this->getJobArray( $result_row['job_id'] );
281        }
282        return $jobs;
283    }
284
285    function getJobArray( $id )
286    {
287        $result = $this->queryDbase( "SELECT * FROM jobs WHERE job_id = '$id'" );
288
289        return ( $this->makeArray( $result[0] ) );
290    }
291
292    function getNodeArray( $id )
293    {
294        $result = $this->queryDbase( "SELECT * FROM nodes WHERE node_id = '$id'" );
295
296        return ( $this->makeArray( $result[0] ) );
297    }
298
299    function makeArray( $result_row )
300    {
301        $myar = array();
302
303        foreach( $result_row as $mykey => $myval )
304        {
305            $map_key = explode( '_', $mykey );
306
307            $rmap_key = array_reverse( $map_key );
308            array_pop( $rmap_key );
309            $map_key = array_reverse( $rmap_key );
310           
311            $newkey = implode( '_', $map_key );
312           
313            $myar[$newkey] = $result_row[$mykey];
314        }
315
316        return $myar;
317    }
318
319    function queryDbase( $query )
320    {
321        $result_rows = array();
322   
323        if( !$this->conn )
324        {
325            $this->connect();
326        }
327
328        $result = pg_query( $this->conn, $query );
329
330        while ($row = pg_fetch_assoc($result))
331        {
332            $result_rows[] = $row;
333        }
334
335        return $result_rows;
336    }
337}
338
339class TarchRrdGraph
340{
341    var $rrdbin, $rrdvalues, $clustername, $hostname, $tempdir, $tarchdir, $metrics;
342
343    function TarchRrdGraph( $clustername, $hostname )
344    {
345        global $conf;
346        global $JOB_ARCHIVE_DIR;
347
348        $this->rrdbin        = $conf['rrdtool'];
349        $this->rrdvalues    = array();
350        $this->tarchdir        = $JOB_ARCHIVE_DIR;
351        $this->clustername    = $clustername;
352        $this->hostname        = $hostname;
353    }
354
355    function doCmd( $command )
356    {
357        $pipe = popen( $command . ' 2>&1', 'r' );
358
359        if (!$pipe)
360        {
361            print "pipe failed.";
362            return "";
363        }
364
365        $output = '';
366
367        while(!feof($pipe))
368        {
369            $output .= fread($pipe, 1024);
370        }
371
372        pclose($pipe);
373
374        $output = explode( "\n", $output );
375
376        return $output;
377    }
378
379    function dirList( $dir )
380    {
381        $dirlist = array();
382
383        if ($handle = opendir( $dir ))
384        {
385            while (false !== ($file = readdir($handle)))
386            {
387                if ($file != "." && $file != "..")
388                {
389                    $dirlist[] = $file;
390                }
391            }
392            closedir($handle);
393        }
394
395        return $dirlist;
396    }
397
398    function getTimePeriods( $start, $end )
399    {
400        $times = array();
401        $dirlist = $this->dirList( $this->tarchdir . '/' . $this->clustername . '/' . $this->hostname );
402
403        $first = 0;
404        $last = 9999999999999;
405
406        foreach( $dirlist as $dir )
407        {
408            if( $dir > $first and $dir <= $start )
409            {
410                $first = $dir;
411            }
412            if( $dir < $last and $dir >= $end )
413            {
414                $last = $dir;
415            }
416        }
417
418        foreach( $dirlist as $dir )
419        {
420            if( $dir >= $first and $dir <= $last and !array_key_exists( $dir, $times ) )
421            {
422                $times[] = $dir;
423            }
424        }
425
426        sort( $times );
427
428        return $times;
429    }
430
431    function getRrdDirs( $start, $stop )
432    {
433        $timess = $this->getTimePeriods( $start, $stop );
434
435        $rrd_files = array();
436
437        foreach( $timess as $time )
438        {
439            $rrd_files[] = $this->tarchdir . '/' . $this->clustername . '/' . $this->hostname. '/'.$time;
440        }
441
442        return $rrd_files;
443    }
444
445    function getRrdFiles( $metric, $start, $stop )
446    {
447        $times = $this->getTimePeriods( $start, $stop );
448
449        $rrd_files = array();
450
451        foreach( $times as $time )
452        {
453            $rrd_files[] = $this->tarchdir . '/' . $this->clustername . '/' . $this->hostname . '/' .$time. '/' . $metric. '.rrd';
454        }
455
456        return $rrd_files;
457    }
458}
459
460class DataSource
461{
462    var $data, $ip, $port;
463
464    function DataSource()
465    {
466        global $DATA_SOURCE, $clustername;
467
468        $ds_fields     = explode( ':', $DATA_SOURCE );
469
470        $ds_ip         = $ds_fields[0];
471        $ds_port       = $ds_fields[1];
472
473        $this->ip       = $ds_ip;
474        $this->port     = $ds_port;
475        $this->clustername = $clustername;
476    }
477
478    function getData()
479    {
480        $errstr        = '';
481        $errno         = 0;
482        $timeout       = 3;
483
484        $fp = fsockopen( $this->ip, $this->port, $errno, $errstr, $timeout );
485
486        if( !$fp )
487        {
488            echo 'Unable to connect to '.$this->ip.':'.$this->port;
489            return;
490        }
491
492        if( $this->port == '8652' )
493        {
494            $request = "/" . $this->clustername . "\n";
495            $rc = fputs($fp, $request);
496            if (!$rc)
497            {
498                $error = "Could not sent request to gmetad: $errstr";
499                if ($debug) print "<br/>DEBUG: $error\n";
500                   return FALSE;
501            }
502        }
503
504        stream_set_timeout( $fp, 30 );
505
506        while ( !feof( $fp ) )
507        {
508            $data .= fread( $fp, 16384 );
509        }
510
511        fclose( $fp );
512
513        return $data;
514    }
515}
516
517class DataGatherer
518{
519    var $xmlhandler, $data, $httpvars;
520
521    function DataGatherer( $cluster )
522    {
523        $this->cluster    = $cluster;
524        $this->httpvars = $httpvars;
525    }
526
527    function parseXML( $data )
528    {
529
530        $this->parser         = xml_parser_create();
531        $this->xmlhandler     = new TorqueXMLHandler( $this->cluster );
532
533        xml_set_element_handler( $this->parser, array( &$this->xmlhandler, 'startElement' ), array( &$this->xmlhandler, 'stopElement' ) );
534
535        if ( !xml_parse( $this->parser, $data ) )
536        {
537            $error = sprintf( 'XML error: %s at %d', xml_error_string( xml_get_error_code( $this->parser ) ), xml_get_current_line_number( $this->parser ) );
538        }
539        $handler = &$this->xmlhandler;
540        $handler->finishUp();
541    }
542
543    function printInfo()
544    {
545        $handler = $this->xmlhandler;
546        $handler->printInfo();
547    }
548
549    function getUsingFQDN()
550    {
551        $handler = $this->xmlhandler;
552        return $handler->getUsingFQDN();
553    }
554
555    function getNodes()
556    {
557        $handler = $this->xmlhandler;
558        return $handler->getNodes();
559    }
560
561    function getNode( $node )
562    {
563        $handler = $this->xmlhandler;
564        return $handler->getNode( $node );
565    }
566
567    function getCpus()
568    {
569        $handler = $this->xmlhandler;
570        return $handler->getCpus();
571    }
572
573    function getJobs()
574    {
575        $handler = $this->xmlhandler;
576        return $handler->getJobs();
577    }
578
579    function getJob( $job )
580    {
581        $handler = $this->xmlhandler;
582        return $handler->getJob( $job );
583    }
584
585    function getHeartbeat()
586    {
587        $handler = $this->xmlhandler;
588        return $handler->getHeartbeat();
589    }
590
591    function isJobmonRunning()
592    {
593        $handler = $this->xmlhandler;
594        return $handler->isJobmonRunning();
595    }
596}
597
598class TorqueXMLHandler
599{
600    var $clusters, $heartbeat, $nodes, $jobs, $clustername, $proc_cluster;
601
602    function TorqueXMLHandler( $clustername )
603    {
604        $this->jobs        = array();
605        $this->clusters     = array();
606        $this->nodes         = array();
607        $this->heartbeat     = array();
608        $this->down_nodes    = array();
609        $this->offline_nodes    = array();
610        $this->clustername    = $clustername;
611        $this->fqdn        = 1;
612    }
613
614    function getUsingFQDN()
615    {
616        return $this->fqdn;
617    }
618
619    function getCpus()
620    {
621        $cpus = 0;
622
623        if( isset( $this->jobs ) && count( $this->jobs ) > 0 )
624        {
625            foreach( $this->jobs as $jobid=>$jobattrs )
626            {
627                $nodes    = count( $jobattrs['nodes'] );
628                $ppn    = (int) $jobattrs['ppn'] ? $jobattrs['ppn'] : 1;
629                $mycpus    = $nodes * $ppn;
630
631                $cpus    = $cpus + $mycpus;
632            }
633        }
634    }
635
636    function isJobmonRunning()
637    {
638        if (isset( $this->heartbeat['time'] ))
639        {
640            return 1;
641        }
642        else
643        {
644            return 0;
645        }
646    }
647
648    function makeHostname( $thostname, $tdomain=null )
649    {
650        // Should hostname be FQDN or short w/o domain
651        //
652        $nodes = &$this->nodes;
653
654        $fqdn = 1;
655
656        //$tdomain = explode( '.', $thostname );
657        //
658        // TODO?: extract domain from hostname or something?
659
660        if( $tdomain )
661        {
662            $domain_len    = 0 - strlen( $tdomain );
663
664            // Let's see if Ganglia use's FQDN or short hostnames
665            //
666            foreach( $nodes as $hostname => $nimage )
667            {
668                if( strpos( $hostname, $tomdain ) !== false )
669                {
670                    $fqdn    = 0;
671                }
672            }
673        }
674        else
675        {
676            $fqdn    = 0;
677        }
678   
679        if( $tdomain && $fqdn )
680        {
681            if( strpos( $thostname, $tdomain ) !== false )
682            {
683                $thostname = $thostname . '.'.$tdomain;
684            } 
685            else
686            {
687                $thostname = $thostname;
688            }
689        }
690
691        return $thostname;
692    }
693
694    function startElement( $parser, $name, $attrs )
695    {
696        $jobs = $this->jobs;
697        $nodes = $this->nodes;
698
699        if( isset( $attrs['TN'] ) )
700        {
701            if ( $attrs['TN'] )
702            {
703                // Ignore dead metrics. Detect and mask failures.
704                if ( $attrs['TN'] > $attrs['TMAX'] * 4 )
705                {
706                    return;
707                }
708            }
709        }
710
711        $jobid = null;
712
713        if( $name == 'CLUSTER' )
714        {
715            $this->proc_cluster = $attrs['NAME'];
716        }
717        else if( $name == 'HOST' and $this->proc_cluster == $this->clustername)
718        {
719            $hostname = $attrs['NAME'];
720
721            $location = $attrs['LOCATION'];
722
723            if( !isset( $nodes[$hostname] ) )
724            {
725                $nodes[$hostname] = new NodeImage( $this->proc_cluster, $hostname );
726            }
727        }
728        else if( $name == 'METRIC' and ( strpos( $attrs['NAME'], 'zplugin_monarch' ) !== false ) and $this->proc_cluster == $this->clustername )
729        {
730            if( strpos( $attrs['NAME'], 'zplugin_monarch_heartbeat' ) !== false )
731            {
732                $this->heartbeat['time'] = $attrs['VAL'];
733            }
734            else if( strpos( $attrs['NAME'], 'zplugin_monarch_down' ) !== false )
735            {
736                $fields        = explode( ' ', $attrs['VAL'] );
737
738                $nodes_down    = array();
739                $down_domain    = null;
740
741                foreach( $fields as $f )
742                {
743                    $togavalues    = explode( '=', $f );
744
745                    $toganame    = $togavalues[0];
746                    $togavalue    = $togavalues[1];
747
748                    if( $toganame == 'nodes' )
749                    {
750                        $mynodes = explode( ';', $togavalue );
751
752                        foreach( $mynodes as $node )
753                        {
754                            $nodes_down[] = $node;
755                        }
756                    }
757                    else if( $toganame == 'domain' )
758                    {
759                        $down_domain = $togavalue;
760                    }
761                    else if( $toganame == 'reported' )
762                    {
763                        if( !isset( $this->down_nodes['heartbeat'] ) )
764                        {
765                            $this->down_nodes[$togavalue]    = array( $nodes_down, $down_domain );
766                        }
767                    }
768                }
769            }
770            else if( strpos( $attrs['NAME'], 'zplugin_monarch_offline' ) !== false )
771            {
772                $fields        = explode( ' ', $attrs['VAL'] );
773
774                $nodes_offline    = array();
775                $offline_domain    = null;
776
777                foreach( $fields as $f )
778                {
779                    $togavalues    = explode( '=', $f );
780
781                    $toganame    = $togavalues[0];
782                    $togavalue    = $togavalues[1];
783
784                    if( $toganame == 'nodes' )
785                    {
786                        $mynodes = explode( ';', $togavalue );
787
788                        foreach( $mynodes as $node )
789                        {
790                            $nodes_offline[] = $node;
791                        }
792                    }
793                    else if( $toganame == 'domain' )
794                    {
795                        $offline_domain = $togavalue;
796                    }
797                    else if( $toganame == 'reported' )
798                    {
799                        if( !isset( $this->offline_nodes['heartbeat'] ) )
800                        {
801                            $this->offline_nodes[$togavalue] = array( $nodes_offline, $offline_domain );
802                        }
803                    }
804                }
805            }
806            else if( strpos( $attrs['NAME'], 'zplugin_monarch_job' ) !== false )
807            {
808                sscanf( $attrs['NAME'], 'zplugin_monarch_job_%d_%s$', $monincr, $jobid );
809
810                if( !isset( $jobs[$jobid] ) )
811                {
812                    $jobs[$jobid] = array();
813                }
814
815                $fields = explode( ' ', $attrs['VAL'] );
816
817                foreach( $fields as $f )
818                {
819                    $togavalues = explode( '=', $f );
820
821                    $toganame = $togavalues[0];
822                    $togavalue = $togavalues[1];
823
824                    if( $toganame == 'nodes' )
825                    {
826                        if( $jobs[$jobid]['status'] == 'R' )
827                        {
828                            if( !isset( $jobs[$jobid][$toganame] ) )
829                            {
830                                $jobs[$jobid][$toganame] = array();
831                            }
832
833                            $mynodes = explode( ';', $togavalue );
834
835                            foreach( $mynodes as $node )
836                            {
837                                if( !in_array( $node, $jobs[$jobid][$toganame] ) )
838                                {
839                                    array_push( $jobs[$jobid][$toganame], $node );
840                                }
841                            }
842
843                        }
844                        else if( $jobs[$jobid]['status'] == 'Q' )
845                        {
846                            $jobs[$jobid][$toganame] = $togavalue;
847                        }
848                    }
849                    else
850                    {
851                        $jobs[$jobid][$toganame] = $togavalue;
852                    }
853                }
854
855                if( isset( $jobs[$jobid]['nodes'] ) )
856                {
857                    $nr_nodes = count( $jobs[$jobid]['nodes'] );
858       
859                    if( $jobs[$jobid]['status'] == 'R' )
860                    {
861
862                        if( isset( $jobs[$jobid]['domain'] ) )
863                        {
864                            $domain        = $jobs[$jobid]['domain'];
865                            $domain_len    = 0 - strlen( $domain );
866
867                            $nodekeys     = array_keys( $nodes );
868
869                            $first_host    = $nodekeys[0];
870                            // Let's see if Ganglia use's FQDN or short hostnames
871                            //
872                            if( strpos( $first_host, $domain ) === false )
873                            {
874                                $this->fqdn    = 0;
875                            }
876                        }
877                        else
878                        {
879                            $this->fqdn    = 0;
880                        }
881
882                        foreach( $jobs[$jobid]['nodes'] as $node )
883                        {
884
885                            // Only add domain name to the hostname if Ganglia is doing that too
886                            //
887                            if( $this->fqdn && isset( $jobs[$jobid]['domain'] ) )
888                            {
889                                if( strpos( $node, $domain ) === false )
890                                {
891                                    $host = $node. '.'.$domain;
892                                } else
893                                {
894                                    $host = $node;
895                                }
896                            }
897                            else
898                            {
899                                $host    = $node;
900                            }
901
902                            if( !isset( $nodes[$host] ) )
903                            {
904                                $my_node = new NodeImage( $this->proc_cluster, $host );
905                            }
906                            else
907                            {
908                                $my_node = $nodes[$host];
909                            }
910
911                            if( !$my_node->hasJob( $jobid ) )
912                            {
913                                if( isset( $jobs[$jobid]['ppn'] ) )
914                                {
915                                    $my_node->addJob( $jobid, ((int) $jobs[$jobid]['ppn']) );
916                                }
917                                else
918                                {
919                                    $my_node->addJob( $jobid, 1 );
920                                }
921                            }
922
923                            $nodes[$host] = $my_node;
924                        }
925                    }
926                }
927            }
928        }
929        $this->jobs    = $jobs;
930        $this->nodes    = $nodes;
931    }
932
933    function finishUp( )
934    {
935        $nodes    = $this->nodes;
936
937        if( sizeof( $this->down_nodes ) > 0 )
938        {
939            foreach( $this->down_nodes as $reported => $dnodes )
940            {
941                if( $reported == $this->heartbeat['time'] )
942                {
943                    $domain = $dnodes[1];
944
945                    foreach( $dnodes[0] as $downhost )
946                    {
947                        $downhost = $this->makeHostname( $downhost, $domain );
948
949                        if( isset( $nodes[$downhost] ) )
950                        {
951                            // OMG PHP4 is fking stupid!
952                            // $nodes[$downhost]->setDown( 1 ) won't work here..
953                            //
954                            $mynode = $nodes[$downhost];
955                            $mynode->setDown( 1 );
956                            $nodes[$downhost] = $mynode;
957                        }
958                    }
959                }
960            }
961        }
962
963        if( sizeof( $this->offline_nodes ) > 0 )
964        {
965            foreach( $this->offline_nodes as $reported => $onodes )
966            {
967                if( $reported == $this->heartbeat['time'] )
968                {
969                    $domain = $onodes[1];
970
971                    foreach( $onodes[0] as $offlinehost )
972                    {
973                        $offlinehost = $this->makeHostname( $offlinehost, $domain );
974
975                        if( isset( $nodes[$offlinehost] ) )
976                        {
977                            // OMG PHP4 is fking stupid!
978                            // $nodes[$offlinehost]->setDown( 1 ) won't work here..
979                            //
980                            $mynode = $nodes[$offlinehost];
981                            $mynode->setOffline( 1 );
982                            $nodes[$offlinehost] = $mynode;
983                        }
984                    }
985                }
986            }
987        }
988
989        $this->nodes = $nodes;
990    }
991
992    function stopElement( $parser, $name )
993    {
994    }
995
996    function printInfo()
997    {
998        $jobs = &$this->jobs;
999
1000        printf( "---jobs---\n" );
1001
1002        foreach( $jobs as $jobid => $job )
1003        {
1004            printf( "job %s\n", $jobid );
1005
1006            if( isset( $job['nodes'] ) )
1007            {
1008                foreach( $job['nodes'] as $node )
1009                {
1010                    $mynode = $this->nodes[$node];
1011                    $hostname = $mynode->getHostname();
1012                    $location = $mynode->getLocation();
1013
1014                    printf( "\t- node %s\tlocation %s\n", $hostname, $location );
1015                }
1016            }
1017        }
1018
1019        printf( "---nodes---\n" );
1020
1021        $nodes = &$this->nodes;
1022
1023        foreach( $nodes as $node )
1024        {
1025            $hostname = $node->getHostname();
1026            $location = $node->getLocation();
1027            $jobs = implode( ' ', $node->getJobs() );
1028            printf( "* node %s\tlocation %s\tjobs %s\n", $hostname, $location, $jobs );
1029        }
1030    }
1031
1032    function getNodes()
1033    {
1034        return $this->nodes;
1035    }
1036
1037    function getNode( $node )
1038    {
1039        $nodes = &$this->nodes;
1040
1041        if( isset( $nodes[$node] ) )
1042        {
1043            return $nodes[$node];
1044        }
1045        else
1046        {
1047            return NULL;
1048        }
1049    }
1050
1051    function getJobs()
1052    {
1053        return $this->jobs;
1054    }
1055
1056    function getJob( $job )
1057    {
1058        $jobs = &$this->jobs;
1059
1060        if( isset( $jobs[$job] ) )
1061        {
1062            return $jobs[$job];
1063        }
1064        else
1065        {
1066            return NULL;
1067        }
1068    }
1069
1070    function getHeartbeat()
1071    {
1072        return $this->heartbeat['time'];
1073    }
1074}
1075
1076class NodeImage
1077{
1078    var $image, $x, $y, $hostname, $jobs, $tasks, $showinfo;
1079
1080    function NodeImage( $cluster, $hostname )
1081    {
1082        global $SMALL_CLUSTERIMAGE_NODEWIDTH;
1083
1084        $this->jobs        = array();
1085        $this->tasks        = 0;
1086        $this->hostname        = $hostname;
1087        $this->clustername    = $cluster;
1088        $this->showinfo        = 1;
1089        $this->size        = $SMALL_CLUSTERIMAGE_NODEWIDTH;
1090        $this->down        = 0;
1091        $this->offline        = 0;
1092    }
1093
1094    function addJob( $jobid, $cpus )
1095    {
1096        $jobs        = &$this->jobs;
1097        $jobs[]        = $jobid;
1098        $this->jobs    = $jobs;
1099
1100        $this->addTask( $cpus );
1101    }
1102
1103    function hasJob( $jobid )
1104    {
1105        $jobfound = 0;
1106
1107        if( count( $this->jobs ) > 0 )
1108        {
1109            foreach( $this->jobs as $job )
1110            {
1111                if( $job == $jobid )
1112                {
1113                    $jobfound = 1;
1114                }
1115            }
1116        }
1117
1118        return $jobfound;
1119    }
1120
1121    function addTask( $cpus )
1122    {
1123        $this->tasks = $this->tasks + $cpus;
1124    }
1125    function setDown( $down )
1126    {
1127        $this->down = $down;
1128    }
1129    function isDown()
1130    {
1131        return $this->down;
1132    }
1133    function setOffline( $offline )
1134    {
1135        $this->offline = $offline;
1136    }
1137    function isOffline()
1138    {
1139        return $this->offline;
1140    }
1141    function setImage( $image )
1142    {
1143        $this->image = $image;
1144    }
1145    function setCoords( $x, $y )
1146    {
1147        $this->x = $x;
1148        $this->y = $y;
1149    }
1150    function getX()
1151    {
1152        return $this->x;
1153    }
1154    function getY()
1155    {
1156        return $this->y;
1157    }
1158
1159    function getImagemapArea()
1160    {
1161        $area_topleft        = $this->x . "," . $this->y;
1162        $area_bottomright    = ($this->x + $this->size) . "," . ($this->y + $this->size);
1163        $area_coords        = $area_topleft . "," . $area_bottomright;
1164
1165        $area_href        = "./?c=" . $this->clustername . "&h=" . $this->hostname;
1166
1167        $area_tooltip        = $this->hostname;
1168
1169        if( $this->down)
1170        {
1171            $area_tooltip        = $area_tooltip . ": DOWN";
1172        }
1173        else if( $this->offline )
1174        {
1175            $area_tooltip        = $area_tooltip . ": OFFLINE";
1176        }
1177
1178        $area_tooltip        = $area_tooltip . ": " . implode( " ", $this->jobs );
1179
1180        $tag_href        = "HREF=\"" . $area_href . "\"";
1181        $tag_coords        = "COORDS=\"" . $area_coords . "\"";
1182        $tag_tooltip1        = "ALT=\"" . $area_tooltip . "\"";
1183        $tag_tooltip2        = "TITLE=\"" . $area_tooltip . "\"";
1184
1185        return ("<AREA SHAPE=\"RECT\" " . $tag_coords . " " . $tag_href . " " . $tag_tooltip1 . " " . $tag_tooltip2 . ">");
1186    }
1187
1188    function colorHex( $color )
1189    {
1190        $my_color = imageColorAllocate( $this->image, hexdec( substr( $color, 0, 2 )), hexdec( substr( $color, 2, 2 )), hexdec( substr( $color, 4, 2 )) );
1191
1192        return $my_color;
1193    }
1194
1195    function setLoad( $load )
1196    {
1197        $this->load = $load;
1198    }
1199
1200    function setHostname( $hostname )
1201    {
1202        $this->hostname = $hostname;
1203    }
1204
1205    function getHostname()
1206    {
1207        return $this->hostname;
1208    }
1209
1210    function getJobs()
1211    {
1212        return $this->jobs;
1213    }
1214
1215    function setShowinfo( $showinfo )
1216    {
1217        $this->showinfo = $showinfo;
1218    }
1219
1220    function drawSmall()
1221    {
1222        global $SMALL_CLUSTERIMAGE_NODEWIDTH;
1223
1224        $this->size    = $SMALL_CLUSTERIMAGE_NODEWIDTH;
1225
1226        $this->draw();
1227    }
1228
1229    function drawBig()
1230    {
1231        global $BIG_CLUSTERIMAGE_NODEWIDTH;
1232
1233        $this->size    = $BIG_CLUSTERIMAGE_NODEWIDTH;
1234
1235        $this->draw();
1236    }
1237
1238    function draw()
1239    {
1240        global $JOB_NODE_MARKING, $NODE_DOWN_MARKING, $NODE_OFFLINE_MARKING;
1241
1242        $black_color = imageColorAllocate( $this->image, 0, 0, 0 );
1243        $size = $this->size;
1244
1245        imageFilledRectangle( $this->image, $this->x, $this->y, $this->x+($size), $this->y+($size), $black_color );
1246
1247        if( $this->showinfo)
1248        {
1249            $this->load = $this->determineLoad();
1250
1251            if( !isset( $this->image ) or !isset( $this->x ) or !isset( $this->y ) )
1252            {
1253                printf( "aborting\n" );
1254                printf( "x %d y %d load %f\n", $this->x, $this->y, $load );
1255                return;
1256            }
1257
1258            // Convert Ganglias Hexadecimal load color to a Decimal one
1259            //
1260            $load = $this->determineLoad();   
1261            $usecolor = $this->colorHex( load_color($load) );
1262            imageFilledRectangle( $this->image, $this->x+1, $this->y+1, $this->x+($size-1), $this->y+($size-1), $usecolor );
1263            if( $this->down )
1264            {
1265                imageString( $this->image, 1, $this->x+(($size/2)-1), $this->y+(($size/2)-4), $NODE_DOWN_MARKING, $black_color );
1266            }
1267            else if( $this->offline )
1268            {
1269                imageString( $this->image, 1, $this->x+(($size/2)-1), $this->y+(($size/2)-4), $NODE_OFFLINE_MARKING, $black_color );
1270            }
1271            else if( count( $this->jobs ) > 0 )
1272            {
1273                imageString( $this->image, 1, $this->x+(($size/2)-1), $this->y+(($size/2)-4), $JOB_NODE_MARKING, $black_color );
1274            }
1275        }
1276        else
1277        {
1278            // White
1279            $usecolor = imageColorAllocate( $this->image, 255, 255, 255 );
1280            imageFilledRectangle( $this->image, $this->x+1, $this->y+1, $this->x+($size-1), $this->y+($size-1), $usecolor );
1281        }
1282    }
1283
1284    function determineLoad()
1285    {
1286        global $metrics;
1287
1288        $cpus = $metrics[$this->hostname]['cpu_num']['VAL'];
1289        if (!$cpus)
1290        {
1291            $cpus=1;
1292        }
1293
1294        $load_one    = $metrics[$this->hostname]['load_one']['VAL'];
1295        $load        = ((float) $load_one)/$cpus;
1296
1297        return $load;
1298    }
1299}
1300
1301class ClusterImage
1302{
1303    var $dataget, $image, $clustername;
1304    var $filtername, $filters;
1305
1306    function ClusterImage( $data, $clustername )
1307    {
1308        $this->dataget        = new DataGatherer( $clustername );
1309        $this->data        = $data;
1310        $this->clustername    = $clustername;
1311        $this->filters        = array();
1312        $this->size        = 's';
1313        $this->width        = 0;
1314        $this->height        = 0;
1315        $this->output        = 1;
1316        $this->jobs         = null;
1317        $this->nodes        = null;
1318    }
1319
1320    function getWidth()
1321    {
1322        return $this->width;
1323    }
1324    function getHeight()
1325    {
1326        return $this->height;
1327    }
1328    function setSmall()
1329    {
1330        $this->size    = 's';
1331    }
1332    function setBig()
1333    {
1334        $this->size    = 'b';
1335    }
1336    function setNoimage()
1337    {
1338        $this->output    = 0;
1339    }
1340    function setJobs($jobs )
1341    {
1342        $this->jobs     = &$jobs;
1343    }
1344    function getJobs()
1345    {
1346        if( $this->jobs == null )
1347        {
1348            $mydatag = $this->dataget;
1349            $mydatag->parseXML( $this->data );
1350            $this->jobs = $mydatag->getJobs();
1351        }
1352
1353        return $this->jobs;
1354    }
1355    function getNodes()
1356    {
1357        if( $this->nodes== null )
1358        {
1359            $mydatag = $this->dataget;
1360            $mydatag->parseXML( $this->data );
1361            $this->nodes = $mydatag->getNodes();
1362        }
1363
1364        return $this->nodes;
1365    }
1366    function setNodes($nodes)
1367    {
1368        $this->nodes    = &$nodes;
1369    }
1370    function isSmall()
1371    {
1372        return ($this->size == 's');
1373    }
1374    function isBig()
1375    {
1376        return ($this->size == 'b');
1377    }
1378    function setFilter( $filtername, $filtervalue )
1379    {
1380        $this->filters[$filtername] = $filtervalue;
1381    }
1382
1383    function filterNodes( $jobs, $nodes )
1384    {
1385        $filtered_nodes = array();
1386
1387        //print_r( $nodes );
1388
1389        foreach( $nodes as $node )
1390        {
1391            $hostname = $node->getHostname();
1392
1393            $addhost = 1;
1394
1395            if( count( $this->filters ) > 0 )
1396            {
1397                $mynjobs = $node->getJobs();
1398
1399                if( count( $mynjobs ) > 0 )
1400                {
1401                    foreach( $mynjobs as $myjob )
1402                    {
1403                        foreach( $this->filters as $filtername => $filtervalue )
1404                        {
1405                            if( $filtername!=null && $filtername!='' )
1406                            {
1407                                if( $filtername == 'jobid' && !$node->hasJob( $filtervalue) )
1408                                {
1409                                    $addhost = 0;
1410                                }
1411                                else if( $filtername != 'jobid' )
1412                                {
1413                                    if( $jobs[$myjob][$filtername] != $filtervalue )
1414                                    {
1415                                        $addhost = 0;
1416                                    }
1417                                }
1418                            }
1419                        }
1420                    }
1421                }
1422                else
1423                {
1424                    $addhost = 0;
1425                }
1426            }
1427
1428            if( $addhost )
1429            {
1430                $filtered_nodes[] = $hostname;
1431            }
1432        }
1433
1434        return $filtered_nodes;
1435    }
1436
1437    function draw()
1438    {
1439        global $SMALL_CLUSTERIMAGE_MAXWIDTH, $SMALL_CLUSTERIMAGE_NODEWIDTH;
1440        global $BIG_CLUSTERIMAGE_MAXWIDTH, $BIG_CLUSTERIMAGE_NODEWIDTH;
1441        global $CLUSTER_CONFS, $confcluster, $SHOW_EMPTY_COLUMN, $SHOW_EMPTY_ROW;
1442
1443        global $SORTBY_HOSTNAME, $SORT_ORDER, $skan_str;
1444        global $x_first, $y_first;
1445
1446        foreach( $CLUSTER_CONFS as $confcluster => $conffile )
1447        {
1448            if( strtolower( trim($this->clustername) ) == strtolower(trim($confcluster)) )
1449            {
1450                include_once $conffile;
1451            }
1452        }
1453
1454        if( $this->isSmall() )
1455        {
1456            $max_width    = $SMALL_CLUSTERIMAGE_MAXWIDTH;
1457            $node_width    = $SMALL_CLUSTERIMAGE_NODEWIDTH;
1458        }
1459        else if( $this->isBig() )
1460        {
1461            $max_width    = $BIG_CLUSTERIMAGE_MAXWIDTH;
1462            $node_width    = $BIG_CLUSTERIMAGE_NODEWIDTH;
1463        }
1464
1465        $nodes        = $this->getNodes();
1466        $nodes_hosts    = array_keys( $nodes );
1467
1468        $nodes_nr    = count( $nodes );
1469
1470        $nodes_size    = $nodes_nr*$node_width;
1471        $node_rows    = 0;
1472
1473        if( $nodes_size > $max_width )
1474        {
1475            $nodes_per_row = ( (int) ($max_width/$node_width) );
1476        }
1477        else
1478        {
1479            $nodes_per_row = $nodes_size;
1480            $node_rows = 1;
1481        }
1482
1483        if( $nodes_per_row < $nodes_nr )
1484        {
1485            $node_rows = ( (int) ($nodes_nr/$nodes_per_row) );
1486            $node_rest = fmod( $nodes_nr, $nodes_per_row );
1487
1488            if( $node_rest > 0 )
1489            {
1490                $node_rows++;
1491            }
1492        }
1493
1494        $y_offset    = 0;
1495        $font         = 2;
1496        $fontwidth    = ImageFontWidth( $font );
1497        $fontheight    = ImageFontHeight( $font );
1498        $fontspaceing    = 2;
1499        $y_offset    = $fontheight + (2 * $fontspaceing);
1500
1501        $this->width    = $max_width;
1502        $this->height    = ($y_offset + (($node_rows*$node_width)+1) );
1503
1504        $jobs = $this->getJobs();
1505        $filtered_nodes = $this->filterNodes( $jobs, $nodes );
1506
1507        if( $SORTBY_HOSTNAME != "" )
1508        {
1509                $sorted     = array();
1510
1511            $x_first    = 0;
1512            $y_first    = 0;
1513
1514            $skan_str    = $SORTBY_HOSTNAME;
1515
1516            global $x_present, $y_present;
1517            $x_present    = false;
1518            $y_present    = false;
1519
1520            // Should we scan by X, Y or both
1521            //
1522            if(strpos( $SORTBY_HOSTNAME, "{x}" ) != false )
1523            {
1524                $x_str        = "{x}";
1525                $x_present    = true;
1526            }
1527            else if(strpos( $SORTBY_HOSTNAME, "{X}" ) != false )
1528            {
1529                $x_str        = "{X}";
1530                $x_present    = true;
1531            }
1532            if(strpos( $SORTBY_HOSTNAME, "{y}" ) != false )
1533            {
1534                $y_str        = "{y}";
1535                $y_present    = true;
1536            }
1537            else if(strpos( $SORTBY_HOSTNAME, "{Y}" ) != false )
1538            {
1539                $y_str        = "{Y}";
1540                $y_present    = true;
1541            }
1542
1543            // If we should scan for both X and Y: see which one is first
1544            //
1545            if(( strpos( $SORTBY_HOSTNAME, $x_str ) < strpos( $SORTBY_HOSTNAME, $y_str ) ) && ( $x_present && $y_present ))
1546            {
1547                $x_first    = 1;
1548            }
1549            else if(( strpos( $SORTBY_HOSTNAME, $x_str ) > strpos( $SORTBY_HOSTNAME, $y_str ) ) && ( $x_present && $y_present ))
1550            {
1551                $y_first    = 1;
1552       
1553            }
1554            else if( $x_present )
1555            {
1556                $x_first    = 1;
1557            }
1558            else if( $y_present )
1559            {
1560                $y_first    = 1;
1561            }
1562
1563            // Now replace our {x} and {y} with %d for sscanf parsing
1564            //
1565            if(( $x_first ) && ( $x_present && $y_present ) )
1566            {
1567                $skan_str    = str_replace( $x_str, "%d", $skan_str );
1568                $skan_str    = str_replace( $y_str, "%d", $skan_str );
1569            } 
1570            else if( $x_present)
1571            {
1572                $skan_str    = str_replace( $x_str, "%d", $skan_str );
1573            }
1574            else if( $y_present)
1575            {
1576                $skan_str    = str_replace( $y_str, "%d", $skan_str );
1577            }
1578
1579            $x_min        = null;
1580            $x_max        = null;
1581            $y_min        = null;
1582            $y_max        = null;
1583
1584            $x_columns    = array();
1585            $y_rows        = array();
1586
1587            // Now let's walk through all our nodes and see which one are valid for our scan pattern
1588            //
1589            foreach( $nodes as $hostname => $node )
1590            {
1591                $x    = null;
1592                $y    = null;
1593
1594                if( $x_present && $y_present )
1595                {
1596                    if( $x_first )
1597                    {
1598                        $n = sscanf( $hostname, $skan_str, $x, $y );
1599                    }
1600                    else if( $y_first )
1601                    {
1602                        $n = sscanf( $hostname, $skan_str, $y, $x );
1603                    }
1604
1605                    // Remove nodes that don't match
1606                    //
1607                    if( $n < 2 )
1608                    {
1609                        // This node hostname has no match for: {x} and {y}
1610                        //
1611                        unset( $nodes[$hostname] );
1612                    }
1613                }
1614                else if( $x_present && !$y_present )
1615                {
1616                    $n = sscanf( $hostname, $skan_str, $x );
1617
1618                    // Remove nodes that don't match
1619                    //
1620                    if( $n < 1 )
1621                    {
1622                        // This node hostname has no match for: {x}
1623                        //
1624                        unset( $nodes[$hostname] );
1625                    }
1626                    $y    = 1;
1627                }
1628                else if( $y_present && !$x_present )
1629                {
1630                    $n = sscanf( $hostname, $skan_str, $y );
1631
1632                    // Remove nodes that don't match
1633                    //
1634                    if( $n < 1 )
1635                    {
1636                        // This node hostname has no match for: {y}
1637                        //
1638                        unset( $nodes[$hostname] );
1639                    }
1640                    $x    = 1;
1641                }
1642
1643                // Determine the lowest value of {x} that exists in all node hostnames
1644                //
1645                if( !$x_min && $x != null )
1646                {
1647                    $x_min    = $x;
1648                }
1649                else if( $x < $x_min && $x != null )
1650                {
1651                    $x_min    = $x;
1652                }
1653
1654                // Determine the highest value of {x} that exists in all node hostnames
1655                //
1656                if( !$x_max && $x != null )
1657                {
1658                    $x_max    = $x;
1659                }
1660                else if( $x > $x_max && $x != null )
1661                {
1662                    $x_max    = $x;
1663                }
1664
1665                // Determine the lowest value of {y} that exists in all node hostnames
1666                //
1667                if( !$y_min && $y != null )
1668                {
1669                    $y_min    = $y;
1670                }
1671                else if( $y < $y_min && $y != null )
1672                {
1673                    $y_min    = $y;
1674                }
1675
1676                // Determine the highest value of {y} that exists in all node hostnames
1677                //
1678                if( !$y_max && $y != null )
1679                {
1680                    $y_max    = $y;
1681                }
1682                else if( $y > $y_max && $y != null )
1683                {
1684                    $y_max    = $y;
1685                }
1686
1687                // Store which non-empty columns and rows we found
1688                //
1689                if( !in_array( $x, $x_columns ) )
1690                {
1691                    $x_columns[] = $x;
1692                }
1693                if( !in_array( $y, $y_rows ) )
1694                {
1695                    $y_rows[] = $y;
1696                }
1697            }
1698
1699            // Sort all the nodes (alpha and numerically)
1700            // 1: gb-r1n1, 2: gb-r1n2, 3: gb-r2n1, etc
1701            //
1702            $sorted_nodes    = usort( $nodes, "cmp" );
1703
1704            //print_r( $x_columns ) ;
1705
1706            $cur_node    = 0;
1707
1708            $x_offset    = 0;
1709            $y_offset    = 0;
1710            $font         = 2;
1711            $fontwidth    = ImageFontWidth( $font );
1712            $fontheight    = ImageFontHeight( $font );
1713            $fontspaceing    = 2;
1714
1715            if( $this->isSmall() ) 
1716            {
1717                $y_offset    = $y_offset + (2 * $fontspaceing) + $fontheight;
1718            }
1719
1720            if( $this->isBig() ) 
1721            {
1722                $y_offset    = ($fontheight * (1 + strlen( $x_max) ) ) + ((2 + strlen( $x_max)) * $fontspaceing);
1723                $x_offset    = ($fontwidth * (1 + strlen( $y_max) ) ) + ((2 + strlen( $y_max)) * $fontspaceing);
1724            }
1725
1726            $image_width    = $x_offset + ($node_width * ($x_max-$x_min+2));
1727
1728            if( $this->isSmall() ) 
1729            {
1730                $image_width    = $max_width;
1731            }
1732            else if( $this->isBig() ) 
1733            {
1734                $image_width    = ($image_width < $max_width) ? $image_width : $max_width;
1735            }
1736            $image_height    = $y_offset + ($node_width * ($y_max-$y_min+2));
1737
1738            $this->width    = $image_width;
1739            $this->heigth    = $image_heigth;
1740
1741            $image        = imageCreateTrueColor( $image_width, $image_height );
1742            $colorwhite    = imageColorAllocate( $image, 255, 255, 255 );
1743
1744            imageFill( $image, 0, 0, $colorwhite );
1745
1746            if( $this->isSmall() )
1747            {
1748                // Draw a fancy little header text to explain what it is
1749                //
1750                $colorblue    = imageColorAllocate( $image, 0, 0, 255 );
1751
1752                imageString( $image, $font, 2, 2, "Monarch Joblist - cluster: ".$this->clustername, $colorblue );
1753            }
1754
1755            if( $this->isBig() && ( isset( $SORT_XLABEL ) || isset( $SORT_YLABEL ) ) )
1756            {
1757                $colorblue    = imageColorAllocate( $image, 0, 0, 255 );
1758
1759                if( isset( $SORT_XLABEL ) )
1760                {
1761                    // Print the {x} label: rack
1762                    //
1763                    imageString( $image, $font, $x_offset, $fontspaceing, $SORT_XLABEL, $colorblue );
1764                }
1765
1766                if( isset( $SORT_YLABEL ) )
1767                {
1768                    // Stupid php without imageStringDown function... we'll make one ourself
1769                    //
1770
1771                    // Print the {y} label: node
1772                    //
1773                    imageStringDown( $image, $font, $fontspaceing, $y_offset, $SORT_YLABEL, $colorblue );
1774                }
1775            }
1776
1777            $previous_n    = 0;
1778            $previous_m    = 0;
1779            $x_empty_count    = 0;
1780            $y_empty_count    = 0;
1781
1782            // Let's start assigning x,y coordinates now
1783            //
1784            for( $n = $x_min; $n <= $x_max; $n++ )
1785            {
1786                for( $m = $y_min; $m <= $y_max; $m++ )
1787                {
1788                    if( $x_min > 0 )
1789                    {
1790                        $x    = $x_offset + ( ($n-$x_min) * $node_width ) - ($x_empty_count * $node_width);
1791                    }
1792                    if( $y_min > 0 )
1793                    {
1794                        $y    = $y_offset + ( ($m-$y_min) * $node_width ) - ($y_empty_count * $node_width);
1795                    }
1796
1797                    // Don't show empty rows/columns if option enabled
1798                    //
1799                    if( !in_array( $n, $x_columns ) && !$SHOW_EMPTY_COLUMN )
1800                    {
1801                        // Skip to next iteration: we don't want a empty column
1802                        //
1803                        if( $n > $previous_n )
1804                        {
1805                            $previous_n = $n;
1806                            $x_empty_count++;
1807                        }
1808                        continue;
1809                    }
1810                    if( !in_array( $m, $y_rows ) && !$SHOW_EMPTY_ROW )
1811
1812                    {
1813                        // Skip to next iteration: we don't want a empty column
1814                        //
1815                        if( $m > $previous_m )
1816                        {
1817                            $previous_m = $m;
1818                            $y_empty_count++;
1819                        }
1820                        continue;
1821                    }
1822
1823                    if( $this->isBig() ) 
1824                    {
1825                        // Draw y(node) column number header
1826                        //
1827                        if(( $n == $x_min ) && ( isset($SORT_YLABEL) ) )
1828                        {
1829                            $mfontspacing    = 1;
1830
1831                            $ylabel_x    = $x - ( $fontwidth * strlen( $y_max ) ) - $mfontspacing;
1832                            $ylabel_y    = $y;
1833
1834                            imageString( $image, $font, $ylabel_x, $ylabel_y, strval( $m ), $colorblue );
1835
1836                            $xmin_hit[$n]    = true;
1837                        }
1838
1839                        // Draw x(rack) column number header
1840                        //
1841                        if(( $m == $y_min ) && ( isset($SORT_XLABEL) ) )
1842                        {
1843                            $mfontspacing    = 2;
1844                            $xlabel_y    = $y - ( $fontheight * strlen( $x_max ) );
1845                            $xlabel_x    = $x + $mfontspacing; 
1846
1847                            imageStringDown( $image, $font, $xlabel_x, $xlabel_y, strval( $n ), $colorblue );
1848                        }
1849                    }
1850
1851                    if( isset( $nodes[$cur_node] ) ) 
1852                    {
1853                        $host    = $nodes[$cur_node]->getHostname();
1854
1855                        if( $x_present && $y_present )
1856                        {
1857                            if( $x_first )
1858                            {
1859                                $nn = sscanf( $host, $skan_str, $rx, $ry );
1860                            }
1861                            else if( $y_first )
1862                            {
1863                                $nn = sscanf( $host, $skan_str, $ry, $rx );
1864                            }
1865                            if ( $nn < 2 )
1866                            {
1867                                //printf( "skipping node %s - y present & x present + <2 x,y matchs\n", $host);
1868                                continue;
1869                            }
1870                            if( intval( $rx ) > $n )
1871                            {
1872                                // If x(rack) is higher than current x, skip to next x(rack)
1873                                //
1874                                $m        = $y_max + 1;
1875
1876                                continue;
1877                            }
1878                            if( intval( $ry ) > $m )
1879                            {
1880                                // If y(node) is higher than current y, skip to next y(node)
1881                                //
1882                                continue;
1883                            }
1884                        }
1885                        else if( $x_present )
1886                        {
1887                            $nn = sscanf( $host, $skan_str, $rx );
1888                        }
1889                        else if( $y_present )
1890                        {
1891                            $nn = sscanf( $host, $skan_str, $ry );
1892                        }
1893
1894                        if( !in_array( $host, $filtered_nodes ) )
1895                        {
1896                            // This node has been filtered out: we only want to see certain nodes
1897                            //
1898                            $nodes[$cur_node]->setShowinfo( 0 );
1899                        }
1900
1901                        $nodes[$cur_node]->setCoords( $x, $y );
1902                        $nodes[$cur_node]->setImage( $image );
1903
1904                        if( $this->isSmall() )
1905                        {
1906                            $nodes[$cur_node]->drawSmall();
1907                        }
1908                        else if( $this->isBig() )
1909                        {
1910                            $nodes[$cur_node]->drawBig();
1911                        }
1912
1913                        $cur_node++;
1914                    }
1915                }
1916            }
1917
1918        }
1919        else
1920        {
1921            if( $this->isSmall() )
1922            {
1923                $image        = imageCreateTrueColor( $max_width, ($y_offset + (($node_rows*$node_width)+1) ) );
1924            }
1925            else if( $this->isBig() )
1926            {
1927                $image_width    = ($node_width * $nodes_nr) + 2;
1928                $image_width    = ($image_width < $max_width) ? $image_width : $max_width;
1929                $image        = imageCreateTrueColor( $image_width, ($y_offset + (($node_rows*$node_width)+1) ) );
1930            }
1931            $colorwhite    = imageColorAllocate( $image, 255, 255, 255 );
1932
1933            imageFill( $image, 0, 0, $colorwhite );
1934
1935            if( $this->isSmall() )
1936            {
1937                $colorblue    = imageColorAllocate( $image, 0, 0, 255 );
1938
1939                imageString( $image, $font, 2, 2, "Monarch Joblist - cluster: ".$this->clustername, $colorblue );
1940            }
1941
1942            for( $n = 0; $n < $node_rows; $n++ )
1943            {
1944                for( $m = 0; $m < $nodes_per_row; $m++ )
1945                {
1946                    $x = ($m * $node_width);
1947                    $y = $y_offset + ($n * $node_width);
1948
1949                    $cur_node = ($n * $nodes_per_row) + ($m);
1950                    $host = isset( $nodes_hosts[$cur_node] ) ? $nodes_hosts[$cur_node] : '';
1951
1952                    if( isset( $nodes[$host] ) )
1953                    {
1954                        $nodes[$host]->setCoords( $x, $y );
1955                        $nodes[$host]->setImage( $image );
1956
1957                        if( !in_array( $host, $filtered_nodes ) )
1958                        {
1959                            $nodes[$host]->setShowinfo( 0 );
1960                        }
1961
1962                        if( $this->isSmall() )
1963                        {
1964                            $nodes[$host]->drawSmall();
1965                        }
1966                        else if( $this->isBig() )
1967                        {
1968                            $nodes[$host]->drawBig();
1969                        }
1970                    }
1971                }
1972            }
1973        }
1974   
1975        $this->nodes    = &$nodes;
1976
1977        if ($this->output)
1978        {
1979            header( 'Content-type: image/png' );
1980            imagePNG( $image );
1981            imageDestroy( $image );
1982        }
1983    }
1984
1985    function getImagemapArea()
1986    {
1987        $clusterimage_map    = "";
1988
1989        foreach( $this->nodes as $hostname => $node )
1990        {
1991            $node_map        = $node->getImagemapArea();
1992            $clusterimage_map    .= $node_map;
1993        }
1994
1995        return $clusterimage_map;
1996    }
1997}
1998
1999class EmptyImage
2000{
2001    function draw()
2002    {
2003        $image        = imageCreateTrueColor( 1, 1 );
2004        $colorwhite    = imageColorAllocate( $image, 255, 255, 255 );
2005        imageFill( $image, 0, 0, $colorwhite );                         
2006
2007        header( 'Content-type: image/png' );
2008        imagePNG( $image );
2009        imageDestroy( $image );
2010    }
2011}
2012
2013class HostImage
2014{
2015    var $data_gather, $cluster, $host, $node, $image;
2016    var $headerstrlen;
2017
2018    function HostImage( $data_gather, $cluster, $host )
2019    {
2020        $this->data_gather     = $data_gather;
2021        $this->cluster        = $cluster;
2022        $this->host        = $host;
2023        $this->y_offset        = 0;
2024        $this->font        = 2;
2025        $this->fontspaceing    = 2;
2026        $this->headerstrlen    = array();
2027
2028        $this->fontheight    = ImageFontHeight( $this->font );
2029        $this->fontwidth    = ImageFontWidth( $this->font );
2030
2031        $dg            = &$this->data_gather;
2032        $this->node        = &$dg->getNode( $this->host );
2033        $n            = &$this->node;
2034        $this->njobs        = $n->getJobs();
2035    }
2036
2037    function drawJobs()
2038    {
2039        $dg                     = &$this->data_gather;
2040        $colorblack        = imageColorAllocate( $this->image, 0, 0, 0 );
2041
2042        for( $n = 0; $n < count( $this->njobs ); $n++ )
2043        {
2044            $jobid            = $this->njobs[$n];
2045            $jobinfo        = $dg->getJob( $jobid );
2046
2047            $xoffset        = 5;
2048            imageString( $this->image, $this->font, $xoffset, $this->y_offset, strval( $jobid ), $colorblack );
2049
2050            foreach( $this->headerstrlen as $headername => $headerlen )
2051            {
2052                if( $headername == 'nodes' )
2053                {
2054                    $attrval    = strval( count( $jobinfo['nodes'] ) );
2055                }
2056                else if( $headername == 'cpus' )
2057                {
2058                    if( !isset( $jobinfo['ppn'] ) )
2059                    {
2060                        $jobinfo['ppn'] = 1;
2061                    }
2062
2063                    $attrval    = strval( count( $jobinfo['nodes'] ) * intval( $jobinfo['ppn'] ) );
2064                }
2065                else if( $headername == 'runningtime' )
2066                {
2067                    $attrval    = makeTime( intval( $jobinfo['reported'] ) - intval( $jobinfo['start_timestamp'] ) );
2068                }
2069                else
2070                {
2071                    $attrval    = strval( $jobinfo[$headername] );
2072                }
2073
2074                imageString( $this->image, $this->font, $xoffset, $this->y_offset, $attrval, $colorblack );
2075       
2076                $xoffset    = $xoffset + ($this->fontwidth * ( $headerlen + 1 ) );
2077            }
2078           
2079            $this->newLineOffset();
2080        }
2081    }
2082
2083    function drawHeader()
2084    {
2085        $dg                     = &$this->data_gather;
2086
2087        for( $n = 0; $n < count( $this->njobs ); $n++ )
2088        {
2089            $jobid            = $this->njobs[$n];
2090            $jobinfo        = $dg->getJob( $jobid );
2091
2092            if( !isset( $this->headerstrlen['id'] ) )
2093            {
2094                $this->headerstrlen['id']    = strlen( strval( $jobid ) );
2095            }
2096            else if( strlen( strval( $jobid ) ) > $this->headerstrlen['id'] )
2097            {
2098                $this->headerstrlen['id']    = strlen( strval( $jobid ) );
2099            }
2100
2101            if( !isset( $this->headerstrlen['owner'] ) )
2102            {
2103                $this->headerstrlen['owner']    = strlen( strval( $jobinfo['owner'] ) );
2104            }
2105            else if( strlen( strval( $jobinfo['owner'] ) ) > $this->headerstrlen['owner'] )
2106            {
2107                $this->headerstrlen['owner']    = strlen( strval( $jobinfo['owner'] ) );
2108            }
2109
2110            if( !isset( $this->headerstrlen['queue'] ) )
2111            {
2112                $this->headerstrlen['queue']    = strlen( strval( $jobinfo['queue'] ) );
2113            }
2114            else if( strlen( strval( $jobinfo['queue'] ) ) > $this->headerstrlen['queue'] )
2115            {
2116                $this->headerstrlen['queue']    = strlen( strval( $jobinfo['queue'] ) );
2117            }
2118
2119            if( !isset( $jobinfo['ppn'] ) )
2120            {
2121                $jobinfo['ppn'] = 1;
2122            }
2123
2124            $cpus            = count( $jobinfo['nodes'] ) * intval( $jobinfo['ppn'] );
2125
2126            if( !isset( $this->headerstrlen['cpus'] ) )
2127            {
2128                $this->headerstrlen['cpus']    = strlen( strval( $cpus ) );
2129            }
2130            else if( strlen( strval( $cpus ) ) > $this->headerstrlen['cpus'] )
2131            {
2132                $this->headerstrlen['cpus']    = strlen( strval( $cpus ) );
2133            }
2134
2135            $nodes            = count( $jobinfo['nodes'] );
2136
2137            if( !isset( $this->headerstrlen['nodes'] ) )
2138            {
2139                $this->headerstrlen['nodes']    = strlen( strval( $nodes ) );
2140            }
2141            else if( strlen( strval( $nodes) ) > $this->headerstrlen['nodes'] )
2142            {
2143                $this->headerstrlen['nodes']    = strlen( strval( $nodes ) );
2144            }
2145
2146            $runningtime        = makeTime( intval( $jobinfo[reported] ) - intval( $jobinfo['start_timestamp'] ) );
2147
2148            if( !isset( $this->headerstrlen['runningtime'] ) )
2149            {
2150                $this->headerstrlen['runningtime']    = strlen( strval( $runningtime) );
2151            }
2152            else if( strlen( strval( $runningtime) ) > $this->headerstrlen['runningtime'] )
2153            {
2154                $this->headerstrlen['runningtime']    = strlen( strval( $runningtime) );
2155            }
2156
2157            if( !isset( $this->headerstrlen['name'] ) )
2158            {
2159                $this->headerstrlen['name']    = strlen( strval( $jobinfo['name'] ) );
2160            }
2161            else if( strlen( strval( $jobinfo['name'] ) ) > $this->headerstrlen['name'] )
2162            {
2163                $this->headerstrlen['name']    = strlen( strval( $jobinfo['name'] ) );
2164            }
2165        }
2166
2167        $xoffset    = 5;
2168
2169        foreach( $this->headerstrlen as $headername => $headerlen )
2170        {
2171            $colorgreen    = imageColorAllocate( $this->image, 0, 200, 0 );
2172
2173            if( $headerlen < strlen( $headername ) )
2174            {
2175                $this->headerstrlen[$headername]    = strlen( $headername );
2176            }
2177
2178            imageString( $this->image, $this->font, $xoffset, $this->y_offset, ucfirst( $headername ), $colorgreen );
2179
2180            $xoffset    = $xoffset + ($this->fontwidth * ( $this->headerstrlen[$headername] + 1 ) );
2181        }
2182        $this->newLineOffset();
2183    }
2184
2185    function newLineOffset()
2186    {
2187        $this->y_offset        = $this->y_offset + $this->fontheight + $this->fontspaceing;
2188    }
2189
2190    function draw()
2191    {
2192        $xlen        = 450;
2193        $ylen        = ( count( $this->njobs ) * ( $this->fontheight + $this->fontspaceing ) ) + (3 * $this->fontheight);
2194
2195        $this->image    = imageCreateTrueColor( $xlen, $ylen );
2196        $colorwhite    = imageColorAllocate( $this->image, 255, 255, 255 );
2197        imageFill( $this->image, 0, 0, $colorwhite );                         
2198
2199        $colorblue    = imageColorAllocate( $this->image, 0, 0, 255 );
2200
2201        imageString( $this->image, $this->font, 1, $this->y_offset, "Monarch Joblist - host: ".$this->host, $colorblue );
2202        $this->newLineOffset();
2203
2204        $this->drawHeader();
2205        $this->drawJobs();
2206
2207        header( 'Content-type: image/png' );
2208        imagePNG( $this->image );
2209        imageDestroy( $this->image );
2210    }
2211}
2212
2213function imageStringDown( &$image, $font, $x, $y, &$s, &$col )
2214{
2215    $fw    = imagefontwidth( $font);
2216    $fh    = imagefontheight( $font);
2217   
2218    $fontspacing = 0;
2219
2220    $fx    = $x;
2221    $fy    = $y;
2222
2223    for( $n=0; $n<strlen( $s ); $n++ )
2224    {
2225        $myc    = $s{$n};
2226
2227        imagestring( $image, $font, $fx, $fy, $myc, $col );
2228
2229        $fy    += ($fontspacing + $fh );
2230    }
2231}
2232
2233function array_rem( $val, &$arr )
2234{
2235    // Delete val from arr
2236    //
2237    $i    = array_search( $val, $arr );
2238
2239    if( $i == false ) return false;
2240
2241    $arr    = array_merge( array_slice( $arr, 0, $i ), array_slice( $arr, $i+1, count( $arr ) ) );
2242
2243    return true;
2244}
2245
2246function cmp( $a, $b ) 
2247{
2248    global $SORT_ORDER;
2249    global $skan_str;
2250    global $x_first, $y_first;
2251    global $x_present, $y_present;
2252
2253    $a_node        = $a;
2254    $b_node        = $b;
2255    $a        = $a_node->getHostname();
2256    $b        = $b_node->getHostname();
2257
2258    if( $a == $b ) return 0;
2259
2260    $a_x        = 0;
2261    $b_x        = 0;
2262    $a_y        = 0;
2263    $b_y        = 0;
2264
2265    if( $x_present && $y_present )
2266    {
2267        if( $x_first )
2268        {
2269            $n = sscanf( $a, $skan_str, $a_x, $a_y );
2270            $n = sscanf( $b, $skan_str, $b_x, $b_y );
2271        }
2272        else if( $y_first )
2273        {
2274            $n = sscanf( $a, $skan_str, $a_y, $a_x );
2275            $n = sscanf( $b, $skan_str, $b_y, $b_x );
2276        }
2277    } 
2278    else if( $x_present && !$y_present )
2279    {
2280        $n = sscanf( $a, $skan_str, $a_x );
2281        $n = sscanf( $b, $skan_str, $b_x );
2282    }
2283    else if( $y_present && !$x_present )
2284    {
2285        $n = sscanf( $a, $skan_str, $a_y );
2286        $n = sscanf( $b, $skan_str, $b_y );
2287    }
2288
2289    if ( $SORT_ORDER=="desc" )
2290    {
2291
2292        if( $x_present && $y_present )
2293        {
2294            // 1  = a < b
2295            // -1 = a > b
2296            //
2297            if ($a_x == $b_x)
2298            {
2299                if ($a_y < $b_y)
2300                {
2301                    return 1;
2302                }
2303                else if ($a_y > $b_y)
2304                {
2305                    return -1;
2306                }
2307            }
2308            else if ($a_x < $b_x)
2309            {
2310                return 1;
2311            }
2312            else if ($a_x > $b_x)
2313            {
2314                return -1;
2315            }
2316        } 
2317        else if( $x_present && !$y_present )
2318        {
2319            if ($a_x < $b_x)
2320            {
2321                return 1;
2322            }
2323            else if ($a_x > $b_x)
2324            {
2325                return -1;
2326            }
2327        }
2328        else if( $y_present && !$x_present )
2329        {
2330            if ($a_y < $b_y)
2331            {
2332                return 1;
2333            }
2334            else if ($a_y > $b_y)
2335            {
2336                return -1;
2337            }
2338        }
2339    }
2340    else if ( $SORT_ORDER == "asc" )
2341    {
2342
2343        if( $x_present && $y_present )
2344        {
2345            // 1  = a > b
2346            // -1 = a < b
2347            //
2348            if ($a_x == $b_x)
2349            {
2350                if ($a_y > $b_y)
2351                {
2352                    return 1;
2353                }
2354                else if ($a_y < $b_y)
2355                {
2356                    return -1;
2357                }
2358            }
2359            else if ($a_x > $b_x)
2360            {
2361                return 1;
2362            }
2363            else if ($a_x < $b_x)
2364            {
2365                return -1;
2366            }
2367        }
2368        else if( $x_present && !$y_present )
2369        {
2370            if ($a_x > $b_x)
2371            {
2372                return 1;
2373            }
2374            else if ($a_x < $b_x)
2375            {
2376                return -1;
2377            }
2378        }
2379        else if( $y_present && !$x_present )
2380        {
2381            if ($a_y > $b_y)
2382            {
2383                return 1;
2384            }
2385            else if ($a_y < $b_y)
2386            {
2387                return -1;
2388            }
2389        }
2390    }
2391}
2392function makeTime( $time )
2393{
2394        $days = intval( $time / 86400 );
2395        $time = ($days>0) ? $time % ($days * 86400) : $time;
2396
2397        $date_str = '';
2398        $day_str = '';
2399
2400        if( $days > 0 )
2401        {
2402            if( $days > 1 )
2403            {
2404                $day_str .= $days . ' days';
2405            }
2406            else
2407            {
2408                $day_str .= $days . ' day';
2409            }
2410        }
2411
2412        $hours = intval( $time / 3600 );
2413        $time = $hours ? $time % ($hours * 3600) : $time;
2414
2415        if( $hours > 0 )
2416        {
2417             $date_str .= $hours . ':';
2418             $date_unit = 'hours'; 
2419        }
2420
2421        $minutes = intval( $time / 60 );
2422        $seconds = $minutes ? $time % ($minutes * 60) : $time;
2423
2424        if( $minutes > 0 )
2425        {
2426            if( $minutes >= 10 )
2427            {
2428                $date_str .= $minutes . ':';
2429            }
2430            else
2431            {
2432                $date_str .= '0' . $minutes . ':';
2433            }
2434                $date_unit = (!isset($date_unit)) ? 'minutes' : $date_unit;
2435        }
2436        else
2437        {
2438            if($hours > 0 )
2439            {
2440                $date_str .= '00:';
2441                $date_unit = (!isset($date_unit)) ? 'minutes' : $date_unit;
2442            }
2443        }
2444
2445        $date_unit = (!isset($date_unit)) ? 'seconds' : $date_unit;
2446
2447        if( $seconds > 0 )
2448        {
2449            if( $seconds >= 10 )
2450            {
2451                $date_str .= $seconds . ' ' . $date_unit;
2452            }
2453            else
2454            {
2455                $date_str .= '0' . $seconds . ' ' . $date_unit;
2456            }
2457        }
2458        else if ( $hours > 0 or $minutes > 0 )
2459        {
2460            $date_str .= '00 ' . $date_unit;
2461        }
2462
2463        if( $days > 0)
2464        {
2465            if( $hours > 0 or $minutes > 0 or $seconds > 0 )
2466            {
2467                $date_str = $day_str . ' - ' . $date_str;
2468            }
2469            else
2470            {
2471                $date_str = $day_str;
2472            }
2473        }
2474        return $date_str;
2475}
2476?>
Note: See TracBrowser for help on using the repository browser.