Salome HOME
merge from branch BR_V511_PR 15 12 2009
[modules/kernel.git] / src / Launcher / BatchTest.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 #include "BatchTest.hxx"
23 #include "Launcher.hxx"
24
25 #ifdef WITH_LIBBATCH
26 #include <Batch/Batch_Date.hxx>
27 #include <Batch/Batch_MpiImpl.hxx>
28 #endif
29
30 #include "utilities.h"
31
32 #include <sys/stat.h>
33 #include <iostream>
34 #include <fstream>
35 #ifdef WIN32
36 # include <io.h>
37 #endif
38 BatchTest::BatchTest(const Engines::ResourceDefinition& batch_descr) 
39 {
40 #ifdef WITH_LIBBATCH
41   _batch_descr = batch_descr;
42
43   // Getting date
44   Batch::Date date = Batch::Date(time(0));
45   _date = date.str();
46   int lend = _date.size() ;
47   int i = 0 ;
48   while (i < lend) 
49   {
50     if (_date[i] == '/' || _date[i] == '-' || _date[i] == ':' ) 
51     {
52       _date[i] = '_' ;
53     }
54     i++ ;
55   }
56   
57   // Creating test temporary file
58   _test_filename =  "/tmp/";
59   _test_filename +=  _date + "_test_cluster_file_";
60   _test_filename += _batch_descr.hostname.in();
61   _base_filename = _date + "_test_cluster_file_" + _batch_descr.hostname.in();
62 #endif
63 }
64
65 BatchTest::~BatchTest() {}
66
67 bool
68 BatchTest::test()
69 {
70   bool rtn = false;
71   INFOS(std::endl 
72         << "--- Testing batch Machine :" << std::endl
73         << "--- Name       : " << _batch_descr.hostname << std::endl
74         << "--- hostname      : " << _batch_descr.hostname << std::endl
75         << "--- Protocol   : " << _batch_descr.protocol << std::endl
76         << "--- User Name  : " << _batch_descr.username << std::endl
77         << "--- Batch Type : " << _batch_descr.batch << std::endl
78         << "--- MPI Impl   : " << _batch_descr.mpiImpl << std::endl
79         << "--- Appli Path : " << _batch_descr.applipath << std::endl
80        );
81
82   std::string result_connection("Not Tested");
83   std::string result_filecopy("Not Tested");
84   std::string result_getresult("Not Tested");
85   std::string result_jobsubmit_simple("Not Tested");
86   std::string result_jobsubmit_mpi("Not Tested");
87   std::string result_appli("Not Tested");
88
89   result_connection = test_connection();
90   result_filecopy = test_filecopy();
91   result_getresult = test_getresult();
92   result_jobsubmit_simple = test_jobsubmit_simple();
93   result_jobsubmit_mpi = test_jobsubmit_mpi();
94   result_appli = test_appli();
95
96   INFOS(std::endl
97         << "--- Test results" << std::endl
98         << "--- Connection          : " << result_connection << std::endl
99         << "--- File copy           : " << result_filecopy << std::endl
100         << "--- Get results         : " << result_getresult << std::endl
101         << "--- Submit simple job   : " << result_jobsubmit_simple << std::endl
102         << "--- Submit mpi job      : " << result_jobsubmit_mpi << std::endl
103         << "--- Application         : " << result_appli << std::endl
104        );
105   
106   if (result_connection == "OK"       && 
107       result_filecopy == "OK"         &&
108       result_getresult == "OK"        &&
109       result_jobsubmit_simple == "OK" &&
110       result_jobsubmit_mpi == "OK"    &&
111       result_appli == "OK")
112     rtn = true;
113       
114   return rtn;
115 }
116
117 // For this test we use : hostname, protocol, username
118 std::string
119 BatchTest::test_connection()
120 {
121   int status;
122   std::string command;
123   std::string result("Failed : ");
124   std::string hostname = _batch_descr.hostname.in();
125   std::string username = _batch_descr.username.in();
126   std::string protocol = _batch_descr.protocol.in();
127
128   // Basic tests
129   if(hostname == "")
130   {
131     result += "hostname is empty !";
132     return result;
133   }
134   if(username == "")
135   {
136     result += "username is empty !";
137     return result;
138   }
139   if( protocol != "rsh" && protocol != "ssh")
140   {
141     result += "protocol unknown ! (" + protocol + ")";
142     return result;
143   }
144
145   // Build command
146   command += protocol
147           + " "
148           + username + "@" + hostname;
149
150   // Test
151   status = system(command.c_str());
152   if(status) {
153     std::ostringstream oss;
154     oss << status;
155     result += "Error of connection on remote host ! status = ";
156     result += oss.str();
157     return result;
158   }
159
160   result = "OK";
161   return result;
162 }
163
164 // For this test we use : hostname, protocol, username
165 std::string
166 BatchTest::test_filecopy()
167 {
168   int status;
169   std::string home;
170   std::string command;
171   std::string result("Failed : ");
172   std::string hostname = _batch_descr.hostname.in();
173   std::string username = _batch_descr.username.in();
174   std::string protocol = _batch_descr.protocol.in();
175
176   // Getting home directory
177   std::string rst = get_home(&home);
178   if(rst != "") {
179     result += rst;
180     return result;
181   }
182
183   // Writing into the tempory file
184   command = "echo Hello > " +  _test_filename;
185   status = system(command.c_str());
186   if(status) {
187     std::ostringstream oss;
188     oss << status;
189     result += "Error in creating tempory file ! status = ";
190     result += oss.str();
191     return result;
192   }
193
194   // Build command
195   command = "scp";
196   if(protocol == "rsh")
197     command = "rcp";
198   command += " " + _test_filename + " "
199           + username + "@" + hostname + ":" + home;
200
201   // Test
202   status = system(command.c_str());
203   if(status) {
204     std::ostringstream oss;
205     oss << status;
206     result += "Error in copy file on remote host ! status = ";
207     result += oss.str();
208     return result;
209   }
210
211   result = "OK";
212   return result;
213 }
214
215 // For this test we use : hostname, protocol, username
216 std::string
217 BatchTest::test_getresult()
218 {
219   int status;
220   std::string home;
221   std::string command;
222   std::string result("Failed : ");
223   std::string hostname = _batch_descr.hostname.in();
224   std::string username = _batch_descr.username.in();
225   std::string protocol = _batch_descr.protocol.in();
226
227   // Getting home directory
228   std::string rst = get_home(&home);
229   if(rst != "") {
230     result += rst;
231     return result;
232   }
233
234   // Build command
235   command = "scp";
236   if(protocol == "rsh")
237     command = "rcp";
238   command += " " + username + "@" + hostname + ":" + home 
239           + "/" + _base_filename + " " + _test_filename + "_copy";
240
241   // Test
242   status = system(command.c_str());
243   if(status) {
244     std::ostringstream oss;
245     oss << status;
246     result += "Error in copy file from remote host ! status = ";
247     result += oss.str();
248     return result;
249   }
250   
251   // Compare files
252   std::ifstream src_file(_test_filename.c_str());
253   if (!src_file)
254   {
255     result += "Error in reading temporary file ! filename = " + _test_filename;
256     return result;
257   }
258   std::string cp_filename = _test_filename + "_copy";
259   std::ifstream cp_file(cp_filename.c_str());
260   if (!cp_file)
261   {
262     result += "Error in reading temporary copy file ! filename = " + cp_filename;
263     return result;
264   }
265   std::string src_firstline;
266   std::string cp_firstline;
267   std::getline(src_file, src_firstline);
268   std::getline(cp_file, cp_firstline);
269   src_file.close();
270   cp_file.close();
271   if (src_firstline != cp_firstline)
272   {
273     result += "Error source file and copy file are not equa ! source = " + src_firstline + " copy = " + cp_firstline;
274     return result;
275   }
276
277   result = "OK";
278   return result;
279 }
280
281 std::string 
282 BatchTest::test_jobsubmit_simple() 
283 {
284   int status;
285   std::string home;
286   std::string command;
287   std::string result("Failed : ");
288   std::string hostname = _batch_descr.hostname.in();
289   std::string username = _batch_descr.username.in();
290   std::string protocol = _batch_descr.protocol.in();
291   std::string batch_type = _batch_descr.batch.in();
292
293   // Basic test
294   if (batch_type == "lsf")
295   {
296     INFOS("test_jobsubmit_simple not yet implemented for lsf... return OK");
297     result = "OK";
298     return result;
299   }
300   if (batch_type == "sge")
301   {
302     INFOS("test_jobsubmit_simple not yet implemented for sge... return OK");
303     result = "OK";
304     return result;
305   }
306   if (batch_type != "pbs")
307   {
308     result += "Batch type unknown ! : " + batch_type;
309     return result;
310   }
311
312   // Getting home directory
313   std::string rst = get_home(&home);
314   if(rst != "") {
315     result += rst;
316     return result;
317   }
318
319   // PBS test
320   std::string _test_file_simple = _test_filename + "_simple";
321   std::ofstream file;
322   file.open(_test_file_simple.c_str(), std::ofstream::out);
323   file << "#!/bin/bash\n"
324        << "#PBS -l nodes=1\n"
325        << "#PBS -l walltime=00:01:00\n"
326        << "#PBS -o " + home + "/" + _date + "_simple_output.log\n"
327        << "#PBS -e " + home + "/" + _date + "_simple_error.log\n"
328        << "echo Bonjour\n"
329        << "echo Error >&2\n";
330   file.flush();
331   file.close();
332
333
334   // Build command for copy
335   command = "scp";
336   if(protocol == "rsh")
337     command = "rcp";
338   command += " " + _test_file_simple + " "
339           + username + "@" + hostname + ":" + home;
340   status = system(command.c_str());
341   if(status) {
342     std::ostringstream oss;
343     oss << status;
344     result += "Error in copy job file to remote host ! status = ";
345     result += oss.str();
346     return result;
347   }
348
349   // Build command for submit job
350   std::string file_job_name = _test_filename + "_jobid";
351   command = protocol + " " + username + "@" + hostname + " qsub " + _base_filename + "_simple > " + file_job_name;
352   status = system(command.c_str());
353   if(status) {
354     std::ostringstream oss;
355     oss << status;
356     result += "Error in sending qsub to remote host ! status = ";
357     result += oss.str();
358     return result;
359   }
360   std::string jobid;
361   std::ifstream file_job(file_job_name.c_str());
362   if (!file_job)
363   {
364     result += "Error in reading temporary file ! filename = " + file_job_name;
365     return result;
366   }
367   std::getline(file_job, jobid);
368   file_job.close();
369  
370   // Wait the end of the job
371   command = protocol + " " + username + "@" + hostname + " qstat -f " + jobid + " > " + file_job_name;
372   bool stop = false;
373   while (!stop) 
374   {
375     status = system(command.c_str());
376     if(status && status != 153 && status != 256*153)
377     {
378       std::ostringstream oss;
379       oss << status;
380       result += "Error in sending qstat to remote host ! status = ";
381       result += oss.str();
382       return result;
383     }
384
385     if(status == 153 || status == 256*153 )
386       stop = true;
387 #ifdef WIN32
388     Sleep(1);
389 #else
390     sleep(1);
391 #endif
392   }
393
394   // Build command for getting results
395   command = "scp";
396   if(protocol == "rsh")
397     command = "rcp";
398   command += " " 
399           + username + "@" + hostname + ":" + home + "/" + _date + "_simple* /tmp";
400   status = system(command.c_str());
401   if(status) {
402     std::ostringstream oss;
403     oss << status;
404     result += "error in getting file result of qsub simple to remote host ! status = ";
405     result += oss.str();
406     return result;
407   }
408   
409   // Test results
410   std::string normal_input;
411   std::string file_normal_name = "/tmp/" + _date + "_simple_output.log";
412   std::ifstream file_normal(file_normal_name.c_str());
413   if (!file_normal)
414   {
415     result += "Error in reading temporary file ! filename = " + file_normal_name;
416     return result;
417   }
418   std::getline(file_normal, normal_input);
419   file_normal.close();
420   if (normal_input != "Bonjour")
421   {
422     result += "error from simple ouput file ! waiting for Bonjour and get : " + normal_input;
423     return result;
424   }
425   std::string error_input;
426   std::string file_error_name = "/tmp/" + _date + "_simple_error.log";
427   std::ifstream file_error(file_error_name.c_str());
428   if (!file_error)
429   {
430     result += "Error in reading temporary file ! filename = " + file_error_name;
431     return result;
432   }
433   std::getline(file_error, error_input);
434   file_error.close();
435   if (error_input != "Error")
436   {
437     result += "error from simple error file ! waiting for Error and get : " + error_input;
438     return result;
439   }
440   result = "OK";
441   return result;
442 }
443
444 std::string 
445 BatchTest::test_jobsubmit_mpi() 
446 {
447 #ifdef WITH_LIBBATCH
448   int status;
449   std::string home;
450   std::string command;
451   MpiImpl * mpiImpl;
452   std::string result("Failed : ");
453   std::string hostname = _batch_descr.hostname.in();
454   std::string username = _batch_descr.username.in();
455   std::string protocol = _batch_descr.protocol.in();
456   std::string batch_type = _batch_descr.batch.in();
457   std::string mpi_type = _batch_descr.mpiImpl.in();
458
459   // Basic test
460   if(mpi_type == "lam")
461     mpiImpl = new MpiImpl_LAM();
462   else if(mpi_type == "mpich1")
463     mpiImpl = new MpiImpl_MPICH1();
464   else if(mpi_type == "mpich2")
465     mpiImpl = new MpiImpl_MPICH2();
466   else if(mpi_type == "openmpi")
467     mpiImpl = new MpiImpl_OPENMPI();
468   else if(mpi_type == "slurm")
469     mpiImpl = new MpiImpl_SLURM();
470   else
471   {
472     result += "Error MPI impl not supported : " + mpi_type;
473     return result;
474   }
475
476   // LSF et SGE not yet implemented...
477   if (batch_type == "lsf")
478   {
479     INFOS("test_jobsubmit_simple not yet implemented for lsf... return OK");
480     result = "OK";
481     return result;
482   }
483
484   if (batch_type == "sge")
485   {
486     INFOS("test_jobsubmit_simple not yet implemented for sge... return OK");
487     result = "OK";
488     return result;
489   }
490
491   // Getting home directory
492   std::string rst = get_home(&home);
493   if(rst != "") {
494     result += rst;
495     return result;
496   }
497
498   // MPI test
499   std::string _test_file_script = _test_filename + "_script";
500   std::ofstream file_script;
501   file_script.open(_test_file_script.c_str(), std::ofstream::out);
502   file_script << "#!/bin/bash\n"
503               << "echo HELLO MPI\n";
504   file_script.flush();
505   file_script.close();
506 #ifdef WIN32
507   _chmod
508 #else
509   chmod
510 #endif
511     (_test_file_script.c_str(), 0x1ED);
512
513   std::string _test_file_mpi = _test_filename + "_mpi";
514   std::ofstream file_mpi;
515   file_mpi.open(_test_file_mpi.c_str(), std::ofstream::out);
516   file_mpi << "#!/bin/bash\n"
517            << "#PBS -l nodes=1\n"
518            << "#PBS -l walltime=00:01:00\n"
519            << "#PBS -o " << home << "/" << _date << "_mpi_output.log\n"
520            << "#PBS -e " << home << "/" << _date << "_mpi_error.log\n"
521            << mpiImpl->boot("${PBS_NODEFILE}", 1)
522            << mpiImpl->run("${PBS_NODEFILE}", 1, _base_filename + "_script")
523            << mpiImpl->halt();
524   file_mpi.flush();
525   file_mpi.close();
526
527
528   // Build command for copy
529   command = "scp";
530   if(protocol == "rsh")
531     command = "rcp";
532   command += " " + _test_file_script + " "
533           + username + "@" + hostname + ":" + home;
534   status = system(command.c_str());
535   if(status) {
536     std::ostringstream oss;
537     oss << status;
538     result += "Error in copy job file to remote host ! status = ";
539     result += oss.str();
540     return result;
541   }
542   command = "scp";
543   if(protocol == "rsh")
544     command = "rcp";
545   command += " " + _test_file_mpi + " "
546           + username + "@" + hostname + ":" + home;
547   status = system(command.c_str());
548   if(status) {
549     std::ostringstream oss;
550     oss << status;
551     result += "Error in copy job file to remote host ! status = ";
552     result += oss.str();
553     return result;
554   }
555
556   // Build command for submit job
557   std::string file_job_name = _test_filename + "_jobid";
558   command = protocol + " " + username + "@" + hostname + " qsub " + _base_filename + "_mpi > " + file_job_name;
559   status = system(command.c_str());
560   if(status) {
561     std::ostringstream oss;
562     oss << status;
563     result += "Error in sending qsub to remote host ! status = ";
564     result += oss.str();
565     return result;
566   }
567   std::string jobid;
568   std::ifstream file_job(file_job_name.c_str());
569   if (!file_job)
570   {
571     result += "Error in reading temporary file ! filename = " + file_job_name;
572     return result;
573   }
574   std::getline(file_job, jobid);
575   file_job.close();
576  
577   // Wait the end of the job
578   command = protocol + " " + username + "@" + hostname + " qstat -f " + jobid + " > " + file_job_name;
579   bool stop = false;
580   while (!stop) 
581   {
582     status = system(command.c_str());
583     if(status && status != 153 && status != 256*153)
584     {
585       std::ostringstream oss;
586       oss << status;
587       result += "Error in sending qstat to remote host ! status = ";
588       result += oss.str();
589       return result;
590     }
591
592     if(status == 153 || status == 256*153 )
593       stop = true;
594 #ifdef WIN32
595     Sleep(1);
596 #else
597     sleep(1);
598 #endif
599   }
600
601   // Build command for getting results
602   command = "scp";
603   if(protocol == "rsh")
604     command = "rcp";
605   command += " " 
606           + username + "@" + hostname + ":" + home + "/" + _date + "_mpi* /tmp";
607   status = system(command.c_str());
608   if(status) {
609     std::ostringstream oss;
610     oss << status;
611     result += "error in getting file result of qsub mpi from remote host ! status = ";
612     result += oss.str();
613     return result;
614   }
615   
616   // Test results
617   std::string normal_input;
618   std::string file_normal_name = "/tmp/" + _date + "_mpi_output.log";
619   std::ifstream file_normal(file_normal_name.c_str());
620   if (!file_normal)
621   {
622     result += "Error in reading temporary file ! filename = " + file_normal_name;
623     return result;
624   }
625   bool test_ok = false;
626   while (std::getline(file_normal, normal_input))
627   {
628     if (normal_input == "HELLO MPI")
629       test_ok = true;
630   }
631   file_normal.close();
632   if (!test_ok)
633   {
634     result += "error from mpi ouput file ! waiting for HELLO MPI please watch /tmp/" + _date + "_mpi_output.log file";
635     return result;
636   }
637   result = "OK";
638   return result;  
639 #else
640   throw LauncherException("Method BatchTest::test_jobsubmit_mpi is not available "
641                           "(libBatch was not present at compilation time)");
642 #endif
643 }
644
645 std::string 
646 BatchTest::test_appli()
647 {
648   int status;
649   std::string home;
650   std::string command;
651   std::string result("Failed : ");
652   std::string hostname = _batch_descr.hostname.in();
653   std::string username = _batch_descr.username.in();
654   std::string protocol = _batch_descr.protocol.in();
655   std::string applipath = _batch_descr.applipath.in();
656   
657   // Getting home directory
658   std::string rst = get_home(&home);
659   if(rst != "") {
660     result += rst;
661     return result;
662   }
663
664   std::string _test_file_appli = _test_filename + "_appli_test";
665   std::ofstream file_appli;
666   file_appli.open(_test_file_appli.c_str(), std::ofstream::out);
667   file_appli << "#!/bin/bash\n"
668              << "if [ -f " << applipath << "/runAppli ]\n"
669              << "then\n"
670              << "  echo OK\n"
671              << "else\n"
672              << "  echo NOK\n"
673              << "fi\n";
674   file_appli.flush();
675   file_appli.close();
676
677   // Build command for copy
678   command = "scp";
679   if(protocol == "rsh")
680     command = "rcp";
681   command += " " + _test_file_appli + " "
682           + username + "@" + hostname + ":" + home;
683   status = system(command.c_str());
684   if(status) {
685     std::ostringstream oss;
686     oss << status;
687     result += "Error in copy appli test file to remote host ! status = ";
688     result += oss.str();
689     return result;
690   }
691
692   // Launch test
693   command = protocol + " " + username + "@" + hostname 
694           + " sh " + home + "/" + _base_filename + "_appli_test > " 
695           + _test_filename + "_appli_test_result";
696
697   status = system(command.c_str());
698   if(status) {
699     std::ostringstream oss;
700     oss << status;
701     result += "Error in launching appli test on remote host ! status = ";
702     result += oss.str();
703     return result;
704   }
705
706   // Read test result
707   std::string rst_appli;
708   std::string file_appli_result_name = _test_filename + "_appli_test_result";
709   std::ifstream file_appli_result(file_appli_result_name.c_str());
710   if (!file_appli_result)
711   {
712     result += "Error in reading temporary file ! filename = " + file_appli_result_name;
713     return result;
714   }
715   std::getline(file_appli_result, rst_appli);
716   file_appli_result.close();
717   
718   if (rst_appli != "OK")
719   {
720     result += "Error checking application on remote host ! result = " + rst;
721     return result;
722   }
723
724   result = "OK";
725   return result;
726 }
727
728 // Useful methods
729 std::string
730 BatchTest::get_home(std::string * home)
731 {
732   int status;
733   std::string result = "";
734   std::string command;
735   std::string hostname = _batch_descr.hostname.in();
736   std::string username = _batch_descr.username.in();
737   std::string protocol = _batch_descr.protocol.in();
738   std::string file_home_name = _test_filename + "_home";
739
740   command = protocol + " " + username + "@" + hostname + " 'echo $HOME' > " + file_home_name; 
741   status = system(command.c_str());
742   if(status) {
743     std::ostringstream oss;
744     oss << status;
745     result += "Error in getting home directory ! status = ";
746     result += oss.str();
747     return result;
748   }
749
750   std::ifstream file_home(file_home_name.c_str());
751   if (!file_home)
752   {
753     result += "Error in reading temporary file ! filename = " + file_home_name;
754     return result;
755   }
756   std::getline(file_home, *home);
757   file_home.close();
758   return result;
759 }