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