File Coverage

blib/lib/Schedule/Load/Hosts.pm
Criterion Covered Total %
statement 243 386 62.9
branch 60 154 38.9
condition 27 96 28.1
subroutine 30 45 66.6
pod 15 25 60.0
total 375 706 53.1


line stmt bran cond sub pod time code
1             # Schedule::Load::Hosts.pm -- Loading information about hosts
2             # See copyright, etc in below POD section.
3             ######################################################################
4              
5             package Schedule::Load::Hosts;
6             require 5.004;
7             require Exporter;
8             @ISA = qw(Exporter);
9              
10 1     1   7 use Socket;
  1         2  
  1         737  
11 1     1   6 use POSIX qw (EWOULDBLOCK EINTR EAGAIN BUFSIZ);
  1         3  
  1         9  
12 1     1   85 use Schedule::Load qw(:_utils);
  1         2  
  1         124  
13 1     1   445 use Schedule::Load::Hold;
  1         3  
  1         29  
14 1     1   561 use Schedule::Load::Hosts::Host;
  1         4  
  1         60  
15 1     1   7 use Schedule::Load::Hosts::Proc;
  1         1  
  1         34  
16 1     1   898 use Time::localtime;
  1         5934  
  1         62  
17 1     1   8 use Sys::Hostname;
  1         3  
  1         45  
18              
19 1     1   6 use strict;
  1         1  
  1         30  
20 1     1   6 use vars qw($VERSION $Debug);
  1         2  
  1         43  
21 1     1   4 use Carp;
  1         2  
  1         5610  
