File Coverage

blib/lib/Parallel/Mpich/MPD/Common.pm
Criterion Covered Total %
statement 112 173 64.7
branch 40 102 39.2
condition 10 20 50.0
subroutine 15 20 75.0
pod 7 12 58.3
total 184 327 56.2


line stmt bran cond sub pod time code
1             package Parallel::Mpich::MPD::Common;
2              
3 12     12   64 use strict;
  12         23  
  12         422  
4 12     12   70 use File::Temp;
  12         25  
  12         1118  
5 12     12   72 use IO::All;
  12         26  
  12         98  
6 12     12   813 use Data::Dumper;
  12         27  
  12         488  
7 12     12   10598 use Sys::Hostname;
  12         198868  
  12         40894  
8             =head1 NAME
9              
10             Parallel::Mpich::MPD::Common - Mpich Common datas and fonctions
11              
12             =head1 SYNOPSIS
13              
14             =head1 DESCRIPTION
15              
16             =head1 SEE ALSO
17              
18             =head1 AUTHOR
19              
20             Olivier Evalet, Alexandre Masselot, C<< >>
21              
22             =head1 EXPORT
23              
24             =head3 $MPICH_HOME
25              
26             mpich prefix (where it was installed). [default is empty, so mpich command shall be in the path]
27              
28             =head1 FUNCTIONS
29              
30             =head2 Environment
31              
32             =head2 env_MpichHome([$val])
33              
34             Get or set (if $val is defined) the Mpich home
35              
36             =head2 env_Check
37              
38             Check if mpd environment is correct
39              
40             =head2 env_Print
41              
42             print current environment
43              
44             =head2 nbHostInMachinefile(machinesfile => $file)
45              
46             return the nb hosts available on machinesfiles
47              
48             =head2 commandPath($cmd)
49              
50             prepend $MPICH_HOME/bin if $MPICH_HOME is defined and return the global command dstring
51              
52             =head2 checkHosts(machinesfile => $machinesfile , hostsdown => \%hostsdown , hostsup =>\%hostsup)
53              
54             check hosts from machinesfile.
55             - check hosts with a ping
56             - check that ssh publickey is well configured
57            
58            
59             =head2 cleanTemp
60              
61             remove tmp files
62            
63             =head2 __exec(cmd => $cmd, params => $params, [stdout=>\$stdout], [stderr=>\$stderr], [pid=>\$pid], [spawn=>$spawn=1])
64              
65             extended exec that return the exit value and catch stds and pid.
66              
67             =head1 BUGS
68              
69             Please report any bugs or feature requests to
70             C, or through the web interface at
71             L.
72             I will be notified, and then you'll automatically be notified of progress on
73             your bug as I make changes.
74              
75             =head1 SUPPORT
76              
77             You can find documentation for this module with the perldoc command.
78              
79             perldoc Parallel::Mpich::MPD
80              
81             You can also look for information at:
82              
83             =over 4
84              
85             =item * AnnoCPAN: Annotated CPAN documentation
86              
87             L
88              
89             =item * CPAN Ratings
90              
91             L
92              
93             =item * RT: CPAN's request tracker
94              
95             L
96              
97             =item * Search CPAN
98              
99             L
100              
101             =back
102              
103             =head1 ACKNOWLEDGEMENTS
104              
105             =head1 COPYRIGHT & LICENSE
106              
107             Copyright 2006 Olivier Evalet, Alexandre Masselot, all rights reserved.
108              
109             This program is free software; you can redistribute it and/or modify it
110             under the same terms as Perl itself.
111              
112             =cut
113              
114             require Exporter;
115             our %env;
116             our $MPICH_HOME=(defined $ENV{MPICH_HOME})?$ENV{MPICH_HOME}:"";
117             our $TMP_MPD_PREFIX="mpd-$ENV{USER}";
118             our $DEBUG=0;
119             our $WARN=0;
120             our $TEST=0;
121             our $ERROR_MSG;
122             our (@ISA, @EXPORT, @EXPORT_OK);
123             our @MPDBINS= qw(mpdlistjobs mpdcheck mpdboot mpdcleanup mpdtrace mpdringtest mpdallexit mpiexec);
124             @ISA = qw(Exporter);
125             @EXPORT = qw(%env env_MpichHome env_Init env_Check env_RPC env_User commandPath checkHosts stripMachinefile $ERROR_MSG $TMP_MPD_PREFIX);
126              
127              
128             @EXPORT_OK = ();
129              
130              
131             #
132             # environment functions
133             #
134             sub env_MpichHome{
135 0     0 1 0 my $val=shift;
136 0 0       0 if(defined $val){
137 0         0 $MPICH_HOME=$val;
138             }
139 0         0 return $MPICH_HOME;
140             }
141              
142              
143             sub commandPath{
144 9 50   9 1 44 my $cmd=shift or die "must provide a command to commanPath";
145            
146 9 50       100 return $MPICH_HOME?$MPICH_HOME."/bin/$cmd":$cmd;
147             }
148             our $_isEnvInited;
149              
150             sub env_Init{
151 3     3 0 11 my %prms=@_;
152 3 50       19 if($prms{reset}){
153 0         0 undef %env;
154 0         0 undef $_isEnvInited;
155             }
156 3 50       14 unless (defined $prms{root}){
157 3         488448 my $id=`id -u`;
158 3         78 chop $id;
159 3 0 33     133 die "ERROR: You must NOT run MPD as super user (root:$id)." if (!$TEST && $id==0 && defined $id);
      33        
160             }
161 3 100       58 return if $_isEnvInited;
162            
163 2 50       361 $env{path}=$MPICH_HOME?"$MPICH_HOME/bin":"";
164              
165 2 100       70 env_Hostsfile("$ENV{HOME}/mpd.hosts") unless $env{conf}{mpd}{hostsfile};
166            
167             #os info
168 2         29 $env{info}{user}="$ENV{USER}";
169 2         74 $env{info}{host}=hostname();
170             #mpd informations
171 2 50       278 $env{info}{ncpus}="0" unless $env{info}{ncpus};
172 2 50       19 $env{info}{listport}="0" unless $env{info}{listport};
173 2 50       28 $env{info}{ifhn}="" unless $env{info}{ifhn};
174 2         20 $_isEnvInited=1;
175             }
176              
177             sub env_Check{
178 1     1 1 3 my $stderr="";
179 1         2 my $cpu="";
180 1         5 env_Init();
181 1         14 foreach (@MPDBINS){
182 1         9 my $cmd=commandPath($_);
183 1 50       6874 unless(`$cmd -h`){
184 1         29 $ERROR_MSG="ERROR:env_Check() cannot execute $cmd -h";
185 1         30 goto err;
186             }
187             }
188 0 0       0 unless($env{conf}{mpiexec}{ncpu}){
189 0         0 $ERROR_MSG="ERROR:env_Check() empty number of cpu defined";
190 0         0 goto err;
191             }
192              
193 0 0       0 unless ( -e "$ENV{HOME}/.mpd.conf"){
194 0         0 $ERROR_MSG="ERROR:env_Check() could not find \$HOME/.mpd.conf at : $ENV{HOME}/.mpd.conf";
195 0         0 goto err;
196             }
197            
198 0         0 return 1;
199 1 50       538 err:
200             Carp::cluck $ERROR_MSG if defined($ERROR_MSG);
201 1         48 return 0;
202             }
203              
204              
205             #env_User([$user])
206             # $user specify the default user
207             sub env_User{
208 0     0 0 0 my $user=shift;
209 0         0 $env{info}{user}=$user;
210 0         0 return $user;
211             }
212              
213             sub env_Ncpu{
214 0     0 0 0 my $ncpu=shift;
215 0         0 $env{conf}{mpiexec}{ncpu}=$ncpu;
216 0         0 return $ncpu;
217             }
218              
219             #env_Hostsfile([$hostfile])
220             # $hostfile specify the default hostsfile for mpd
221             sub env_Hostsfile{
222 3     3 0 1905 my ($hostsfile)=@_;
223             # Carp::cluck "HOST FILE=[$hostsfile]\n";
224 3 50       26 return $env{conf}{mpd}{hostsfile} unless $hostsfile;
225              
226 3 100 50     152 print STDERR "ERROR: no $hostsfile" && return 0 unless -f $hostsfile;
227              
228 2         11 $env{conf}{mpd}{hostsfile}=$hostsfile;
229             # the localhost should be added (could be a FIXME)
230 2         12 $env{conf}{mpiexec}{ncpu}=nbHostInMachinefile($env{conf}{mpd}{hostsfile});
231 2         129 return $env{conf}{mpd}{hostsfile};
232             }
233              
234             sub nbHostInMachinefile{
235 2 50   2 1 15 my $file=shift or die "must provide a file to ".__PACKAGE__.":nbHostInMachinefile()";
236 2         14 my $hosts = io($file)->slurp;
237 2         20555 $hosts=~s/#.*$//gm;
238 2         66 my @tmp=split(/\s*\n\s*/, $hosts);
239 2         6 my $count=@tmp;
240 2 50       15 print "DEBUG:nbHostInMachinefile(1) input=$file return=$count\n" if $DEBUG==1;
241 2         15 return $count;
242             }
243              
244             sub stripMachinefile{
245 6 50   6 0 9690 my $file=shift or die "must provide a file to ".__PACKAGE__.":stripMachinefile()";
246 6         54 my $hosts = io($file)->slurp;
247 6         61392 $hosts=~s/#.*$//gm;
248 6         240 my @tmp=split(/\s*\n\s*/, $hosts);
249 6         18 my %host;
250 6         24 foreach my $h (@tmp){
251 24         60 $host{$h}=1;
252             }
253 6         30 @tmp= keys %host;
254 6         18 my $count=@tmp;
255            
256 6         762 my $fh = new File::Temp(UNLINK=>0, TEMPLATE => File::Spec->tmpdir."/$TMP_MPD_PREFIX-hosts-XXXX");
257 6         17040 foreach (@tmp){
258 12         474 print $fh $_."\n";
259             }
260            
261 6 50       36 print "DEBUG:stripMachinefile(1) input=$file return=$count, output=".$fh->filename."\n" if $DEBUG==1;
262 6         42 return ($count,$fh->filename);
263             }
264              
265             sub env_Print{
266 1     1 1 13 env_Init();
267 1         97 printf "%-20s : %s\n", "user", "$env{info}{user}";
268 1         15 printf "%-20s : %s\n", "machinesfile", $env{conf}{mpd}{hostsfile};
269 1         21 printf "%-20s : %s\n", "mpiexec.cpu", $env{conf}{mpiexec}{ncpu};
270            
271 1         13 printf "%-20s : %s\n", "mpd.cpu", $env{info}{ncpus};
272 1         15 printf "%-20s : %s\n", "mpd.port", $env{info}{listport};
273 1         12 printf "%-20s : %s\n", "mpd.master", $env{info}{host};
274 1         9 printf "%-20s : %s\n", "mpd.ifhn", $env{info}{ifhn};
275            
276 1         17 printf "%-20s : %s\n", "mpd.home", $MPICH_HOME;
277 1         61 foreach (@MPDBINS){
278 8         26 printf "%-20s : %s\n", "mpd.command", $MPICH_HOME.commandPath($_);
279             }
280 1         34 return 1;
281             }
282              
283            
284              
285             sub __param_buildHost{
286             #FIXME: ca veut dire quoi, cette ligne?
287 0     0   0 my @hosts=shift;
288 0 0       0 if(@hosts){
289 0         0 my $fh = new File::Temp(UNLINK=>!$ENV{DO_NOT_REMOVE_TEMPFILE}, TEMPLATE => File::Spec->tmpdir."/$TMP_MPD_PREFIX-hosts-XXXX");
290             # $hosts=~s/\s+/\n/g;
291 0         0 foreach (@hosts){
292 0         0 print $fh $_."\n";
293             }
294 0         0 return $fh->filename;
295             }
296             }
297              
298             # Check hosts will :
299             # - check up or down
300             # - ssh publickey auth
301              
302             # machinesfile => $machinesfile , hostsdown => \%hostsdown , hostsup =>\%hostsup
303             sub checkHosts{
304 0     0 1 0 my %params=@_;
305 0         0 env_Init();
306 0         0 my $hosts;
307 0 0       0 my $hostsfile=(defined $params{machinesfile})? $params{machinesfile}:$env{conf}{mpd}{hostsfile};
308 0         0 my $cmdssh;
309             my %hostsdown;
310 0         0 my %hostsup;
311              
312 0 0 0     0 if (defined $hostsfile && -e $hostsfile ){
313 0 0       0 print "DEBUG: checkHosts -> $hostsfile\n" if ($Parallel::Mpich::MPD::Common::DEBUG == 1);
314 0         0 $hosts=io($hostsfile)->slurp;
315 0         0 my $res;
316 0         0 foreach (split/\n/, $hosts){
317 0 0       0 next unless /\S/;
318 0 0       0 next if /#.*$/;
319 0         0 $cmdssh="LANG=POSIX ping -fq -c 1 -i200ms $_ &>/dev/null && ssh -o PasswordAuthentication=no -o StrictHostKeyChecking=no $_ exit 33 &>/dev/null";
320 0         0 $res=int( system("$cmdssh") / 256);
321 0 0       0 print "INFO: sheck host on $_ \treturn :$res (33 for ok)\n" if $DEBUG==1;
322 0 0       0 print $cmdssh."\n\treturn:$res\n" if ($Parallel::Mpich::MPD::Common::DEBUG == 1);
323            
324 0 0       0 if ("$res" eq "1" ){
325 0 0       0 print "WARNING: Connection refused on host: $_\n" if ($Parallel::Mpich::MPD::Common::WARN == 1);
326 0         0 $hostsdown{$_}=1;
327 0         0 next;
328             }
329            
330             #ssh errors == 255
331 0 0       0 if ("$res" eq "255" ){
332 0 0       0 print "WARNING: authentication method publickey is not working on host: $_\n" if ($Parallel::Mpich::MPD::Common::WARN == 1);
333 0         0 $hostsdown{$_}=1;
334 0         0 next;
335             }
336             #ssh publickey connexion ok == 33
337 0 0       0 $hostsup{$_}=1 if ("$res" eq "33" );
338            
339             }
340            
341 0 0       0 %{$params{hostsup}} = %hostsup if (defined $params{hostsup} );
  0         0  
342 0 0       0 if (defined( keys %hostsdown)){
343 0 0       0 %{$params{hostsdown}}=%hostsdown if defined $params{hostsdown};
  0         0  
344 0         0 return %hostsup=();
345             }
346 0 0       0 print "INFO: authentication method publickey is working on all hosts." if ($Parallel::Mpich::MPD::Common::WARN == 1);
347 0         0 return %hostsup;
348             }
349 0         0 print STDERR "ERROR: mpd hostsfile is not configured \n";
350 0         0 return %hostsup=();
351             }
352              
353              
354             sub cleanTemp{
355 1     1 1 16304 my $tmp=File::Spec->tmpdir;
356 1 50       26 die "ERROR:cleanTemp: tmp directory is not defined!" unless defined ($tmp);
357 1         9 my $cmd="rm -rf $tmp/$TMP_MPD_PREFIX-*";
358 1         13803 return system($cmd)==0;
359             }
360              
361             #
362             #{
363             # cmd => $cmd, spawn => undef? , stdout => \$stdout, stderr => <$stderr, pid => \$pid
364             #}
365             sub __exec{
366 20     20   232610 my %params=@_;
367 20         1891 my $fout = new File::Temp(UNLINK=>1, TEMPLATE => File::Spec->tmpdir."/$TMP_MPD_PREFIX-sout-XXXX");
368 20         19115 my $ferr = new File::Temp(UNLINK=>1, TEMPLATE => File::Spec->tmpdir."/$TMP_MPD_PREFIX-serr-XXXX");
369 20         12223 my $ret="";
370 20 100       143 my $end= ($params{spawn})? "
371 20 100 100     440 my $_out=(! $params{spawn} && defined($params{stdout}) )? " 1>".$fout->filename:"";
372 20 100 100     236 my $_err=(! $params{spawn} && defined($params{stderr}) )? " 2>".$ferr->filename:"";
373 20         50898 my $p = fork();
374 20 100       1362 if ($p == 0) {
375              
376 5 50 33     1196 print STDERR "DEBUG: ".__PACKAGE__."::__exec($params{cmd} ".$_out . $_err .$end.")\n" if ($DEBUG==1) or $params{verbose};
377 5 0       0 exec($params{cmd} .$_out . $_err .$end) || return 1;
378             } else {
379 15 100       219 ${$params{pid}}=$p if (defined($params{pid}));
  1         154  
380 15 100       118 if ($params{spawn}){
381 2         326 return 0;
382             }
383 13         14885100 waitpid($p, 0);
384 13         411 my $exitval=$?/256;
385 13 50       109 print STDERR __PACKAGE__."(".__LINE__.")exitval=[$exitval][$?]\n" if ($DEBUG==1);
386 13 100       85 if (defined($params{stdout})){
387 1         53 ${$params{stdout}}=io($fout->filename)->slurp;
  1         5155  
388             }
389 13 100       130 if (defined($params{stderr})){
390 4         185 ${$params{stderr}}=io($ferr->filename)->slurp ;
  4         5714  
391             }
392 13         550 $ret=$exitval;
393             }
394 13         604 return $ret;
395             }
396              
397              
398             # __exec($cmd,$stdout,$stderr) return exit code
399             # sub __exec_old{
400             # my ($cmd,$stdout,$stderr, $pid)=@_;
401             # my $fout = new File::Temp(UNLINK=>1);
402             # my $ferr = new File::Temp(UNLINK=>1);
403             # my $ret=system("$cmd 1>".$fout->filename." 2>".$ferr->filename) >> 8;
404             # io($fout->filename) > $$stdout;
405             # io($ferr->filename) > $$stderr;
406             # return $ret;
407             # }
408              
409              
410              
411 7     7   22818 END { } # module clean-up code here (global destructor)
412              
413             1;
414              
415             __END__