Ticket #131: service_internal_hpc.c

File service_internal_hpc.c, 14.2 KB (added by remicress, 9 years ago)

new zoo HPC service (service_internal_hpc.c)

Line 
1/*
2 * Author : Rémi Cresson
3 */
4
5#include "service_internal_hpc.h"
6//#include "response_print.h"
7//#include "server_internal.h"
8#include "ssh_api.h" // WPS server-side API (WPS<->Cluster)
9#include <string>     // std::string, std::to_string
10/**
11 * Remote application prefix
12 */
13const std::string REMOTE_APPLICATION_PREFIX = "otbcli_"; // TODO: get this from cfg
14
15/**
16 * Global OTB counter
17 */
18int hpcCounter=0;
19
20/**
21 * A pointer to the conf maps containing the main.cfg settings
22 */
23maps* m_HPCConf;
24
25/**
26 * Replace all occurence of from by to in a str string
27 *
28 * @param str the string to transform
29 * @param from the string to replace
30 * @param to the string used as replacement
31 * @return the resulting string
32 */
33std::string ReplaceString(std::string str, const std::string& from, const std::string& to) {
34    size_t start_pos = 0;
35    while((start_pos = str.find(from, start_pos)) != std::string::npos) {
36        str.replace(start_pos, from.length(), to);
37        start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
38    }
39    return str;
40}
41
42struct FileToTransfert
43{
44  std::string local;
45  std::string remote;
46  std::string commandLineKey;
47};
48
49struct CommandLineAtom
50{
51  std::string key;
52  std::string value;
53};
54
55// Dirty routine to get separate logs TODO: remove this
56void clearLog()
57{
58  std::ofstream myfile;
59  myfile.open ("/var/www/tmpWps/output_debug_log.txt");
60  myfile << "Log:\n";
61  myfile.close();
62}
63
64// Dirty routine to get separate logs TODO: remove this
65void log(char * s)
66{
67  std::ofstream myfile;
68  myfile.open ("/var/www/tmpWps/output_debug_log.txt", std::ios::app);
69  myfile << s;
70  myfile << "\n";
71  myfile.close();
72}
73
74// Dirty routine to get separate logs TODO: remove this
75void log(std::string s)
76{
77  log((char*) s.c_str());
78}
79
80
81/*
82
83// FOR DEBUG
84
85void pipeMap(std::stringstream &log, map * it)
86{
87if (it==NULL)
88return;
89if (it->name==NULL)
90return;
91for (;;)
92{
93log << "\nNAME=" << it->name << "\tVALUE=" << it->value;
94if (it->next!=NULL)
95{
96it = it->next;
97}
98else
99{
100break;
101}
102}
103}
104
105void pipeElements(std::stringstream &log, elements * it)
106{
107if (it==NULL)
108return;
109if (it->name==NULL)
110return;
111for (;;)
112{
113log << "\nNAME=" << it->name << "\nContents:";
114pipeMap(log, it->content);
115if (it->next!=NULL)
116{
117it = it->next;
118}
119else
120{
121break;
122}
123}
124}
125*/
126
127
128/*
129 * get the input image extension
130 */
131std::string get_file_extension(map * mimeTypeMap)
132{
133  std::string ext;
134  if(strncasecmp(mimeTypeMap->value,"image/jp2",9)==0)
135    ext="j2k";
136  if(strncasecmp(mimeTypeMap->value,"image/tiff",10)==0)
137    ext="tiff";
138  else if(strncasecmp(mimeTypeMap->value,"image/png",9)==0)
139    ext="png";
140  else if(strncasecmp(mimeTypeMap->value,"image/jpeg",10)==0)
141    ext="jpeg";
142  else if(strncasecmp(mimeTypeMap->value,"text/xml",8)==0)
143    ext="gml";
144  else
145  {
146    ext="unknow";
147    log("ERROR: Unknow file format, mimetype=" + std::string(mimeTypeMap->value));
148  }
149  return ext;
150}
151
152/**
153 * Transform local filename (wps server side) into remote filename (cluster side)
154 */
155std::string LocalFilenameToRemoteFilename(std::string &localfilename)
156{
157  char sep = '/';
158  size_t i = localfilename.rfind(sep, localfilename.length());
159  if (i != std::string::npos)
160  {
161     return(REMOTE_SCRATCH_DIRECTORY + localfilename.substr(i+1, localfilename.length() - i));
162  }
163
164   return("");
165}
166
167/**
168 * Upload a list of files. Return 0 if Ok, else the number of failed transfert
169 */
170int UploadFiles(std::vector<FileToTransfert> list)
171{
172  int rc = 0;
173  for (unsigned int i = 0 ; i < list.size(); i++)
174  {
175    log ("Upload "  + list[i].local + " to " + list[i].remote);
176    if (upload_file(list[i].local, list[i].remote) != 0)
177    {
178      rc = -1;
179      log("\tError: could not transfert file");
180    }
181  }
182  return rc;
183}
184
185/**
186 * Download a list of files. Return 0 if Ok, else the number of failed transfert
187 */
188int DownloadFiles(std::vector<FileToTransfert> list)
189{
190  int rc = 0;
191  for (unsigned int i = 0 ; i < list.size(); i++)
192  {
193    log ("Download "  + list[i].remote + " to " + list[i].local);
194    if (download_file(list[i].local, list[i].remote) != 0)
195    {
196      rc ++;
197      log("\tError: could not transfert file");
198    }
199  }
200  return rc;
201}
202
203/**
204 * Load and run an OTB Application corresponding to the service by using inputs parameters.
205 * Define the m_HPCConf
206 *
207 * @param main_conf the conf maps containing the main.cfg settings
208 * @param request the map containing the HTTP request
209 * @param s the service structure, describe the .zcfg
210 * @param real_inputs the maps containing the inputs
211 * @param real_outputs the maps containing the outputs
212 */
213int zoo_hpc_support(maps** main_conf,map* request,service* s,maps **real_inputs,maps **real_outputs){
214  clearLog();
215
216  maps* m=*main_conf;
217  maps* inputs=*real_inputs;
218  maps* outputs=*real_outputs;
219
220  // Temporary directory (e.g. /var/www/tmpWps)
221  map* tmpPath=getMapFromMaps(m,"main","tmpPath");
222
223  // SID (kind of hashcode)
224  map* tmpSid_main=getMapFromMaps(m,"lenv","usid");
225
226  // Save inputs to the temporary directory
227  dumpMapsValuesToFiles(main_conf,real_inputs);
228
229  // Get the list of keys/values (input of application)
230  std::vector<CommandLineAtom> commandLineAtoms;
231  std::vector<FileToTransfert> filesToDownload;
232  std::vector<FileToTransfert> filesToUpload;
233
234  // Browse inputs
235  elements * it = s->inputs;
236  if (it->name!=NULL)
237  {
238    for (;;)
239    {
240      // get the current input key
241      map * input_key=getMapFromMaps(inputs,it->name,"value");
242log("processing key " + std::string(it->name));
243      // if associated value is NULL, we skip this key/value
244      if (strcmp(input_key->value,"NULL")!=0)
245      {
246        std::string key, value;
247        key = std::string(it->name);
248log("processed key " + key + " is not null");
249        // if the key's value is ComplexData, then we check the associated cache_file in
250        // order to upload file(s)
251        if (strcmp(it->format,"ComplexData")==0 )
252        {
253log("key related to complex data");
254          // value can be a list, so we need to iterate through the map
255          map* input_cache_file = getMapFromMaps(inputs,it->name,"cache_file");
256          if (input_cache_file == NULL)
257          {
258            // passed by reference TODO: something with the url?
259          }
260          else
261          {
262
263            // Check if the key has multiple values (i.e. list)
264            value = std::string(input_cache_file->value);
265            FileToTransfert fileToTransfert;
266            fileToTransfert.local = value;
267            fileToTransfert.remote = LocalFilenameToRemoteFilename(value);
268            fileToTransfert.commandLineKey = std::string(it->name);
269            filesToUpload.push_back(fileToTransfert);
270            value = fileToTransfert.remote;
271            map* tmpLength=getMapFromMaps(inputs,it->name,"length");
272            if(tmpLength!=NULL)
273            {
274              // key may have multiple parameters
275              int len=atoi(tmpLength->value);
276              for(int k=1;k<len;k++)
277              {
278                char tmp[15];
279                sprintf(tmp,"cache_file_%d",k);
280                log(std::string(tmp));
281                map* tmpVal=getMapFromMaps(inputs,it->name,tmp);
282                if(tmpVal!=NULL){
283                  std::string filename(tmpVal->value);
284                  FileToTransfert fileToTransfert;
285                  fileToTransfert.local = filename;
286                  fileToTransfert.remote = LocalFilenameToRemoteFilename(filename);
287                  fileToTransfert.commandLineKey = std::string(it->name);
288                  filesToUpload.push_back(fileToTransfert);
289                  value += " " + fileToTransfert.remote;
290                }
291              }
292            }
293          } // passed by reference/expression
294        }  // is complex data
295        else
296        {
297          value = input_key->value;
298        }
299
300        // get the current output key
301        maps* output_key=getMaps(outputs,it->name);
302        if (output_key!=NULL)
303        {
304
305          // If the current output key is not NULL, we consider its value an output parameter.
306          // As an current input key already exists, we check if it's the same. Then we concatenate
307          // the output key value with the generated filename in order to respect the convention
308          // of OTB. e.g. -out output_file.tif uint8. In this example, uint8 is the
309          // current input value and output_file the current output value
310
311          // check that output_key is the same as input_key
312          if (key.compare(std::string(output_key->name)) != 0)
313          {
314            log("ERROR: key is not the same at the input/output");
315            return SERVICE_FAILED;
316          }
317
318          // get output (file?) type
319          map* mimeTypeMap = getMapFromMaps(outputs,output_key->name,"mimeType");
320          if (mimeTypeMap->value == NULL)
321          {
322            log("ERROR: mimeTypeMap is NULL");
323            return SERVICE_FAILED;
324          }
325          std::string extension = get_file_extension(mimeTypeMap);
326
327          // construct the local output file name
328          // TODO: Make something generalizable to other apps than OTB...
329          std::string filename = std::string(tmpPath->value) + std::string(s->name) // temp. path + application name
330                + "_" + key // application output name (e.g. "out")
331                + "_" + std::string(tmpSid_main->value)  // sid
332                + "." + extension; // output filename extension (e.g. ".tiff")
333
334          // add the filename to the list of files to download
335          FileToTransfert fileToTransfert;
336          fileToTransfert.local = filename;
337          fileToTransfert.remote = LocalFilenameToRemoteFilename(filename);
338          fileToTransfert.commandLineKey = key;
339          filesToDownload.push_back(fileToTransfert);
340          log ( "\nAdd file to download after execution : \n\tLocal:" + fileToTransfert.local + "\n\tRemote:" + fileToTransfert.remote);
341
342          // the stored value is the filename followed by the datatype value (OTB convention)
343          value = fileToTransfert.remote
344                + " " + value; // output data type (e.g. "uint16") 
345        }
346
347        // we add the key/value
348         log ( "\nAdd key=" + key + " (format: "  + std::string(it->format) + ") value=" + value);
349        CommandLineAtom commandLineAtom;
350        commandLineAtom.key = key;
351        commandLineAtom.value = value;
352        commandLineAtoms.push_back(commandLineAtom);
353      } // key is not NULL
354
355      if (it->next!=NULL)
356      {
357        it = it->next;
358      }
359      else
360      {
361        break;
362      }
363    }
364  }
365
366  // Browse outputs
367  elements * out_it = s->outputs;
368  if (out_it->name!=NULL)
369  {
370    for (;;)
371    {
372      // get the current output key
373      map * output_key=getMapFromMaps(outputs,out_it->name,"value");
374      std::string output_key_name(out_it->name);
375      log("processing output key " + output_key_name + "(" + std::string(out_it->format) + ")" );
376
377      if (strcmp(out_it->format,"ComplexData")==0 )
378      {
379        // get the current associated input key
380        map * input_key=getMapFromMaps(inputs,out_it->name,"value");
381 
382        // if associated value is not NULL, we skip this key/value (already done when browsing inputs)
383        if (input_key!=NULL)
384        {
385log("This key is already incorporated in the commandline");
386        }
387        else
388        {
389log("We have an output key to add.");
390
391          // get output (file?) type
392          std::string key(out_it->name);
393          map* mimeTypeMap = getMapFromMaps(outputs,key.c_str(),"mimeType");
394          if (mimeTypeMap==NULL)
395          {
396            log("mimeTypeMap=NULL");
397          }
398          else if (mimeTypeMap->value == NULL)
399          {
400            log("ERROR: mimeTypeMap is NULL");
401            return SERVICE_FAILED;
402          }
403
404          std::string extension = get_file_extension(mimeTypeMap);
405
406          // construct the local output file name
407          std::string filename = std::string(tmpPath->value) + std::string(s->name) // temp. path + application name
408                + "_" + key // application output name (e.g. "out")
409                + "_" + std::string(tmpSid_main->value)  // sid
410                + "." + extension; // output filename extension (e.g. ".tiff")
411
412          // add the filename to the list of files to download
413          FileToTransfert fileToTransfert;
414          fileToTransfert.local = filename;
415          fileToTransfert.remote = LocalFilenameToRemoteFilename(filename);
416          fileToTransfert.commandLineKey = key;
417          filesToDownload.push_back(fileToTransfert);
418          log ( "\nAdd file to download after execution : \n\tLocal:" + fileToTransfert.local + "\n\tRemote:" + fileToTransfert.remote);
419
420        // we add the key/value
421            CommandLineAtom commandLineAtom;
422        commandLineAtom.key = key;
423        commandLineAtom.value = fileToTransfert.remote;
424        commandLineAtoms.push_back(commandLineAtom);
425        }
426      }
427      if (out_it->next!=NULL)
428      {
429        out_it = out_it->next;
430      }
431      else
432      {
433        break;
434      }
435    }
436  }
437
438  // Create the commandline
439  std::string commandLine(REMOTE_APPLICATION_PREFIX + std::string(s->name));
440  for (unsigned int i = 0 ; i < commandLineAtoms.size(); i++)
441  {
442    commandLine += " -" + commandLineAtoms[i].key + " " + commandLineAtoms[i].value;
443  }
444  log ( "\nCommand line (cluster side) is:" + commandLine);
445
446  // Upload files
447  int rc = UploadFiles(filesToUpload);
448  if (rc==0)
449  {
450    log ( "\nFiles were successfuly uploaded" );
451  }
452  else
453  {
454    log ( "\nSome upload(s) failed" );
455    return SERVICE_FAILED;
456  }
457
458  // Execute the job (synchronous mode)
459  std::string executionResult = "";
460  rc = submit_command_sync(commandLine, executionResult);
461  if (rc==0)
462  {
463    log ( "\nJob successfuly executed (" + executionResult + ")" );
464  }
465  else
466  {
467    log ( "\nError during job execution : " + executionResult );
468    return SERVICE_FAILED;
469  }
470 
471  // Download results
472  rc = DownloadFiles(filesToDownload);
473  if (rc==0)
474  {
475    log ( "\nFiles were successfuly downloaded" );
476  }
477  else
478  {
479    log ( "\nWarning, some download(s) failed" );
480  }
481
482  // Encapsulate results in output
483  // As we are lazy, we just iterate over the downloaded files
484  // (no need to check filesToDownload consistency since the previous
485  // step not returned)
486  for (unsigned int i = 0 ; i < filesToDownload.size() ; i++)
487  {
488    log("Encapsulating " + filesToDownload[i].local + " (" + filesToDownload[i].commandLineKey + ")");
489    setMapInMaps(outputs,filesToDownload[i].commandLineKey.c_str(),"generated_file",filesToDownload[i].local.c_str());
490  }
491
492  log("Service succeeded");
493  return SERVICE_SUCCEEDED;
494
495}

Search

Context Navigation

ZOO Sponsors

http://www.zoo-project.org/trac/chrome/site/img/geolabs-logo.pnghttp://www.zoo-project.org/trac/chrome/site/img/neogeo-logo.png http://www.zoo-project.org/trac/chrome/site/img/apptech-logo.png http://www.zoo-project.org/trac/chrome/site/img/3liz-logo.png http://www.zoo-project.org/trac/chrome/site/img/gateway-logo.png

Become a sponsor !

Knowledge partners

http://www.zoo-project.org/trac/chrome/site/img/ocu-logo.png http://www.zoo-project.org/trac/chrome/site/img/gucas-logo.png http://www.zoo-project.org/trac/chrome/site/img/polimi-logo.png http://www.zoo-project.org/trac/chrome/site/img/fem-logo.png http://www.zoo-project.org/trac/chrome/site/img/supsi-logo.png http://www.zoo-project.org/trac/chrome/site/img/cumtb-logo.png

Become a knowledge partner

Related links

http://zoo-project.org/img/ogclogo.png http://zoo-project.org/img/osgeologo.png