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