init copied from arcsub.cpp
[gp-arc-client-c.git] / src / submit.cpp
1 /*
2  *  submit.cpp
3  *  arcclientc
4  *
5  *  Created by Tamas Jung on 4/7/10.
6  *  Copyright 2010 Interface Kft. All rights reserved.
7  *
8  */
9
10 #include "submit.h"
11 // -*- indent-tabs-mode: nil -*-
12
13 #ifdef HAVE_CONFIG_H
14 #include <config.h>
15 #endif
16
17 #include <fstream>
18 #include <iostream>
19 #include <list>
20 #include <string>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24
25 #include <arc/ArcConfig.h>
26 #include <arc/ArcLocation.h>
27 #include <arc/DateTime.h>
28 #include <arc/FileLock.h>
29 #include <arc/IString.h>
30 #include <arc/Logger.h>
31 #include <arc/OptionParser.h>
32 #include <arc/StringConv.h>
33 #include <arc/URL.h>
34 #include <arc/Utils.h>
35 #include <arc/XMLNode.h>
36 #include <arc/client/Submitter.h>
37 #include <arc/client/TargetGenerator.h>
38 #include <arc/client/JobDescription.h>
39 #include <arc/UserConfig.h>
40 #include <arc/client/Broker.h>
41
42 int main(int argc, char **argv) {
43         
44         setlocale(LC_ALL, "");
45         
46         Arc::Logger logger(Arc::Logger::getRootLogger(), "arcsub");
47         Arc::LogStream logcerr(std::cerr);
48         logcerr.setFormat(Arc::ShortFormat);
49         Arc::Logger::getRootLogger().addDestination(logcerr);
50         Arc::Logger::getRootLogger().setThreshold(Arc::WARNING);
51         
52         Arc::ArcLocation::Init(argv[0]);
53         
54         Arc::OptionParser options(istring("[filename ...]"),
55                                                           istring("The arcsub command is used for "
56                                                                           "submitting jobs to grid enabled "
57                                                                           "computing\nresources."),
58                                                           istring("Argument to -i has the format "
59                                                                           "Flavour:URL e.g.\n"
60                                                                           "ARC0:ldap://grid.tsl.uu.se:2135/"
61                                                                           "mds-vo-name=sweden,O=grid\n"
62                                                                           "CREAM:ldap://cream.grid.upjs.sk:2170/"
63                                                                           "o=grid\n"
64                                                                           "\n"
65                                                                           "Argument to -c has the format "
66                                                                           "Flavour:URL e.g.\n"
67                                                                           "ARC0:ldap://grid.tsl.uu.se:2135/"
68                                                                           "nordugrid-cluster-name=grid.tsl.uu.se,"
69                                                                           "Mds-Vo-name=local,o=grid"));
70         
71         std::list<std::string> clusters;
72         options.AddOption('c', "cluster",
73                                           istring("explicity select or reject a specific cluster"),
74                                           istring("[-]name"),
75                                           clusters);
76         
77         std::list<std::string> indexurls;
78         options.AddOption('i', "index",
79                                           istring("explicity select or reject an index server"),
80                                           istring("[-]name"),
81                                           indexurls);
82         
83         std::list<std::string> jobdescriptionstrings;
84         options.AddOption('e', "jobdescrstring",
85                                           istring("jobdescription string describing the job to "
86                                                           "be submitted"),
87                                           istring("string"),
88                                           jobdescriptionstrings);
89         
90         std::list<std::string> jobdescriptionfiles;
91         options.AddOption('f', "jobdescrfile",
92                                           istring("jobdescription file describing the job to "
93                                                           "be submitted"),
94                                           istring("string"),
95                                           jobdescriptionfiles);
96         
97         std::string joblist;
98         options.AddOption('j', "joblist",
99                                           istring("file where the jobs will be stored"),
100                                           istring("filename"),
101                                           joblist);
102         
103         /*
104      bool dryrun = false;
105      options.AddOption('D', "dryrun", istring("add dryrun option"),
106          dryrun);
107          
108          */
109         bool dumpdescription = false;
110         options.AddOption('x', "dumpdescription",
111                                           istring("do not submit - dump job description "
112                                                           "in the language accepted by the target"),
113                                           dumpdescription);
114         
115         int timeout = -1;
116         options.AddOption('t', "timeout", istring("timeout in seconds (default 20)"),
117                                           istring("seconds"), timeout);
118         
119         std::string conffile;
120         options.AddOption('z', "conffile",
121                                           istring("configuration file (default ~/.arc/client.conf)"),
122                                           istring("filename"), conffile);
123         
124         std::string debug;
125         options.AddOption('d', "debug",
126                                           istring("FATAL, ERROR, WARNING, INFO, VERBOSE or DEBUG"),
127                                           istring("debuglevel"), debug);
128         
129         std::string broker;
130         options.AddOption('b', "broker",
131                                           istring("select broker method (Random (default), FastestQueue, or custom)"),
132                                           istring("broker"), broker);
133         
134         /**
135          * Sandboxing is always done atm. Maybe there should be a switch to turn it off? 'n' "nolocalsandbox"
136          bool dolocalsandbox = true;
137          options.AddOption('n', "dolocalsandbox",
138          istring("store job descriptions in local sandbox."),
139          dolocalsandbox);
140          */
141         
142         bool version = false;
143         options.AddOption('v', "version", istring("print version information"),
144                                           version);
145         
146         std::list<std::string> params = options.Parse(argc, argv);
147         
148         // If debug is specified as argument, it should be set before loading the configuration.
149         if (!debug.empty())
150                 Arc::Logger::getRootLogger().setThreshold(Arc::string_to_level(debug));
151         
152         Arc::UserConfig usercfg(conffile, joblist);
153         if (!usercfg) {
154                 logger.msg(Arc::ERROR, "Failed configuration initialization");
155                 return 1;
156         }
157         
158         if (debug.empty() && !usercfg.Verbosity().empty())
159                 Arc::Logger::getRootLogger().setThreshold(Arc::string_to_level(usercfg.Verbosity()));
160         
161         if (timeout > 0)
162                 usercfg.Timeout(timeout);
163         
164         if (!broker.empty())
165                 usercfg.Broker(broker);
166         
167         if (version) {
168                 std::cout << Arc::IString("%s version %s", "arcsub", VERSION)
169                 << std::endl;
170                 return 0;
171         }
172         
173         if (!clusters.empty() || !indexurls.empty())
174                 usercfg.ClearSelectedServices();
175         
176         if (!clusters.empty())
177                 usercfg.AddServices(clusters, Arc::COMPUTING);
178         
179         if (!indexurls.empty())
180                 usercfg.AddServices(indexurls, Arc::INDEX);
181         
182         jobdescriptionfiles.insert(jobdescriptionfiles.end(),
183                                                            params.begin(), params.end());
184         
185         if (jobdescriptionfiles.empty() && jobdescriptionstrings.empty()) {
186                 logger.msg(Arc::ERROR, "No job description input specified");
187                 return 1;
188         }
189         
190         std::list<Arc::JobDescription> jobdescriptionlist;
191         
192         //Loop over input job description files
193         for (std::list<std::string>::iterator it = jobdescriptionfiles.begin();
194                  it != jobdescriptionfiles.end(); it++) {
195                 
196                 std::ifstream descriptionfile(it->c_str());
197                 
198                 if (!descriptionfile) {
199                         logger.msg(Arc::ERROR, "Can not open job description file: %s", *it);
200                         return 1;
201                 }
202                 
203                 descriptionfile.seekg(0, std::ios::end);
204                 std::streamsize length = descriptionfile.tellg();
205                 descriptionfile.seekg(0, std::ios::beg);
206                 
207                 char *buffer = new char[length + 1];
208                 descriptionfile.read(buffer, length);
209                 descriptionfile.close();
210                 
211                 buffer[length] = '\0';
212                 Arc::JobDescription jobdesc;
213                 jobdesc.Parse((std::string)buffer);
214                 
215                 if (jobdesc)
216                         jobdescriptionlist.push_back(jobdesc);
217                 else {
218                         logger.msg(Arc::ERROR, "Invalid JobDescription:");
219                         std::cout << buffer << std::endl;
220                         delete[] buffer;
221                         return 1;
222                 }
223                 delete[] buffer;
224         }
225         
226         //Loop over job description input strings
227         for (std::list<std::string>::iterator it = jobdescriptionstrings.begin();
228                  it != jobdescriptionstrings.end(); it++) {
229                 
230                 Arc::JobDescription jobdesc;
231                 
232                 jobdesc.Parse(*it);
233                 
234                 if (jobdesc)
235                         jobdescriptionlist.push_back(jobdesc);
236                 else {
237                         logger.msg(Arc::ERROR, "Invalid JobDescription:");
238                         std::cout << *it << std::endl;
239                         return 1;
240                 }
241         }
242         
243         Arc::TargetGenerator targen(usercfg);
244         targen.GetTargets(0, 1);
245         
246         if (targen.FoundTargets().empty()) {
247                 std::cout << Arc::IString("Job submission aborted because no clusters returned any information") << std::endl;
248                 return 1;
249         }
250         
251         std::map<int, std::string> notsubmitted;
252         
253         int jobnr = 1;
254         std::list<std::string> jobids;
255         
256         Arc::BrokerLoader loader;
257         Arc::Broker *ChosenBroker = loader.load(usercfg.Broker().first, usercfg);
258         if (!ChosenBroker) {
259                 logger.msg(Arc::ERROR, "Unable to load broker %s", usercfg.Broker().first);
260                 return 1;
261         }
262         logger.msg(Arc::INFO, "Broker %s loaded", usercfg.Broker().first);
263         
264         for (std::list<Arc::JobDescription>::iterator it =
265          jobdescriptionlist.begin(); it != jobdescriptionlist.end();
266                  it++, jobnr++) {
267                 
268                 ChosenBroker->PreFilterTargets(targen.ModifyFoundTargets(), *it);
269                 
270                 while (true) {
271                         const Arc::ExecutionTarget* target = ChosenBroker->GetBestTarget();
272                         
273                         if (!target) {
274                                 if (dumpdescription) {
275                                         std::cout << Arc::IString("Unable to print job description: No target found.") << std::endl;
276                                         return 1;
277                                 }
278                                 std::cout << Arc::IString("Job submission failed, no more possible targets") << std::endl;
279                                 break;
280                         }
281                         
282                         Arc::Submitter *submitter = target->GetSubmitter(usercfg);
283                         
284                         if (dumpdescription) {
285                                 Arc::JobDescription jobdescdump(*it);
286                                 if (!submitter->ModifyJobDescription(jobdescdump, *target)) {
287                                         std::cout << "Unable to modify job description according to needs for target cluster." << std::endl;
288                                         return 1;
289                                 }
290                                 
291                                 std::string jobdesclang = "ARCJSDL";
292                                 if (target->GridFlavour == "ARC0")
293                                         jobdesclang = "XRSL";
294                                 else if (target->GridFlavour == "CREAM")
295                                         jobdesclang = "JDL";
296                                 const std::string jobdesc = jobdescdump.UnParse(jobdesclang);
297                                 if (jobdesc.empty()) {
298                                         std::cout << Arc::IString("An error occurred during the generation of the job description output.") << std::endl;
299                                         return 1;
300                                 }
301                                 
302                                 std::cout << Arc::IString("Job description to be send to ") << target->Cluster.str() << ":" << std::endl;
303                                 std::cout << jobdesc << std::endl;
304                                 return 0;
305                         }
306                         
307                         
308                         //submit the job
309                         Arc::URL jobid = submitter->Submit(*it, *target);
310                         if (!jobid) {
311                                 std::cout << Arc::IString("Submission to %s failed, trying next target", target->url.str()) << std::endl;
312                                 continue;
313                         }
314                         
315                         ChosenBroker->RegisterJobsubmission();
316                         std::cout << Arc::IString("Job submitted with jobid: %s", jobid.str())
317                         << std::endl;
318                         
319                         break;
320                 } //end loop over all possible targets
321         } //end loop over all job descriptions
322         
323         if (jobdescriptionlist.size() > 1) {
324                 std::cout << std::endl << Arc::IString("Job submission summary:")
325                 << std::endl;
326                 std::cout << "-----------------------" << std::endl;
327                 std::cout << Arc::IString("%d of %d jobs were submitted",
328                                                                   jobdescriptionlist.size() - notsubmitted.size(),
329                                                                   jobdescriptionlist.size()) << std::endl;
330                 if (notsubmitted.size())
331                         std::cout << Arc::IString("The following %d were not submitted",
332                                                                           notsubmitted.size()) << std::endl;
333                 /*
334                  std::map<int, std::string>::iterator it;
335                  for (it = notsubmitted.begin(); it != notsubmitted.end(); it++) {
336                  std::cout << _("Job nr.") << " " << it->first;
337                  if (it->second.size()>0) std::cout << ": " << it->second;
338                  std::cout << std::endl;
339                  }
340                  */
341         }
342         
343         return 0;
344 }
345