22              
23             ######################################################################
24             #### Configuration Section
25              
26             # Other configurable settings.
27             $Debug = $Schedule::Load::Debug;
28              
29             $VERSION = '3.064';
30              
31             ######################################################################
32             #### Globals
33              
34             ######################################################################
35             #### Creator
36              
37             sub new {
38 1 50   1 0 6 @_ >= 1 or croak 'usage: Schedule::Load::Hosts->new ({options})';
39 1         2 my $proto = shift;
40 1   33     28 my $class = ref($proto) || $proto;
41 1   50     62 my $self = {
42             %Schedule::Load::_Default_Params,
43             username=>($ENV{USER}||""),
44             #Internal
45             @_,};
46 1         18 bless $self, $class;
47 1         6 return $self;
48             }
49              
50             ######################################################################
51             #### Constructor
52              
53             sub fetch {
54 8     8 1 1920 my $self = shift;
55 8 50       39 $self = $self->new(@_) if (!ref($self));
56 8 50 66     70 return if $self->{_fetched} && $self->{_fetched}<0;
57             # Erase current structures in case a host goes down
58 8         317 delete $self->{hosts};
59             # Make the request
60 8         65 $self->_request("get_const_load_proc_chooinfo\n");
61 8         23 $self->{_fetched} = 1;
62 8         34 return $self;
63             }
64              
65             sub _fetch_if_unfetched {
66 39     39   68 my $self = shift;
67 39 100       123 $self->fetch() if (!$self->{_fetched});
68 39         61 return $self;
69             }
70             sub kill_cache {
71 0     0 0 0 my $self = shift;
72 0         0 $self->{_fetched} = 0;
73             }
74              
75             sub restart {
76 0     0 1 0 my $self = shift;
77 0         0 my $params = {
78             chooser=>1,
79             chooser_if_reporters=>0,
80             reporter=>1,
81             @_,};
82 0 0       0 $self->_request("report_restart\n") if $params->{reporter};
83 0 0       0 $self->_request("chooser_restart_if_reporters\n") if $params->{chooser_if_reporters};
84 0 0 0     0 $self->_request("chooser_restart\n") if $params->{chooser} && !$params->{chooser_if_reporters};
85             }
86             sub _chooser_close_all {
87 0     0   0 my $self = shift;
88 0         0 $self->_request("chooser_close_all\n");
89             }
90              
91             ######################################################################
92             #### Accessors
93              
94             sub hosts {
95 0 0 0 0 1 0 my $self = shift; ($self && ref($self)) or croak 'usage: $self->hosts()';
  0         0  
96             # Return all hosts - for backward compatibility this is is a sorted accessor
97 0         0 my @keys = $self->hosts_sorted;
98 0 0       0 return (wantarray ? @keys : \@keys);
99             }
100              
101             sub hosts_sorted {
102 14 50 33 14 1 852 my $self = shift; ($self && ref($self)) or croak 'usage: $self->hosts()';
  14         94  
103             # Return all hosts
104 14         50 $self->_fetch_if_unfetched;
105             # For speed, we're avoiding the hostname accessor. Generally don't do this.
106 14   50     130 return (sort {($a->{const}{hostname}||"") cmp ($b->{const}{hostname}||"")} # $a->hostname cmp $b->hostname
  14   50     86  
107 14         20 values %{$self->{hosts}});
108             }
109              
110             sub hosts_unsorted {
111 0 0 0 0 1 0 my $self = shift; ($self && ref($self)) or croak 'usage: $self->hosts()';
  0         0  
112             # Return all hosts
113 0         0 $self->_fetch_if_unfetched;
114 0         0 return (values %{$self->{hosts}});
  0         0  
115             }
116              
117             sub hosts_match {
118 7 50 33 7 1 1635 my $self = shift; ($self && ref($self)) or croak 'usage: $self->hosts_match()';
  7         64  
119 7         20 my %params = (#classes=>[], # Passed to Host::host_match
120             #match_cb=>0, # Passed to Host::host_match
121             #allow_reserved=>1, # Passed to Host::host_match
122             @_);
123             # Return all hosts matching parameters
124 7         21 $self->_fetch_if_unfetched;
125 7         13 my @keys;
126 7         31 foreach my $host ($self->hosts_sorted) {
127 14 50       70 push @keys, $host if $host->host_match(%params);
128             }
129 7 50       46 return (wantarray ? @keys : \@keys);
130             }
131              
132             sub schreq_holds {
133 0 0 0 0 0 0 my $self = shift; ($self && ref($self)) or croak 'usage: $self->schreqs_holds()';
  0         0  
134             # Return all hosts matching parameters
135 0         0 $self->_fetch_if_unfetched;
136 0         0 my @keys;
137 0         0 foreach my $hold (values(%{$self->{chooinfo}{schreqs}})) {
  0         0  
138 0         0 push @keys, $hold;
139             }
140 0 0       0 return (wantarray ? @keys : \@keys);
141             }
142              
143             sub get_host {
144 12 50 33 12 1 95 my $self = shift; ($self && ref($self)) or croak 'usage: $self->get_host(hostname)';
  12         90  
145 12         24 my $hostname = shift;
146              
147 12         44 $self->_fetch_if_unfetched;
148 12         49 return $self->{hosts}{$hostname};
149             }
150              
151             sub classes {
152 1 50 33 1 1 2 my $self = shift; ($self && ref($self)) or croak 'usage: $self->classes()';
  1         16  
153              
154 1         3 my %classes = ();
155 1         6 $self->_fetch_if_unfetched;
156 1         18 foreach my $host ($self->hosts_sorted) {
157 2         17 foreach (sort ($host->fields)) {
158             # Ignore classes that are set to 0
159 64 100 66     189 $classes{$_} = 1 if /^class_/ && $host->get($_);
160             }
161             }
162 1         6 my @classes = (keys %classes);
163 1 50       7 return (wantarray ? @classes : \@classes);
164             }
165              
166             ######################################################################
167             ######################################################################
168             #### Totals across all hosts
169              
170             sub cpus {
171 1 50 33 1 0 3 my $self = shift; ($self && ref($self)) or croak 'usage: $self->classes()';
  1         10  
172 1         5 my %params = (#classes=>[], # Passed to Host::host_match
173             #match_cb=>0, # Passed to Host::host_match
174             allow_reserved=>1, # Passed to Host::host_match
175             @_);
176             # Return number of cpus for a given class
177 1         4 $self->_fetch_if_unfetched;
178 1         2 my $jobs = 0;
179 1         24 foreach my $host ($self->hosts_match(%params)) {
180 2         53 $jobs += $host->cpus();
181             }
182 1         3 return $jobs;
183             }
184              
185             sub hostnames {
186 0 0 0 0 0 0 my $self = shift; ($self && ref($self)) or croak 'usage: $self->hosts()';
  0         0  
187 0         0 my %params = (#classes=>[], # Passed to Host::host_match
188             #match_cb=>0, # Passed to Host::host_match
189             allow_reserved=>1, # Passed to Host::host_match
190             @_);
191             # Return hostnames, potentially matching given classes
192 0         0 my @hnames;
193 0         0 foreach my $host ($self->hosts_match(%params)) {
194 0         0 push @hnames, $host->hostname;
195             }
196 0         0 @hnames = (sort @hnames);
197 0 0       0 return (wantarray ? @hnames : \@hnames);
198             }
199              
200             sub idle_host_names {
201 4 50 33 4 1 9 my $self = shift; ($self && ref($self)) or croak 'usage: $self->hosts()';
  4         24  
202 4         22 my %params = (#classes=>[], # Passed to Host::host_match
203             #match_cb=>0, # Passed to Host::host_match
204             allow_reserved=>0, # Passed to Host::host_match
205             #ign_pctcpu=>0,
206             #by_pctcpu=>0,
207             @_);
208             # Return idle hosts, potentially matching given classes
209             # Roughly scaled so even powered hosts have even representation
210              
211 4         5 my @hnames;
212 4         29 foreach my $host ($self->hosts_match(%params)) {
213 8         160 my $idleCpus = $host->cpus;
214 8 50       29 if ($params{ign_pctcpu}) {
    50          
215             } elsif ($params{by_pctcpu}) { # min of adj_load or percentage
216 0         0 $idleCpus = $host->cpus;
217 0         0 my $adj = (($host->cpus * $host->total_pctcpu / 100) - 0.2); # 80% used? squeeze another in
218 0 0       0 $adj = 0 if $adj<0;
219 0         0 $idleCpus -= $adj;
220             } else {
221 8         31 $idleCpus = $host->free_cpus;
222             }
223 8         23 for (my $c=0; $c<$idleCpus; $c++) {
224 128         2898 push @hnames, $host->hostname;
225             }
226             }
227 4         25 @hnames = (sort @hnames);
228 4 50       56 return (wantarray ? @hnames : \@hnames);
229             }
230              
231             ######################################################################
232             ######################################################################
233             #### Low level prints
234              
235             sub digit {
236 2     2 0 4 my $host = shift;
237 2         5 my $field = shift;
238 2 50       14 return " " if !$host->exists($field);
239 0         0 my $val = $host->get($field);
240 0 0       0 return " " if !$val;
241 0 0       0 return "*" if $val>9;
242 0         0 return $val;
243             }
244              
245             sub _format_time {
246 0   0 0   0 my $value = shift || 0;
247 0         0 my $t = localtime($value);
248 0         0 return sprintf("%04d/%02d/%02d %02d:%02d:%02d", $t->year+1900,$t->mon+1,$t->mday,$t->hour,$t->min,$t->sec);
249             }
250              
251             sub _format_utime {
252 0     0   0 my $time = shift;
253 0         0 my $time_usec = shift;
254 0         0 my ($sec,$min,$hour,$mday,$mon) = CORE::localtime($time);
255 0         0 return sprintf ("[%02d/%02d %02d:%02d:%02d.%06d]",
256             $mon+1, $mday, $hour, $min, $sec, $time_usec);
257             }
258              
259             sub _hostname_width {
260 0     0   0 my $hosts = shift;
261 0         0 my $hostwidth = 4; # For 'HOST' header
262 0         0 foreach my $host ($hosts->hosts_sorted) {
263 0 0       0 $hostwidth = length($host->hostname) if $hostwidth < length($host->hostname);
264             }
265 0         0 return $hostwidth;
266             }
267              
268             ######################################################################
269             ######################################################################
270             #### Table printing
271              
272             sub format_table {
273 3     3 1 5 shift; # Ignored; just so can object call it
274 3         14 my %params = (formats => [],
275             data => [],
276             @_);
277             # Given table with row of formats, where ^ is the width of the column,
278             # return string with data formatted.
279 3         7 my @widths;
280 3         153 foreach my $rowref (@{$params{data}}) {
  3         8  
281 8         14 for (my $col=0; $col<=$#{$rowref}; $col++) {
  56         117  
282 48 50       89 $rowref->[$col] = '' if !defined $rowref->[$col];
283 48 100 100     187 $widths[$col] = length($rowref->[$col])
284             if (($widths[$col]||0) < length($rowref->[$col]));
285             }
286             }
287 3         4 my @formats = (@{$params{formats}});
  3         13  
288 3         11 for (my $col=0; $col<=$#formats; $col++) {
289 19   50     40 my $width = $widths[$col] || 1;
290 19         72 $formats[$col] =~ s!\^!$width!;
291             }
292 3         4 my @out;
293 3         4 foreach my $rowref (@{$params{data}}) {
  3         8  
294 8         11 for (my $col=0; $col<=$#{$rowref}; $col++) {
  56         121  
295 48 100       99 push @out, ' ' if $col>0;
296 48         167 push @out, sprintf($formats[$col], $rowref->[$col]);
297             }
298 8         18 push @out, "\n";
299             }
300 3         46 return join ("", @out);
301             }
302              
303             ######################################################################
304             ######################################################################
305             #### Information printing
306              
307             sub print_hosts {
308 1     1 1 598 my $hosts = shift;
309             # Overall machine status
310 1         25 my @fmts = ("%-^s", " %^s", "%^s", "%^s%%", "%^s", "%^s", "%^s"," %s");
311 1         12 my @data = ["HOST", "CPUs", "FREQ", "TotCPU", "LOAD", "RATE", "RL", "ARCH/OS"];
312 1         39 foreach my $host ($hosts->hosts_sorted) {
313 2         83 my $ostype = $host->archname ." ". $host->osvers;
314 2 50       29 $ostype = "Reserved: ".$host->reserved if ($host->reserved);
315 2 50       29 push @data, [$host->hostname,
316             $host->cpus_slash,
317             $host->max_clock,
318             sprintf("%3.1f", $host->total_pctcpu),
319             sprintf("%2.2f", $host->adj_load),
320             $host->rating_text,
321             ( ($host->reservable?"R":" ")
322             . digit($host,'load_limit')),
323             $ostype,
324             ];
325             }
326 1         13 return $hosts->format_table(formats=>\@fmts, data=>\@data);
327             }
328              
329             sub print_holds {
330 0     0 0 0 my $hosts = shift;
331             # Holding commands
332 0         0 my %holdlist;
333 0         0 my $i=0;
334 0         0 foreach my $host ($hosts->hosts_sorted) {
335 0         0 foreach my $hold ($host->holds) {
336 0         0 $i++;
337 0         0 my $key = $hold->req_user."_".$hold->req_hostname."_".$hold->req_pid
338             ."_".$hold->hold_key."_".$host->hostname."_".$i;
339 0 0       0 $holdlist{$key} = {hold => $hold,
340             host => $host,
341             code => ($hold->allocated?"A":"S"),};
342             }
343             }
344 0         0 foreach my $hold ($hosts->schreq_holds) {
345 0         0 my $key = $hold->req_user."_".$hold->req_hostname."_".$hold->req_pid
346             ."_".$hold->hold_key."_CHOO_".$i;
347 0         0 $holdlist{$key} = {hold => $hold,
348             host => undef,
349             code => "P",};
350             }
351 0         0 my @fmts = ("%-^s", " %-^s", " %^s", "%^s", "%^s","%^s","%^s", "%-^s", " %-s");
352 0         0 my @data = ["USER", "UHOST", "UPID", "PRI", "L", "S", "WAIT", "ON_HOST", "COMMENT"];
353 0         0 foreach my $key (sort (keys %holdlist)) {
354 0         0 my $hold = $holdlist{$key}{hold};
355 0         0 my $host = $holdlist{$key}{host};
356 0 0       0 push @data, [$hold->req_user,
357             $hold->req_hostname,
358             $hold->req_pid,
359             $hold->req_pri,
360             $hold->hold_load,
361             $holdlist{$key}{code},
362             Schedule::Load::Hosts::Proc->format_hhmm(time() - $hold->req_time),
363             #
364             ($host ? $host->hostname : "{pending}"),
365             $hold->comment,
366             ];
367             }
368 0         0 return $hosts->format_table(formats=>\@fmts, data=>\@data);
369             }
370              
371             sub print_status {
372 0     0 0 0 my $hosts = shift;
373             # Daemon status, mostly for debugging
374 0         0 $hosts->_fetch_if_unfetched;
375 0         0 my $out = "";
376             {
377 0         0 my @fmts = ("%-^s", "%^s", "%-^s", "%^s", " %-s");
  0         0  
378 0         0 my @data = ["CHOOSER", "VERSION", "CONNECTED", "DELAY", "DAEMON STATUS"];
379 0   0     0 push @data, [$hosts->{chooinfo}{slchoosed_hostname},
      0        
      0        
380             ($hosts->{chooinfo}{slchoosed_version}||"?"),
381             _format_time($hosts->{chooinfo}{slchoosed_connect_time}||0),
382             sprintf("%2.3f",$hosts->{chooinfo}{last_command_delay}||0),
383             $hosts->{chooinfo}{slchoosed_status}];
384 0         0 $out .= $hosts->format_table(formats=>\@fmts, data=>\@data);
385 0         0 $out .= "\n";
386             }
387             {
388 0         0 my @fmts = ("%-^s", "%-^s", "%-^s", "%-^s",);
  0         0  
389 0         0 my @data = ["CHOOSER", "DATE", "LEVEL", "MESSAGE"];
390 0   0     0 my $msgs = $hosts->{chooinfo}{slchoosed_messages}||[];
391 0         0 foreach my $msg (@$msgs) {
392 0         0 my $text = $msg->[3]; $text =~ s!\n$!!;
  0         0  
393 0         0 push @data, [$hosts->{chooinfo}{slchoosed_hostname},
394             _format_utime($msg->[0], $msg->[1]),
395              
396             $msg->[2], $text];
397             }
398 0         0 $out .= $hosts->format_table(formats=>\@fmts, data=>\@data);
399 0         0 $out .= "\n";
400             }
401             {
402 0         0 my @fmts = ("%-^s", "%^s%%", "%^s", "%^s", "%^s", "%-^s", "%-^s", "%^s", " %-s");
  0         0  
403 0         0 my @data = ["HOST", "TotCPU","LOAD", "RATE", "REPORTER", "VERSION", "CONNECTED", "DELAY", "DAEMON STATUS"];
404 0         0 foreach my $host ($hosts->hosts_sorted) {
405 0 0 0     0 push @data, [$host->hostname,
      0        
406             sprintf("%3.1f", $host->total_pctcpu),
407             sprintf("%2.2f", $host->adj_load),
408             $host->rating_text,
409             $host->slreportd_hostname,
410             ($host->get_undef('slreportd_version')||"?"),
411             _format_time($host->slreportd_connect_time||0),
412             (defined $host->slreportd_delay ? sprintf("%2.3f",$host->slreportd_delay) : "?"),
413             $host->slreportd_status,
414             ];
415             }
416 0         0 $out .= $hosts->format_table(formats=>\@fmts, data=>\@data);
417             }
418 0         0 return $out;
419             }
420              
421             sub print_top {
422 1     1 1 2 my $hosts = shift;
423             # Top processes
424 1         23 my @fmts = ("%-^s", "%^s", "%-^s", "%^s", "%^s", "%-^s", "%^s", "%^s%%"," %-s");
425 1         6 my @data = ["HOST", "PID", "USER", "NICE", "MEM", "STATE", "RUNTM", "CPU","COMMAND"];
426 1         4 foreach my $host ($hosts->hosts_sorted) {
427 2         5 foreach my $p ( sort {$b->pctcpu <=> $a->pctcpu}
  0         0  
  2         10  
428             @{$host->top_processes} ) {
429 1 50       60 next if ($p->pctcpu < $hosts->{min_pctcpu});
430 1 50       13 my $comment = ($p->exists('cmndcomment')? $p->cmndcomment:$p->fname);
431 1   50     27 push @data, [$host->hostname,
432             $p->pid,
433             $p->uname, $p->nice0,
434             int(($p->size||0)/1024/1024)."M",
435             $p->state, $p->time_hhmm,
436             sprintf("%3.1f", $p->pctcpu),
437             substr ($comment,0,18),
438             ];
439             }
440             }
441 1         4 return $hosts->format_table(formats=>\@fmts, data=>\@data);
442             }
443              
444             sub print_loads {
445 0     0 1 0 my $hosts = shift;
446             # Top processes
447 0         0 my @fmts = ("%-^s", "%-^s", "%^s", "%-^s", "%^s", "%^s", "%^s%%", " %-s");
448 0         0 my @data = ["HOST", "REQHOST", "PID", "USER", "NIC", "RUNTM", "CPU", "COMMAND"];
449 0         0 foreach my $host ($hosts->hosts_sorted) {
450 0         0 foreach my $p ( sort {$b->pctcpu <=> $a->pctcpu}
  0         0  
  0         0  
451             @{$host->top_processes} ) {
452 0 0       0 my $comment = ($p->exists('cmndcomment')? $p->cmndcomment:$p->fname);
453 0 0       0 push @data, [$host->hostname,
454             ($p->exists('req_hostname')? $p->req_hostname : ''),
455             $p->pid,
456             $p->uname,
457             $p->nice,
458             $p->time_hhmm,
459             sprintf("%3.1f", $p->pctcpu),
460             $comment,
461             ];
462             }
463             }
464 0         0 return $hosts->format_table(formats=>\@fmts, data=>\@data);
465             }
466              
467             sub print_kills {
468 0     0 0 0 my $hosts = shift;
469 0         0 my $params = {
470             signal=>0,
471             @_,};
472             # Top processes
473 0         0 my @fmts = ("ssh %-^s"," kill %s","%^s"," # %-^s","%-^s","%^s","%^s%%","%-s");
474 0         0 my @data;
475 0         0 foreach my $host ($hosts->hosts_sorted) {
476 0         0 foreach my $p ( sort {$b->pctcpu <=> $a->pctcpu}
  0         0  
  0         0  
477             @{$host->top_processes} ) {
478 0 0       0 my $comment = ($p->exists('cmndcomment')? $p->cmndcomment:$p->fname);
479 0 0       0 push @data, [($p->exists('req_hostname')? $p->req_hostname : $host->hostname),
    0          
480             ($params->{signal}?"-$params->{signal} ":""),
481             $p->pid,
482             $host->hostname,
483             $p->uname, $p->time_hhmm,
484             sprintf("%3.1f", $p->pctcpu),
485             $comment,
486             ];
487             }
488             }
489 0         0 return $hosts->format_table(formats=>\@fmts, data=>\@data);
490             }
491              
492             sub print_classes {
493 1     1 1 3 my $hosts = shift;
494             # Host classes
495 1         11 my $out = "";
496              
497 1         10 my @classes = (sort ($hosts->classes()));
498 1         3 my $classnum = 0;
499 1         2 my %class_letter;
500             my %class_numeric;
501 0         0 my @col_width;
502 1         3 foreach my $class (@classes) {
503 1         7 $class_letter{$class} = chr($classnum%26+ord("a"));
504 1         2 $col_width[$classnum] = 1;
505 1         4 foreach my $host ($hosts->hosts_sorted) {
506 2         7 my $val = $host->get_undef($class);
507 2 50       8 if ($val) {
508 2 50       6 $col_width[$classnum] = length $val if $col_width[$classnum] < length $val;
509 2 50       10 $class_numeric{$class} = 1 if $val>1;
510             }
511             }
512 1         3 $classnum++;
513             }
514              
515 1         18 my @fmts = ("%-^s", "%-s");
516 1         3 my @data;
517              
518 1         2 my $classes = $classnum;
519 1         2 $classnum = 0;
520 1         3 foreach my $class (@classes) {
521 1         8 my $out;
522 1         5 for (my $prtclassnum = 0; $prtclassnum<$classnum; $prtclassnum++) {
523 0         0 $out .= (" "x$col_width[$prtclassnum])."|";
524             }
525 1         5 $out .= (" "x$col_width[$classnum]).$class_letter{$class};
526 1         5 for (my $prtclassnum = $classnum+1; $prtclassnum<$#classes; $prtclassnum++) {
527 0         0 $out .= ("-"x$col_width[$prtclassnum])."-";
528             }
529 1 50       4 $out.= "-$class_letter{$class}" if $classnum!=$classes-1;
530 1         5 $out.=sprintf ("- %s", $class);
531 1         2 $classnum++;
532 1 50       7 push @data, [(($classnum==$classes-1)?"HOST":""), $out];
533             }
534 1         3 foreach my $host ($hosts->hosts_sorted) {
535 2         4 my $out;
536 2         2 $classnum = 0;
537 2         5 foreach my $class (@classes) {
538 2         7 my $val = $host->get_undef($class);
539 2         11 my $chr = ".";
540 2 50 33     35 if ($val && ($val > 1 || $class_numeric{$class})) {
    50 33        
541 0         0 $chr = $val;
542             } elsif ($val) {
543 2         5 $chr = $class_letter{$class};
544             } else {
545 0         0 $chr = ".";
546             }
547 2         7 $out .= sprintf (" %$col_width[$classnum]s", $chr);
548 2         5 $classnum++;
549             }
550 2         63 push @data, [$host->hostname, $out];
551             }
552 1         5 return $hosts->format_table(formats=>\@fmts, data=>\@data);
553             }
554              
555             ######################################################################
556             ######################################################################
557             #### User requests
558              
559             sub cmnd_comment {
560 1 50 33 1 0 888150 my $self = shift; ($self && ref($self)) or croak 'usage: $self->cmnd_comment)';
  1         26  
561 1         11 my $params = {
562             host=>hostname(),
563             comment=>undef,
564             uid=>$<,
565             pid=>$$,
566             @_,};
567              
568 1 50       54 print __PACKAGE__."::cmnd_comment($params->{comment})\n" if $Debug;
569 1 50       8 (defined $params->{comment}) or croak 'usage: cmnd_comment needs comment parameter)';
570 1         9 $self->_request(_pfreeze( 'report_fwd_comment', $params, $Debug));
571             }
572              
573             ######################################################################
574             ######################################################################
575             #### Guts: Sending and receiving messages
576              
577             sub _open {
578 1     1   9 my $self = shift;
579              
580 1         4 my @hostlist = ($self->{dhost});
581 1 50       5 @hostlist = @{$self->{dhost}} if (ref($self->{dhost}) eq "ARRAY");
  0         0  
582              
583 1         2 my $fh;
584 1         9 foreach my $host (@hostlist) {
585 1 50       11 print "Trying host $host\n" if $Debug;
586 1         50 $fh = Schedule::Load::Socket->new(
587             PeerAddr => $host,
588             PeerPort => $self->{port},
589             );
590 1 50       4 if ($fh) {
591 1 50       13 print "Opened $host\n" if $Debug;
592 1         4 last;
593             }
594             }
595 1 50       5 if (!$fh) {
596 0 0       0 if (defined $self->{print_down}) {
597 0         0 &{$self->{print_down}} ($self);
  0         0  
598 0         0 return;
599             }
600 0         0 croak "%Error: Can't locate slchoosed server on " . (join " or ", @hostlist), " $self->{port}\n"
601             . "\tYou probably need to run slchoosed\n$self->_request(): Stopped";
602             }
603 1         3 $self->{_fh} = $fh;
604 1         13 $self->{_inbuffer} = "";
605             }
606              
607             sub _request {
608 20     20   46 my $self = shift;
609 20         46 my $cmd = shift;
610 20   50     179 my %params = (req_retries => ($self->{req_retries}||3),
      50        
611             req_retry_delay => ($self->{req_retry_delay}||20),
612             );
613              
614 20         92 for (my $retry=0; $retry<$params{req_retries}; $retry++) {
615 20         83 my $done = $self->_request_try($cmd);
616 20 50       68 if ($done) {
617 20         128 last;
618             } else {
619 0 0       0 print "RETRY\n" if $Debug;
620 0         0 sleep $params{req_retry_delay};
621             }
622             }
623             }
624              
625             sub _request_try {
626 20     20   43 my $self = shift;
627 20         37 my $cmd = shift;
628              
629 20 100       256 if (!defined $self->{_fh}) {
630 1         35 $self->_open;
631             }
632 20         45 my $fh = $self->{_fh};
633              
634 20 50       63 print "_request-> $cmd\n" if $Debug;
635 20         103 $fh->send_and_check($cmd);
636              
637 20         33 my $done;
638             my $eof;
639 0         0 my $completed;
640 20         202 while (!$done) {
641 27 50       117 if ($self->{_inbuffer} !~ /\n/) {
642 27         57 my $data = '';
643 27         56 $!=undef;
644 27         162 my $rv = $fh->sysread($data, POSIX::BUFSIZ, 0);
645 27         9572860 $self->{_inbuffer} .= $data;
646 27 0 33     292 $eof = 1 if (!defined $rv || (length $data == 0))
      0        
      33        
647             && ($! != POSIX::EINTR && $! != POSIX::EAGAIN);
648 27   33     167 $done ||= $eof;
649             }
650              
651 27         612 while ($self->{_inbuffer} =~ s/^([^\n]*)\n//) {
652 80         273 my $line = $1;
653 80         145 chomp $line;
654 80 50       204 print "GOT $line\n" if $Debug;
655              
656 80         380 my ($cmd, $params) = _pthaw($line, $Debug);
657 80 50       432 next if $line =~ /^\s*$/;
658 80 100       295 if ($cmd eq "DONE") {
    100          
    100          
    50          
659 20         36 $done = 1;
660 20         218 $completed = 1;
661             } elsif ($cmd eq "host") {
662 48         159 $self->_host_load ($params);
663             } elsif ($cmd eq "schrtn") {
664 4         21 $self->{_schrtn} = $params;
665             } elsif ($cmd eq "chooinfo") {
666 8         104 $self->{chooinfo} = $params;
667             } else {
668 0         0 warn "%Warning: Bad Schedule::Load server response: $line\n";
669 0         0 $line = undef;
670             }
671             }
672             }
673 20 50 33     173 if ($eof || !$fh->connected()) {
674 0         0 $fh->close();
675 0         0 undef $self->{_fh};
676             }
677 20 50       558 print "_request DONE-> $cmd\n" if $Debug;
678 20         65 return $completed;
679             }
680              
681             ######################################################################
682             #### Loading
683              
684             sub _host_load {
685 48     48   62 my $self = shift;
686 48         60 my $params = shift;
687             # load/proc command (also used by Chooser)
688             # Load a Hosts::Host hash, bless, and load given field
689             # Move perhaps to Hosts::Host->new.
690              
691 48         153 my $hostname = $params->{hostname};
692 48         77 my $field = $params->{type};
693              
694 48         208 $self->{hosts}{$hostname}{$field} = $params->{table};
695 48         1010 bless $self->{hosts}{$hostname}, "Schedule::Load::Hosts::Host";
696             }
697              
698             ######################################################################
699             ######################################################################
700             #### Utilities
701              
702             sub ping {
703 0     0 1   my $self = shift;
704 0           my @params = @_;
705 0           my $ok = eval {
706 0           $self->fetch(@params);
707             };
708 0           return $ok;
709             }
710              
711             ######################################################################
712             #### Package return
713             1;
714              
715             ######################################################################
716             __END__