Salome HOME
Adding a new specific parameter for LoadLeveler
[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_Date.hxx>
28 #include <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 == "ccc")
302   {
303     INFOS("test_jobsubmit_simple not yet implemented for ccc... return OK");
304     result = "OK";
305     return result;
306   }
307   if (batch_type == "sge")
308   {
309     INFOS("test_jobsubmit_simple not yet implemented for sge... return OK");
310     result = "OK";
311     return result;
312   }
313   if (batch_type != "pbs")
314   {
315     result += "Batch type unknown ! : " + batch_type;
316     return result;
317   }
318
319   // Getting home directory
320   std::string rst = get_home(&home);
321   if(rst != "") {
322     result += rst;
323     return result;
324   }
325
326   // PBS test
327   std::string _test_file_simple = _test_filename + "_simple";
328   std::ofstream file;
329   file.open(_test_file_simple.c_str(), std::ofstream::out);
330   file << "#!/bin/bash\n"
331        << "#PBS -l nodes=1\n"
332        << "#PBS -l walltime=00:01:00\n"
333        << "#PBS -o " + home + "/" + _date + "_simple_output.log\n"
334        << "#PBS -e " + home + "/" + _date + "_simple_error.log\n"
335        << "echo Bonjour\n"
336        << "echo Error >&2\n";
337   file.flush();
338   file.close();
339
340
341   // Build command for copy
342   command = "scp";
343   if(protocol == "rsh")
344     command = "rcp";
345   command += " " + _test_file_simple + " "
346           + username + "@" + hostname + ":" + home;
347   status = system(command.c_str());
348   if(status) {
349     std::ostringstream oss;
350     oss << status;
351     result += "Error in copy job file to remote host ! status = ";
352     result += oss.str();
353     return result;
354   }
355
356   // Build command for submit job
357   std::string file_job_name = _test_filename + "_jobid";
358   command = protocol + " " + username + "@" + hostname + " qsub " + _base_filename + "_simple > " + file_job_name;
359   status = system(command.c_str());
360   if(status) {
361     std::ostringstream oss;
362     oss << status;
363     result += "Error in sending qsub to remote host ! status = ";
364     result += oss.str();
365     return result;
366   }
367   std::string jobid;
368   std::ifstream file_job(file_job_name.c_str());
369   if (!file_job)
370   {
371     result += "Error in reading temporary file ! filename = " + file_job_name;
372     return result;
373   }
374   std::getline(file_job, jobid);
375   file_job.close();
376  
377   // Wait the end of the job
378   command = protocol + " " + username + "@" + hostname + " qstat -f " + jobid + " > " + file_job_name;
379   bool stop = false;
380   while (!stop) 
381   {
382     status = system(command.c_str());
383     if(status && status != 153 && status != 256*153)
384     {
385       std::ostringstream oss;
386       oss << status;
387       result += "Error in sending qstat to remote host ! status = ";
388       result += oss.str();
389       return result;
390     }
391
392     if(status == 153 || status == 256*153 )
393       stop = true;
394 #ifdef WIN32
395     Sleep(1);
396 #else
397     sleep(1);
398 #endif
399   }
400
401   // Build command for getting results
402   command = "scp";
403   if(protocol == "rsh")
404     command = "rcp";
405   command += " " 
406           + username + "@" + hostname + ":" + home + "/" + _date + "_simple* /tmp";
407   status = system(command.c_str());
408   if(status) {
409     std::ostringstream oss;
410     oss << status;
411     result += "error in getting file result of qsub simple to remote host ! status = ";
412     result += oss.str();
413     return result;
414   }
415   
416   // Test results
417   std::string normal_input;
418   std::string file_normal_name = "/tmp/" + _date + "_simple_output.log";
419   std::ifstream file_normal(file_normal_name.c_str());
420   if (!file_normal)
421   {
422     result += "Error in reading temporary file ! filename = " + file_normal_name;
423     return result;
424   }
425   std::getline(file_normal, normal_input);
426   file_normal.close();
427   if (normal_input != "Bonjour")
428   {
429     result += "error from simple ouput file ! waiting for Bonjour and get : " + normal_input;
430     return result;
431   }
432   std::string error_input;
433   std::string file_error_name = "/tmp/" + _date + "_simple_error.log";
434   std::ifstream file_error(file_error_name.c_str());
435   if (!file_error)
436   {
437     result += "Error in reading temporary file ! filename = " + file_error_name;
438     return result;
439   }
440   std::getline(file_error, error_input);
441   file_error.close();
442   if (error_input != "Error")
443   {
444     result += "error from simple error file ! waiting for Error and get : " + error_input;
445     return result;
446   }
447   result = "OK";
448   return result;
449 }
450
451 std::string 
452 BatchTest::test_jobsubmit_mpi() 
453 {
454 #ifdef WITH_LIBBATCH
455   int status;
456   std::string home;
457   std::string command;
458   MpiImpl * mpiImpl;
459   std::string result("Failed : ");
460   std::string hostname = _batch_descr.hostname.in();
461   std::string username = _batch_descr.username.in();
462   std::string protocol = _batch_descr.protocol.in();
463   std::string batch_type = _batch_descr.batch.in();
464   std::string mpi_type = _batch_descr.mpiImpl.in();
465
466   // Basic test
467   if(mpi_type == "lam")
468     mpiImpl = new MpiImpl_LAM();
469   else if(mpi_type == "mpich1")
470     mpiImpl = new MpiImpl_MPICH1();
471   else if(mpi_type == "mpich2")
472     mpiImpl = new MpiImpl_MPICH2();
473   else if(mpi_type == "openmpi")
474     mpiImpl = new MpiImpl_OPENMPI();
475   else if(mpi_type == "slurm")
476     mpiImpl = new MpiImpl_SLURM();
477   else
478   {
479     result += "Error MPI impl not supported : " + mpi_type;
480     return result;
481   }
482
483   // LSF et SGE not yet implemented...
484   if (batch_type == "lsf")
485   {
486     INFOS("test_jobsubmit_simple not yet implemented for lsf... return OK");
487     result = "OK";
488     return result;
489   }
490
491   if (batch_type == "ccc")
492   {
493     INFOS("test_jobsubmit_simple not yet implemented for ccc... return OK");
494     result = "OK";
495     return result;
496   }
497
498   if (batch_type == "sge")
499   {
500     INFOS("test_jobsubmit_simple not yet implemented for sge... return OK");
501     result = "OK";
502     return result;
503   }
504
505   // Getting home directory
506   std::string rst = get_home(&home);
507   if(rst != "") {
508     result += rst;
509     return result;
510   }
511
512   // MPI test
513   std::string _test_file_script = _test_filename + "_script";
514   std::ofstream file_script;
515   file_script.open(_test_file_script.c_str(), std::ofstream::out);
516   file_script << "#!/bin/bash\n"
517               << "echo HELLO MPI\n";
518   file_script.flush();
519   file_script.close();
520 #ifdef WIN32
521   _chmod
522 #else
523   chmod
524 #endif
525     (_test_file_script.c_str(), 0x1ED);
526
527   std::string _test_file_mpi = _test_filename + "_mpi";
528   std::ofstream file_mpi;
529   file_mpi.open(_test_file_mpi.c_str(), std::ofstream::out);
530   file_mpi << "#!/bin/bash\n"
531            << "#PBS -l nodes=1\n"
532            << "#PBS -l walltime=00:01:00\n"
533            << "#PBS -o " << home << "/" << _date << "_mpi_output.log\n"
534            << "#PBS -e " << home << "/" << _date << "_mpi_error.log\n"
535            << mpiImpl->boot("${PBS_NODEFILE}", 1)
536            << mpiImpl->run("${PBS_NODEFILE}", 1, _base_filename + "_script")
537            << mpiImpl->halt();
538   file_mpi.flush();
539   file_mpi.close();
540
541
542   // Build command for copy
543   command = "scp";
544   if(protocol == "rsh")
545     command = "rcp";
546   command += " " + _test_file_script + " "
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   command = "scp";
557   if(protocol == "rsh")
558     command = "rcp";
559   command += " " + _test_file_mpi + " "
560           + username + "@" + hostname + ":" + home;
561   status = system(command.c_str());
562   if(status) {
563     std::ostringstream oss;
564     oss << status;
565     result += "Error in copy job file to remote host ! status = ";
566     result += oss.str();
567     return result;
568   }
569
570   // Build command for submit job
571   std::string file_job_name = _test_filename + "_jobid";
572   command = protocol + " " + username + "@" + hostname + " qsub " + _base_filename + "_mpi > " + file_job_name;
573   status = system(command.c_str());
574   if(status) {
575     std::ostringstream oss;
576     oss << status;
577     result += "Error in sending qsub to remote host ! status = ";
578     result += oss.str();
579     return result;
580   }
581   std::string jobid;
582   std::ifstream file_job(file_job_name.c_str());
583   if (!file_job)
584   {
585     result += "Error in reading temporary file ! filename = " + file_job_name;
586     return result;
587   }
588   std::getline(file_job, jobid);
589   file_job.close();
590  
591   // Wait the end of the job
592   command = protocol + " " + username + "@" + hostname + " qstat -f " + jobid + " > " + file_job_name;
593   bool stop = false;
594   while (!stop) 
595   {
596     status = system(command.c_str());
597     if(status && status != 153 && status != 256*153)
598     {
599       std::ostringstream oss;
600       oss << status;
601       result += "Error in sending qstat to remote host ! status = ";
602       result += oss.str();
603       return result;
604     }
605
606     if(status == 153 || status == 256*153 )
607       stop = true;
608 #ifdef WIN32
609     Sleep(1);
610 #else
611     sleep(1);
612 #endif
613   }
614
615   // Build command for getting results
616   command = "scp";
617   if(protocol == "rsh")
618     command = "rcp";
619   command += " " 
620           + username + "@" + hostname + ":" + home + "/" + _date + "_mpi* /tmp";
621   status = system(command.c_str());
622   if(status) {
623     std::ostringstream oss;
624     oss << status;
625     result += "error in getting file result of qsub mpi from remote host ! status = ";
626     result += oss.str();
627     return result;
628   }
629   
630   // Test results
631   std::string normal_input;
632   std::string file_normal_name = "/tmp/" + _date + "_mpi_output.log";
633   std::ifstream file_normal(file_normal_name.c_str());
634   if (!file_normal)
635   {
636     result += "Error in reading temporary file ! filename = " + file_normal_name;
637     return result;
638   }
639   bool test_ok = false;
640   while (std::getline(file_normal, normal_input))
641   {
642     if (normal_input == "HELLO MPI")
643       test_ok = true;
644   }
645   file_normal.close();
646   if (!test_ok)
647   {
648     result += "error from mpi ouput file ! waiting for HELLO MPI please watch /tmp/" + _date + "_mpi_output.log file";
649     return result;
650   }
651   result = "OK";
652   return result;  
653 #else
654   throw LauncherException("Method BatchTest::test_jobsubmit_mpi is not available "
655                           "(libBatch was not present at compilation time)");
656 #endif
657 }
658
659 std::string 
660 BatchTest::test_appli()
661 {
662   int status;
663   std::string home;
664   std::string command;
665   std::string result("Failed : ");
666   std::string hostname = _batch_descr.hostname.in();
667   std::string username = _batch_descr.username.in();
668   std::string protocol = _batch_descr.protocol.in();
669   std::string applipath = _batch_descr.applipath.in();
670   
671   // Getting home directory
672   std::string rst = get_home(&home);
673   if(rst != "") {
674     result += rst;
675     return result;
676   }
677
678   std::string _test_file_appli = _test_filename + "_appli_test";
679   std::ofstream file_appli;
680   file_appli.open(_test_file_appli.c_str(), std::ofstream::out);
681   file_appli << "#!/bin/bash\n"
682              << "if [ -f " << applipath << "/runAppli ]\n"
683              << "then\n"
684              << "  echo OK\n"
685              << "else\n"
686              << "  echo NOK\n"
687              << "fi\n";
688   file_appli.flush();
689   file_appli.close();
690
691   // Build command for copy
692   command = "scp";
693   if(protocol == "rsh")
694     command = "rcp";
695   command += " " + _test_file_appli + " "
696           + username + "@" + hostname + ":" + home;
697   status = system(command.c_str());
698   if(status) {
699     std::ostringstream oss;
700     oss << status;
701     result += "Error in copy appli test file to remote host ! status = ";
702     result += oss.str();
703     return result;
704   }
705
706   // Launch test
707   command = protocol + " " + username + "@" + hostname 
708           + " sh " + home + "/" + _base_filename + "_appli_test > " 
709           + _test_filename + "_appli_test_result";
710
711   status = system(command.c_str());
712   if(status) {
713     std::ostringstream oss;
714     oss << status;
715     result += "Error in launching appli test on remote host ! status = ";
716     result += oss.str();
717     return result;
718   }
719
720   // Read test result
721   std::string rst_appli;
722   std::string file_appli_result_name = _test_filename + "_appli_test_result";
723   std::ifstream file_appli_result(file_appli_result_name.c_str());
724   if (!file_appli_result)
725   {
726     result += "Error in reading temporary file ! filename = " + file_appli_result_name;
727     return result;
728   }
729   std::getline(file_appli_result, rst_appli);
730   file_appli_result.close();
731   
732   if (rst_appli != "OK")
733   {
734     result += "Error checking application on remote host ! result = " + rst;
735     return result;
736   }
737
738   result = "OK";
739   return result;
740 }
741
742 // Useful methods
743 std::string
744 BatchTest::get_home(std::string * home)
745 {
746   int status;
747   std::string result = "";
748   std::string command;
749   std::string hostname = _batch_descr.hostname.in();
750   std::string username = _batch_descr.username.in();
751   std::string protocol = _batch_descr.protocol.in();
752   std::string file_home_name = _test_filename + "_home";
753
754   command = protocol + " " + username + "@" + hostname + " 'echo $HOME' > " + file_home_name; 
755   status = system(command.c_str());
756   if(status) {
757     std::ostringstream oss;
758     oss << status;
759     result += "Error in getting home directory ! status = ";
760     result += oss.str();
761     return result;
762   }
763
764   std::ifstream file_home(file_home_name.c_str());
765   if (!file_home)
766   {
767     result += "Error in reading temporary file ! filename = " + file_home_name;
768     return result;
769   }
770   std::getline(file_home, *home);
771   file_home.close();
772   return result;
773 }