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