neptune 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. data/README +7 -4
  2. data/doc/AppControllerClient.html +12 -4
  3. data/doc/CommonFunctions.html +55 -42
  4. data/doc/Kernel.html +187 -0
  5. data/doc/LICENSE.html +2 -0
  6. data/doc/Object.html +488 -198
  7. data/doc/README.html +26 -5
  8. data/doc/bin/neptune.html +1 -1
  9. data/doc/created.rid +6 -6
  10. data/doc/index.html +20 -2
  11. data/doc/lib/app_controller_client_rb.html +2 -2
  12. data/doc/lib/common_functions_rb.html +2 -2
  13. data/doc/lib/neptune_rb.html +3 -1
  14. data/lib/app_controller_client.rb +2 -2
  15. data/lib/common_functions.rb +50 -24
  16. data/lib/neptune.rb +224 -159
  17. data/samples/appscale/add_appserver.rb +10 -0
  18. data/samples/appscale/add_database.rb +9 -0
  19. data/samples/appscale/add_loadbalancer.rb +9 -0
  20. data/samples/appscale/add_slave.rb +9 -0
  21. data/samples/c/compile_helloworld.rb +10 -0
  22. data/samples/c/helloworld/helloworld.c +6 -0
  23. data/samples/erlang/compile_erlang_ring.rb +10 -0
  24. data/samples/erlang/get_erlang_output.rb +8 -0
  25. data/samples/erlang/ring/Makefile +3 -0
  26. data/samples/erlang/ring/ring.erl +90 -0
  27. data/samples/erlang/run_erlang_ring.rb +6 -0
  28. data/samples/go/compile_hello.rb +10 -0
  29. data/samples/go/get_hello_output.rb +6 -0
  30. data/samples/go/hello/hello.go +8 -0
  31. data/samples/go/put_input.rb +8 -0
  32. data/samples/go/run_hello.rb +9 -0
  33. data/samples/mapreduce/expected-output.txt +7078 -0
  34. data/samples/mapreduce/get_mapreduce_output.rb +4 -0
  35. data/samples/mapreduce/hadoop-0.20.0-examples.jar +0 -0
  36. data/samples/mapreduce/input-10 +64 -0
  37. data/samples/mapreduce/input-30 +64 -0
  38. data/samples/mapreduce/input-7 +4 -0
  39. data/samples/mapreduce/map.rb +48 -0
  40. data/samples/mapreduce/reduce.rb +48 -0
  41. data/samples/mapreduce/run_java_mr.rb +14 -0
  42. data/samples/mapreduce/run_mapreduce.rb +13 -0
  43. data/samples/mapreduce/the-end-of-time.txt +11256 -0
  44. data/samples/mpi/Makefile +22 -0
  45. data/samples/mpi/MpiQueen +0 -0
  46. data/samples/mpi/compile_mpi_ring.rb +10 -0
  47. data/samples/mpi/compile_x10_nqueens.rb +8 -0
  48. data/samples/mpi/cpi +0 -0
  49. data/samples/mpi/get_mpi_output.rb +5 -0
  50. data/samples/mpi/get_ring_output.rb +5 -0
  51. data/samples/mpi/hw2.c +205 -0
  52. data/samples/mpi/hw2harness.c +84 -0
  53. data/samples/mpi/hw2harness.h +45 -0
  54. data/samples/mpi/powermethod +0 -0
  55. data/samples/mpi/ring/Makefile +2 -0
  56. data/samples/mpi/ring/Ring.c +76 -0
  57. data/samples/mpi/run_mpi_cpi.rb +10 -0
  58. data/samples/mpi/run_mpi_nqueens.np +6 -0
  59. data/samples/mpi/run_mpi_powermethod.rb +8 -0
  60. data/samples/mpi/run_mpi_ring.rb +12 -0
  61. data/samples/r/compile_hello.rb +10 -0
  62. data/samples/r/get_hello_output.rb +6 -0
  63. data/samples/r/hello/hello.r +1 -0
  64. data/samples/r/put_input.rb +8 -0
  65. data/samples/r/run_hello.rb +9 -0
  66. data/samples/upc/compile_upc_helloworld.rb +10 -0
  67. data/samples/upc/compile_upc_ring.rb +11 -0
  68. data/samples/upc/get_mpi_output.rb +8 -0
  69. data/samples/upc/helloworld/HelloWorld.c +9 -0
  70. data/samples/upc/helloworld/Makefile +3 -0
  71. data/samples/upc/ring/Makefile +3 -0
  72. data/samples/upc/ring/Ring.c +116 -0
  73. data/samples/upc/run_upc_helloworld.rb +12 -0
  74. data/samples/upc/run_upc_ring.rb +12 -0
  75. data/samples/x10/MyPowerMethod +0 -0
  76. data/samples/x10/MyPowerMethod.x10 +236 -0
  77. data/samples/x10/NQueensDist +0 -0
  78. data/samples/x10/NQueensDist.x10 +112 -0
  79. data/samples/x10/compile_x10_nqueens.rb +7 -0
  80. data/samples/x10/compile_x10_ring.rb +12 -0
  81. data/samples/x10/get_x10_output.rb +8 -0
  82. data/samples/x10/ring/Makefile +3 -0
  83. data/samples/x10/ring/Ring.x10 +28 -0
  84. data/samples/x10/ring/RingOld.x10 +68 -0
  85. data/samples/x10/run_x10_nqueens.rb +6 -0
  86. data/samples/x10/run_x10_powermethod.rb +7 -0
  87. data/samples/x10/run_x10_ring.rb +6 -0
  88. data/test/{tc_c.rb → integration/tc_c.rb} +2 -2
  89. data/test/{tc_dfsp.rb → integration/tc_dfsp.rb} +0 -0
  90. data/test/{tc_dwssa.rb → integration/tc_dwssa.rb} +0 -0
  91. data/test/{tc_erlang.rb → integration/tc_erlang.rb} +0 -0
  92. data/test/{tc_mapreduce.rb → integration/tc_mapreduce.rb} +0 -0
  93. data/test/{tc_mpi.rb → integration/tc_mpi.rb} +0 -0
  94. data/test/{tc_storage.rb → integration/tc_storage.rb} +0 -0
  95. data/test/{tc_upc.rb → integration/tc_upc.rb} +0 -0
  96. data/test/{tc_x10.rb → integration/tc_x10.rb} +0 -0
  97. data/test/{test_helper.rb → integration/test_helper.rb} +0 -0
  98. data/test/{ts_neptune.rb → integration/ts_neptune.rb} +2 -2
  99. data/test/unit/test_app_controller_client.rb +106 -0
  100. data/test/unit/test_common_functions.rb +106 -0
  101. data/test/unit/test_neptune.rb +208 -0
  102. data/test/unit/ts_all.rb +6 -0
  103. metadata +91 -15
data/doc/LICENSE.html CHANGED
@@ -66,6 +66,8 @@
66
66
 
67
67
  <li><a href="./CommonFunctions.html">CommonFunctions</a></li>
68
68
 
69
+ <li><a href="./Kernel.html">Kernel</a></li>
70
+
69
71
  <li><a href="./Object.html">Object</a></li>
70
72
 
71
73
  </ul>
data/doc/Object.html CHANGED
@@ -72,18 +72,32 @@
72
72
  <h3 class="section-header">Methods</h3>
73
73
  <ul class="link-list">
74
74
 
75
+ <li><a href="#method-i-compile_code">#compile_code</a></li>
76
+
75
77
  <li><a href="#method-i-do_preprocessing">#do_preprocessing</a></li>
76
78
 
79
+ <li><a href="#method-i-get_input">#get_input</a></li>
80
+
81
+ <li><a href="#method-i-get_job_data">#get_job_data</a></li>
82
+
83
+ <li><a href="#method-i-get_std_out_and_err">#get_std_out_and_err</a></li>
84
+
77
85
  <li><a href="#method-i-neptune">#neptune</a></li>
78
86
 
79
87
  <li><a href="#method-i-preprocess_compile">#preprocess_compile</a></li>
80
88
 
81
89
  <li><a href="#method-i-preprocess_erlang">#preprocess_erlang</a></li>
82
90
 
83
- <li><a href="#method-i-preprocess_mapreduce">#preprocess_mapreduce</a></li>
84
-
85
91
  <li><a href="#method-i-preprocess_mpi">#preprocess_mpi</a></li>
86
92
 
93
+ <li><a href="#method-i-preprocess_ssa">#preprocess_ssa</a></li>
94
+
95
+ <li><a href="#method-i-run_job">#run_job</a></li>
96
+
97
+ <li><a href="#method-i-validate_storage_params">#validate_storage_params</a></li>
98
+
99
+ <li><a href="#method-i-wait_for_compilation_to_finish">#wait_for_compilation_to_finish</a></li>
100
+
87
101
  </ul>
88
102
  </div>
89
103
 
@@ -126,6 +140,8 @@
126
140
 
127
141
  <li><a href="./CommonFunctions.html">CommonFunctions</a></li>
128
142
 
143
+ <li><a href="./Kernel.html">Kernel</a></li>
144
+
129
145
  <li><a href="./Object.html">Object</a></li>
130
146
 
131
147
  </ul>
@@ -145,7 +161,9 @@
145
161
  Neptune support. In the future, it is likely that the only exposed /
146
162
  monkey-patched method should be job, while the others could probably be
147
163
  folded into either a Neptune-specific class or into <a
148
- href="CommonFunctions.html">CommonFunctions</a>.</p>
164
+ href="CommonFunctions.html">CommonFunctions</a>. TODO(cbunch): This
165
+ doesn’t look like it does anything - run the integration test and confirm
166
+ one way or the other.</p>
149
167
 
150
168
  </div>
151
169
 
@@ -201,6 +219,65 @@ computation can be performed.</p></dd>
201
219
  <h3 class="section-header">Public Instance Methods</h3>
202
220
 
203
221
 
222
+ <div id="compile_code-method" class="method-detail ">
223
+ <a name="method-i-compile_code"></a>
224
+
225
+
226
+ <div class="method-heading">
227
+ <span class="method-name">compile_code</span><span
228
+ class="method-args">(job_data, ssh_args, shadow_ip, shell=Kernel.method(:`))</span>
229
+ <span class="method-click-advice">click to toggle source</span>
230
+ </div>
231
+
232
+
233
+ <div class="method-description">
234
+
235
+ <p>This method sends out a request to compile code, waits for it to finish,
236
+ and gets the standard out and error returned from the compilation. This
237
+ method returns a hash containing the standard out, error, and a result that
238
+ indicates whether or not the compilation was successful.</p>
239
+
240
+
241
+
242
+ <div class="method-source-code"
243
+ id="compile_code-source">
244
+ <pre>
245
+ <span class="ruby-comment"># File lib/neptune.rb, line 281</span>
246
+ def compile_code(job_data, ssh_args, shadow_ip, shell=<span class="ruby-constant">Kernel</span>.method(:`))
247
+ compiled_location = controller.compile_code(job_data)
248
+
249
+ copy_to = job_data[<span class="ruby-string">&quot;@copy_to&quot;</span>]
250
+
251
+ wait_for_compilation_to_finish(ssh_args, shadow_ip, compiled_location)
252
+
253
+ <span class="ruby-constant">FileUtils</span>.rm_rf(copy_to)
254
+
255
+ scp_command = &quot;scp -r #{ssh_args} root@#{shadow_ip}:#{compiled_location} #{copy_to} 2&gt;&amp;1&quot;
256
+ puts scp_command
257
+ shell.call(scp_command)
258
+
259
+ code = job_data[<span class="ruby-string">&quot;@code&quot;</span>]
260
+ dirs = code.split(<span class="ruby-regexp">/\//</span>)
261
+ remote_dir = <span class="ruby-string">&quot;/tmp/&quot;</span> + dirs[-1]
262
+
263
+ [remote_dir, compiled_location].each { |remote_files|
264
+ ssh_command = &quot;ssh #{ssh_args} root@#{shadow_ip} 'rm -rf #{remote_files}' 2&gt;&amp;1&quot;
265
+ puts ssh_command
266
+ shell.call(ssh_command)
267
+ }
268
+
269
+ return get_std_out_and_err(copy_to)
270
+ end</pre>
271
+ </div>
272
+
273
+ </div>
274
+
275
+
276
+
277
+
278
+ </div>
279
+
280
+
204
281
  <div id="do_preprocessing-method" class="method-detail ">
205
282
  <a name="method-i-do_preprocessing"></a>
206
283
 
@@ -223,10 +300,12 @@ method to use based on the type of the job that the user has asked to run.</p>
223
300
  <div class="method-source-code"
224
301
  id="do_preprocessing-source">
225
302
  <pre>
226
- <span class="ruby-comment"># File lib/neptune.rb, line 49</span>
303
+ <span class="ruby-comment"># File lib/neptune.rb, line 52</span>
227
304
  def do_preprocessing(job_data)
228
305
  job_type = job_data[<span class="ruby-string">&quot;@type&quot;</span>]
229
- return unless <span class="ruby-constant">NEED_PREPROCESSING</span>.include?(job_type)
306
+ if !<span class="ruby-constant">NEED_PREPROCESSING</span>.include?(job_type)
307
+ return
308
+ end
230
309
 
231
310
  preprocess = &quot;preprocess_#{job_type}&quot;.to_sym
232
311
  send(preprocess, job_data)
@@ -241,51 +320,101 @@ end</pre>
241
320
  </div>
242
321
 
243
322
 
244
- <div id="neptune-method" class="method-detail ">
245
- <a name="method-i-neptune"></a>
323
+ <div id="get_input-method" class="method-detail ">
324
+ <a name="method-i-get_input"></a>
246
325
 
247
326
 
248
327
  <div class="method-heading">
249
- <span class="method-name">neptune</span><span
250
- class="method-args">(params)</span>
328
+ <span class="method-name">get_input</span><span
329
+ class="method-args">(job_data, ssh_args, shadow_ip, controller, file=File, shell=Kernel.method(:`))</span>
251
330
  <span class="method-click-advice">click to toggle source</span>
252
331
  </div>
253
332
 
254
333
 
255
334
  <div class="method-description">
256
335
 
257
- <p>This method is the heart of Neptune - here, we take blocks of code that the
258
- user has written and convert them into HPC job requests. At a high level,
259
- the user can request to run a job, retrieve a job’s output, or modify the
260
- access policy (ACL) for the output of a job. By default, job data is
261
- private, but a Neptune job can be used to set it to public later (and
262
- vice-versa).</p>
336
+ <p>This method takes a file on the local user’s computer and stores it
337
+ remotely via AppScale. It returns a hash map indicating whether or not the
338
+ job succeeded and if it failed, the reason for it.</p>
263
339
 
264
340
 
265
341
 
266
342
  <div class="method-source-code"
267
- id="neptune-source">
343
+ id="get_input-source">
268
344
  <pre>
269
- <span class="ruby-comment"># File lib/neptune.rb, line 175</span>
270
- def neptune(params)
271
- puts <span class="ruby-string">&quot;Received a request to run a job.&quot;</span>
272
- puts params[:type]
345
+ <span class="ruby-comment"># File lib/neptune.rb, line 227</span>
346
+ def get_input(job_data, ssh_args, shadow_ip, controller, file=<span class="ruby-constant">File</span>,
347
+ shell=<span class="ruby-constant">Kernel</span>.method(:`))
348
+ result = {:result =&gt; :success}
273
349
 
274
- keyname = params[:keyname] || <span class="ruby-string">&quot;appscale&quot;</span>
350
+ if !job_data[<span class="ruby-string">&quot;@local&quot;</span>]
351
+ abort(<span class="ruby-string">&quot;You failed to specify a file to copy over via the :local flag.&quot;</span>)
352
+ end
275
353
 
276
- shadow_ip = <span class="ruby-constant">CommonFunctions</span>.get_from_yaml(keyname, :shadow)
277
- secret = <span class="ruby-constant">CommonFunctions</span>.get_secret_key(keyname)
278
- controller = <span class="ruby-constant">AppControllerClient</span>.new(shadow_ip, secret)
279
- ssh_key = <span class="ruby-constant">File</span>.expand_path(&quot;~/.appscale/#{keyname}.key&quot;)
354
+ local_file = file.expand_path(job_data[<span class="ruby-string">&quot;@local&quot;</span>])
355
+ if !file.exists?(local_file)
356
+ reason = &quot;the file you specified to copy, #{local_file}, doesn't exist.&quot; +
357
+ <span class="ruby-string">&quot; Please specify a file that exists and try again.&quot;</span>
358
+ return {:result =&gt; :failure, :reason =&gt; reason}
359
+ end
360
+
361
+ remote = &quot;/tmp/neptune-input-#{rand(100000)}&quot;
362
+ scp_cmd = &quot;scp -r #{ssh_args} #{local_file} root@#{shadow_ip}:#{remote}&quot;
363
+ puts scp_cmd
364
+ shell.call(scp_cmd)
365
+
366
+ job_data[<span class="ruby-string">&quot;@local&quot;</span>] = remote
367
+ puts &quot;job data = #{job_data.inspect}&quot;
368
+ response = controller.put_input(job_data)
369
+ if response
370
+ return {:result =&gt; :success}
371
+ else
372
+ <span class="ruby-comment"># TODO - expand this to include the reason why it failed</span>
373
+ return {:result =&gt; :failure}
374
+ end
375
+ end</pre>
376
+ </div>
377
+
378
+ </div>
379
+
380
+
381
+
382
+
383
+ </div>
280
384
 
385
+
386
+ <div id="get_job_data-method" class="method-detail ">
387
+ <a name="method-i-get_job_data"></a>
388
+
389
+
390
+ <div class="method-heading">
391
+ <span class="method-name">get_job_data</span><span
392
+ class="method-args">(params)</span>
393
+ <span class="method-click-advice">click to toggle source</span>
394
+ </div>
395
+
396
+
397
+ <div class="method-description">
398
+
399
+
400
+
401
+
402
+
403
+ <div class="method-source-code"
404
+ id="get_job_data-source">
405
+ <pre>
406
+ <span class="ruby-comment"># File lib/neptune.rb, line 151</span>
407
+ def get_job_data(params)
281
408
  job_data = {}
282
409
  params.each { |k, v|
283
410
  key = &quot;@#{k}&quot;
284
411
  job_data[key] = v
285
412
  }
286
413
 
287
- job_data[<span class="ruby-string">&quot;@job&quot;</span>] = nil
288
- job_data[<span class="ruby-string">&quot;@keyname&quot;</span>] = keyname || <span class="ruby-string">&quot;appscale&quot;</span>
414
+ job_data.delete(<span class="ruby-string">&quot;@job&quot;</span>)
415
+ job_data[<span class="ruby-string">&quot;@keyname&quot;</span>] = params[:keyname] || <span class="ruby-string">&quot;appscale&quot;</span>
416
+
417
+ job_data[<span class="ruby-string">&quot;@type&quot;</span>] = job_data[<span class="ruby-string">&quot;@type&quot;</span>].to_s
289
418
  type = job_data[<span class="ruby-string">&quot;@type&quot;</span>]
290
419
 
291
420
  if type == <span class="ruby-string">&quot;upc&quot;</span> or type == <span class="ruby-string">&quot;x10&quot;</span>
@@ -307,115 +436,110 @@ def neptune(params)
307
436
  end
308
437
  end
309
438
 
310
- if job_data[<span class="ruby-string">&quot;@storage&quot;</span>]
311
- storage = job_data[<span class="ruby-string">&quot;@storage&quot;</span>]
312
- unless <span class="ruby-constant">ALLOWED_STORAGE_TYPES</span>.include?(storage)
313
- msg = &quot;Supported storage types are #{ALLOWED_STORAGE_TYPES.join(', ')}&quot; +
314
- &quot; - we do not support #{storage}.&quot;
315
- abort(msg)
316
- end
439
+ return job_data
440
+ end</pre>
441
+ </div>
442
+
443
+ </div>
317
444
 
318
- <span class="ruby-comment"># Our implementation for storing / retrieving via Google Storage uses</span>
319
- <span class="ruby-comment"># the same library as we do for S3 - so just tell it that it's S3</span>
320
- if storage == <span class="ruby-string">&quot;gstorage&quot;</span>
321
- storage = <span class="ruby-string">&quot;s3&quot;</span>
322
- job_data[<span class="ruby-string">&quot;@storage&quot;</span>] = <span class="ruby-string">&quot;s3&quot;</span>
323
- end
445
+
324
446
 
325
- if storage == <span class="ruby-string">&quot;s3&quot;</span>
326
- [<span class="ruby-string">&quot;EC2_ACCESS_KEY&quot;</span>, <span class="ruby-string">&quot;EC2_SECRET_KEY&quot;</span>, <span class="ruby-string">&quot;S3_URL&quot;</span>].each { |item|
327
- unless job_data[&quot;@#{item}&quot;]
328
- if <span class="ruby-constant">ENV</span>[item]
329
- puts &quot;Using #{item} from environment&quot;
330
- job_data[&quot;@#{item}&quot;] = <span class="ruby-constant">ENV</span>[item]
331
- else
332
- msg = &quot;When storing data to S3, #{item} must be specified or be in &quot; +
333
- <span class="ruby-string">&quot;your environment. Please do so and try again.&quot;</span>
334
- abort(msg)
335
- end
336
- end
337
- }
338
- end
447
+
448
+ </div>
449
+
450
+
451
+ <div id="get_std_out_and_err-method" class="method-detail ">
452
+ <a name="method-i-get_std_out_and_err"></a>
453
+
454
+
455
+ <div class="method-heading">
456
+ <span class="method-name">get_std_out_and_err</span><span
457
+ class="method-args">(location)</span>
458
+ <span class="method-click-advice">click to toggle source</span>
459
+ </div>
460
+
461
+
462
+ <div class="method-description">
463
+
464
+ <p>This method returns a hash containing the standard out and standard error
465
+ from a completed job, as well as a result field that indicates whether or
466
+ not the job completed successfully (success = no errors).</p>
467
+
468
+
469
+
470
+ <div class="method-source-code"
471
+ id="get_std_out_and_err-source">
472
+ <pre>
473
+ <span class="ruby-comment"># File lib/neptune.rb, line 310</span>
474
+ def get_std_out_and_err(location)
475
+ result = {}
476
+
477
+ out = <span class="ruby-constant">File</span>.open(&quot;#{location}/compile_out&quot;) { |f| f.read.chomp! }
478
+ result[:out] = out
479
+
480
+ err = <span class="ruby-constant">File</span>.open(&quot;#{location}/compile_err&quot;) { |f| f.read.chomp! }
481
+ result[:err] = err
482
+
483
+ if result[:err]
484
+ result[:result] = :failure
339
485
  else
340
- job_data[<span class="ruby-string">&quot;@storage&quot;</span>] = <span class="ruby-string">&quot;appdb&quot;</span>
341
- end
486
+ result[:result] = :success
487
+ end
342
488
 
343
- <span class="ruby-comment">#if job_data[&quot;@can_run_on&quot;].class == Range</span>
344
- <span class="ruby-comment"># job_data[&quot;@can_run_on&quot;] = job_data[&quot;@can_run_on&quot;].to_a</span>
345
- <span class="ruby-comment">#elsif job_data[&quot;@can_run_on&quot;].class == Fixnum</span>
346
- <span class="ruby-comment"># job_data[&quot;@can_run_on&quot;] = [job_data[&quot;@can_run_on&quot;]]</span>
347
- <span class="ruby-comment">#end</span>
489
+ return result
490
+ end</pre>
491
+ </div>
492
+
493
+ </div>
348
494
 
349
- puts &quot;job data = #{job_data.inspect}&quot;
495
+
350
496
 
351
- do_preprocessing(job_data)
497
+
498
+ </div>
352
499
 
353
- ssh_args = &quot;-i ~/.appscale/#{keyname}.key -o StrictHostkeyChecking=no &quot;
500
+
501
+ <div id="neptune-method" class="method-detail ">
502
+ <a name="method-i-neptune"></a>
354
503
 
355
- if type == <span class="ruby-string">&quot;input&quot;</span>
356
- <span class="ruby-comment"># copy file to remote</span>
357
- <span class="ruby-comment"># set location</span>
358
- local_file = <span class="ruby-constant">File</span>.expand_path(job_data[<span class="ruby-string">&quot;@local&quot;</span>])
359
- if !<span class="ruby-constant">File</span>.exists?(local_file)
360
- msg = &quot;the file you specified to copy, #{local_file}, doesn't exist.&quot; +
361
- <span class="ruby-string">&quot; Please specify a file that exists and try again.&quot;</span>
362
- abort(msg)
363
- end
504
+
505
+ <div class="method-heading">
506
+ <span class="method-name">neptune</span><span
507
+ class="method-args">(params)</span>
508
+ <span class="method-click-advice">click to toggle source</span>
509
+ </div>
510
+
364
511
 
365
- remote = &quot;/tmp/neptune-input-#{rand(100000)}&quot;
366
- scp_cmd = &quot;scp #{ssh_args} #{local_file} root@#{shadow_ip}:#{remote}&quot;
367
- puts scp_cmd
368
- `#{scp_cmd}`
369
-
370
- job_data[<span class="ruby-string">&quot;@local&quot;</span>] = remote
371
- puts &quot;job data = #{job_data.inspect}&quot;
372
- return controller.put_input(job_data)
373
- elsif type == <span class="ruby-string">&quot;output&quot;</span>
374
- return controller.get_output(job_data)
375
- elsif type == <span class="ruby-string">&quot;get-acl&quot;</span>
376
- job_data[<span class="ruby-string">&quot;@type&quot;</span>] = <span class="ruby-string">&quot;acl&quot;</span>
377
- return controller.get_acl(job_data)
378
- elsif type == <span class="ruby-string">&quot;set-acl&quot;</span>
379
- job_data[<span class="ruby-string">&quot;@type&quot;</span>] = <span class="ruby-string">&quot;acl&quot;</span>
380
- return controller.set_acl(job_data)
381
- elsif type == <span class="ruby-string">&quot;compile&quot;</span>
382
- compiled_location = controller.compile_code(job_data)
383
-
384
- copy_to = job_data[<span class="ruby-string">&quot;@copy_to&quot;</span>]
385
-
386
- loop {
387
- ssh_command = &quot;ssh #{ssh_args} root@#{shadow_ip} 'ls #{compiled_location}' 2&gt;&amp;1&quot;
388
- <span class="ruby-comment">#puts ssh_command</span>
389
- result = `#{ssh_command}`
390
- <span class="ruby-comment">#puts &quot;result was [#{result}]&quot;</span>
391
- if result =~ <span class="ruby-regexp">/No such file or directory/</span>
392
- puts <span class="ruby-string">&quot;Still waiting for code to be compiled...&quot;</span>
393
- else
394
- puts &quot;compilation complete! Copying compiled code to #{copy_to}&quot;
395
- break
396
- end
397
- sleep(5)
398
- }
512
+ <div class="method-description">
513
+
514
+ <p>This method is the heart of Neptune - here, we take blocks of code that the
515
+ user has written and convert them into HPC job requests. At a high level,
516
+ the user can request to run a job, retrieve a job’s output, or modify the
517
+ access policy (ACL) for the output of a job. By default, job data is
518
+ private, but a Neptune job can be used to set it to public later (and
519
+ vice-versa).</p>
520
+
399
521
 
400
- rm_local = &quot;rm -rf #{copy_to}&quot;
401
- <span class="ruby-comment">#puts rm_local</span>
402
- `#{rm_local}`
522
+
523
+ <div class="method-source-code"
524
+ id="neptune-source">
525
+ <pre>
526
+ <span class="ruby-comment"># File lib/neptune.rb, line 368</span>
527
+ def neptune(params)
528
+ puts <span class="ruby-string">&quot;Received a request to run a job.&quot;</span>
529
+ puts params[:type]
403
530
 
404
- scp_command = &quot;scp -r #{ssh_args} root@#{shadow_ip}:#{compiled_location} #{copy_to} 2&gt;&amp;1&quot;
405
- puts scp_command
406
- `#{scp_command}`
531
+ job_data = get_job_data(params)
532
+ validate_storage_params(job_data)
533
+ puts &quot;job data = #{job_data.inspect}&quot;
534
+ do_preprocessing(job_data)
535
+ keyname = job_data[<span class="ruby-string">&quot;@keyname&quot;</span>]
407
536
 
408
- out = <span class="ruby-constant">File</span>.open(&quot;#{copy_to}/compile_out&quot;) { |f| f.read.chomp! }
409
- err = <span class="ruby-constant">File</span>.open(&quot;#{copy_to}/compile_err&quot;) { |f| f.read.chomp! }
410
- return {:out =&gt; out, :err =&gt; err }
411
- else
412
- result = controller.start_neptune_job(job_data)
413
- if result =~ <span class="ruby-regexp">/job is now running\Z/</span>
414
- return {:result =&gt; :success, :msg =&gt; result}
415
- else
416
- return {:result =&gt; :failure, :msg =&gt; result}
417
- end
418
- end
537
+ shadow_ip = <span class="ruby-constant">CommonFunctions</span>.get_from_yaml(keyname, :shadow)
538
+ secret = <span class="ruby-constant">CommonFunctions</span>.get_secret_key(keyname)
539
+ ssh_key = <span class="ruby-constant">File</span>.expand_path(&quot;~/.appscale/#{keyname}.key&quot;)
540
+ ssh_args = &quot;-i ~/.appscale/#{keyname}.key -o StrictHostkeyChecking=no &quot;
541
+
542
+ return run_job(job_data, ssh_args, shadow_ip, secret)
419
543
  end</pre>
420
544
  </div>
421
545
 
@@ -433,7 +557,7 @@ end</pre>
433
557
 
434
558
  <div class="method-heading">
435
559
  <span class="method-name">preprocess_compile</span><span
436
- class="method-args">(job_data)</span>
560
+ class="method-args">(job_data, shell=Kernel.method(:`))</span>
437
561
  <span class="method-click-advice">click to toggle source</span>
438
562
  </div>
439
563
 
@@ -449,10 +573,10 @@ copy over libraries as well.</p>
449
573
  <div class="method-source-code"
450
574
  id="preprocess_compile-source">
451
575
  <pre>
452
- <span class="ruby-comment"># File lib/neptune.rb, line 60</span>
453
- def preprocess_compile(job_data)
576
+ <span class="ruby-comment"># File lib/neptune.rb, line 65</span>
577
+ def preprocess_compile(job_data, shell=<span class="ruby-constant">Kernel</span>.method(:`))
454
578
  code = <span class="ruby-constant">File</span>.expand_path(job_data[<span class="ruby-string">&quot;@code&quot;</span>])
455
- unless <span class="ruby-constant">File</span>.exists?(code)
579
+ if !<span class="ruby-constant">File</span>.exists?(code)
456
580
  abort(&quot;The source file #{code} does not exist.&quot;)
457
581
  end
458
582
 
@@ -463,8 +587,8 @@ def preprocess_compile(job_data)
463
587
 
464
588
  ssh_args = &quot;-i ~/.appscale/#{keyname}.key -o StrictHostkeyChecking=no root@#{shadow_ip}&quot;
465
589
  remove_dir = &quot;ssh #{ssh_args} 'rm -rf #{dest}' 2&gt;&amp;1&quot;
466
- <span class="ruby-comment">#puts remove_dir</span>
467
- `#{remove_dir}`
590
+ puts remove_dir
591
+ shell.call(remove_dir)
468
592
 
469
593
  <span class="ruby-constant">CommonFunctions</span>.scp_to_shadow(code, dest, keyname, is_dir=true)
470
594
 
@@ -486,7 +610,7 @@ end</pre>
486
610
 
487
611
  <div class="method-heading">
488
612
  <span class="method-name">preprocess_erlang</span><span
489
- class="method-args">(job_data)</span>
613
+ class="method-args">(job_data, file=File, common_functions=CommonFunctions)</span>
490
614
  <span class="method-click-advice">click to toggle source</span>
491
615
  </div>
492
616
 
@@ -500,18 +624,21 @@ end</pre>
500
624
  <div class="method-source-code"
501
625
  id="preprocess_erlang-source">
502
626
  <pre>
503
- <span class="ruby-comment"># File lib/neptune.rb, line 81</span>
504
- def preprocess_erlang(job_data)
505
- source_code = <span class="ruby-constant">File</span>.expand_path(job_data[<span class="ruby-string">&quot;@code&quot;</span>])
506
- unless <span class="ruby-constant">File</span>.exists?(source_code)
507
- file_not_found = &quot;The specified code, #{job_data['@code']},&quot; +
508
- <span class="ruby-string">&quot; didn't exist. Please specify one that exists and try again&quot;</span>
509
- abort(file_not_found)
627
+ <span class="ruby-comment"># File lib/neptune.rb, line 86</span>
628
+ def preprocess_erlang(job_data, file=<span class="ruby-constant">File</span>, common_functions=<span class="ruby-constant">CommonFunctions</span>)
629
+ if !job_data[<span class="ruby-string">&quot;@code&quot;</span>]
630
+ abort(<span class="ruby-string">&quot;When running Erlang jobs, :code must be specified.&quot;</span>)
631
+ end
632
+
633
+ source_code = file.expand_path(job_data[<span class="ruby-string">&quot;@code&quot;</span>])
634
+ if !file.exists?(source_code)
635
+ abort(&quot;The specified code, #{job_data['@code']},&quot; +
636
+ <span class="ruby-string">&quot; didn't exist. Please specify one that exists and try again&quot;</span>)
510
637
  end
511
638
  dest_code = <span class="ruby-string">&quot;/tmp/&quot;</span>
512
639
 
513
640
  keyname = job_data[<span class="ruby-string">&quot;@keyname&quot;</span>]
514
- <span class="ruby-constant">CommonFunctions</span>.scp_to_shadow(source_code, dest_code, keyname)
641
+ common_functions.scp_to_shadow(source_code, dest_code, keyname)
515
642
  end</pre>
516
643
  </div>
517
644
 
@@ -523,12 +650,12 @@ end</pre>
523
650
  </div>
524
651
 
525
652
 
526
- <div id="preprocess_mapreduce-method" class="method-detail ">
527
- <a name="method-i-preprocess_mapreduce"></a>
653
+ <div id="preprocess_mpi-method" class="method-detail ">
654
+ <a name="method-i-preprocess_mpi"></a>
528
655
 
529
656
 
530
657
  <div class="method-heading">
531
- <span class="method-name">preprocess_mapreduce</span><span
658
+ <span class="method-name">preprocess_mpi</span><span
532
659
  class="method-args">(job_data)</span>
533
660
  <span class="method-click-advice">click to toggle source</span>
534
661
  </div>
@@ -536,38 +663,89 @@ end</pre>
536
663
 
537
664
  <div class="method-description">
538
665
 
539
- <p>This preprocessing method handles copying data for regular Hadoop MapReduce
540
- and Hadoop MapReduce Streaming. For the former case, we copy over just the
541
- JAR the user has given us, and in the latter case, we copy over the Map and
542
- Reduce files that have been specified. In either case, if the user has
543
- specified to us to copy over an input file, we do that as well: AppScale
544
- will copy it into HDFS for us.</p>
666
+ <p>This preprocessing method verifies that the user specified the number of
667
+ nodes to use. If they also specified the number of processes to use, we
668
+ also verify that this value is at least as many as the number of nodes
669
+ (that is, nodes can’t be underprovisioned in MPI).</p>
545
670
 
546
671
 
547
672
 
548
673
  <div class="method-source-code"
549
- id="preprocess_mapreduce-source">
674
+ id="preprocess_mpi-source">
550
675
  <pre>
551
- <span class="ruby-comment"># File lib/neptune.rb, line 101</span>
552
- def preprocess_mapreduce(job_data)
553
- return
554
- <span class="ruby-comment">#items_to_copy = [&quot;@map&quot;, &quot;@reduce&quot;] if job_data[&quot;@map&quot;] and job_data[&quot;@reduce&quot;]</span>
555
- items_to_copy = [<span class="ruby-string">&quot;@mapreducejar&quot;</span>] if job_data[<span class="ruby-string">&quot;@mapreducejar&quot;</span>]
556
- <span class="ruby-comment">#items_to_copy &lt;&lt; &quot;@input&quot; if job_data[&quot;@copy_input&quot;]</span>
557
- items_to_copy.each { |item|
558
- source = <span class="ruby-constant">File</span>.expand_path(job_data[item])
559
- unless <span class="ruby-constant">File</span>.exists?(source)
560
- abort(&quot;The #{item} file #{source} does not exist.&quot;)
676
+ <span class="ruby-comment"># File lib/neptune.rb, line 106</span>
677
+ def preprocess_mpi(job_data)
678
+ if !job_data[<span class="ruby-string">&quot;@nodes_to_use&quot;</span>]
679
+ abort(<span class="ruby-string">&quot;When running MPI jobs, :nodes_to_use must be specified.&quot;</span>)
680
+ end
681
+
682
+ if !job_data[<span class="ruby-string">&quot;@procs_to_use&quot;</span>]
683
+ abort(<span class="ruby-string">&quot;When running MPI jobs, :procs_to_use must be specified.&quot;</span>)
684
+ end
685
+
686
+ if job_data[<span class="ruby-string">&quot;@procs_to_use&quot;</span>]
687
+ p = job_data[<span class="ruby-string">&quot;@procs_to_use&quot;</span>]
688
+ n = job_data[<span class="ruby-string">&quot;@nodes_to_use&quot;</span>]
689
+ if p &lt; n
690
+ abort(<span class="ruby-string">&quot;When specifying both :procs_to_use and :nodes_to_use&quot;</span> +
691
+ <span class="ruby-string">&quot;, :procs_to_use must be at least as large as :nodes_to_use. Please &quot;</span> +
692
+ &quot;change this and try again. You specified :procs_to_use = #{p} and&quot; +
693
+ &quot;:nodes_to_use = #{n}.&quot;)
561
694
  end
695
+ end
696
+
697
+ return job_data
698
+ end</pre>
699
+ </div>
700
+
701
+ </div>
702
+
703
+
562
704
 
563
- suffix = source.split(<span class="ruby-string">'/'</span>)[-1]
564
- dest = &quot;/tmp/#{suffix}&quot;
705
+
706
+ </div>
565
707
 
566
- keyname = job_data[<span class="ruby-string">&quot;@keyname&quot;</span>]
567
- <span class="ruby-constant">CommonFunctions</span>.scp_to_shadow(source, dest, keyname)
708
+
709
+ <div id="preprocess_ssa-method" class="method-detail ">
710
+ <a name="method-i-preprocess_ssa"></a>
568
711
 
569
- job_data[item] = dest
570
- }
712
+
713
+ <div class="method-heading">
714
+ <span class="method-name">preprocess_ssa</span><span
715
+ class="method-args">(job_data)</span>
716
+ <span class="method-click-advice">click to toggle source</span>
717
+ </div>
718
+
719
+
720
+ <div class="method-description">
721
+
722
+ <p>This preprocessing method verifies that the user specified the number of
723
+ trajectories to run, via either :trajectories or :simulations. Both should
724
+ not be specified - only one or the other, and regardless of which they
725
+ specify, convert it to be :trajectories.</p>
726
+
727
+
728
+
729
+ <div class="method-source-code"
730
+ id="preprocess_ssa-source">
731
+ <pre>
732
+ <span class="ruby-comment"># File lib/neptune.rb, line 133</span>
733
+ def preprocess_ssa(job_data)
734
+ if job_data[<span class="ruby-string">&quot;@simulations&quot;</span>] and job_data[<span class="ruby-string">&quot;@trajectories&quot;</span>]
735
+ abort(<span class="ruby-string">&quot;Both :simulations and :trajectories cannot be specified - use one&quot;</span> +
736
+ <span class="ruby-string">&quot; or the other.&quot;</span>)
737
+ end
738
+
739
+ if job_data[<span class="ruby-string">&quot;@simulations&quot;</span>]
740
+ job_data[<span class="ruby-string">&quot;@trajectories&quot;</span>] = job_data[<span class="ruby-string">&quot;@simulations&quot;</span>]
741
+ job_data.delete(<span class="ruby-string">&quot;@simulations&quot;</span>)
742
+ end
743
+
744
+ if !job_data[<span class="ruby-string">&quot;@trajectories&quot;</span>]
745
+ abort(<span class="ruby-string">&quot;:trajectories needs to be specified when running ssa jobs&quot;</span>)
746
+ end
747
+
748
+ return job_data
571
749
  end</pre>
572
750
  </div>
573
751
 
@@ -579,12 +757,73 @@ end</pre>
579
757
  </div>
580
758
 
581
759
 
582
- <div id="preprocess_mpi-method" class="method-detail ">
583
- <a name="method-i-preprocess_mpi"></a>
760
+ <div id="run_job-method" class="method-detail ">
761
+ <a name="method-i-run_job"></a>
584
762
 
585
763
 
586
764
  <div class="method-heading">
587
- <span class="method-name">preprocess_mpi</span><span
765
+ <span class="method-name">run_job</span><span
766
+ class="method-args">(job_data, ssh_args, shadow_ip, secret, controller=AppControllerClient, file=File)</span>
767
+ <span class="method-click-advice">click to toggle source</span>
768
+ </div>
769
+
770
+
771
+ <div class="method-description">
772
+
773
+ <p>This method actually runs the Neptune job, given information about the job
774
+ as well as information about the node to send the request to.</p>
775
+
776
+
777
+
778
+ <div class="method-source-code"
779
+ id="run_job-source">
780
+ <pre>
781
+ <span class="ruby-comment"># File lib/neptune.rb, line 330</span>
782
+ def run_job(job_data, ssh_args, shadow_ip, secret,
783
+ controller=<span class="ruby-constant">AppControllerClient</span>, file=<span class="ruby-constant">File</span>)
784
+ controller = controller.new(shadow_ip, secret)
785
+
786
+ <span class="ruby-comment"># TODO - right now the job is assumed to succeed in many cases</span>
787
+ <span class="ruby-comment"># need to investigate the various failure scenarios</span>
788
+ result = { :result =&gt; :success }
789
+
790
+ case job_data[<span class="ruby-string">&quot;@type&quot;</span>]
791
+ when <span class="ruby-string">&quot;input&quot;</span>
792
+ result = get_input(job_data, ssh_args, shadow_ip, controller, file)
793
+ when <span class="ruby-string">&quot;output&quot;</span>
794
+ result[:output] = controller.get_output(job_data)
795
+ when <span class="ruby-string">&quot;get-acl&quot;</span>
796
+ job_data[<span class="ruby-string">&quot;@type&quot;</span>] = <span class="ruby-string">&quot;acl&quot;</span>
797
+ result[:acl] = controller.get_acl(job_data)
798
+ when <span class="ruby-string">&quot;set-acl&quot;</span>
799
+ job_data[<span class="ruby-string">&quot;@type&quot;</span>] = <span class="ruby-string">&quot;acl&quot;</span>
800
+ result[:acl] = controller.set_acl(job_data)
801
+ when <span class="ruby-string">&quot;compile&quot;</span>
802
+ result = compile_code(job_data, ssh_args, shadow_ip)
803
+ else
804
+ msg = controller.start_neptune_job(job_data)
805
+ result[:msg] = msg
806
+ result[:result] = :failure if result[:msg] !~ <span class="ruby-regexp">/job is now running\Z/</span>
807
+ end
808
+
809
+ return result
810
+ end</pre>
811
+ </div>
812
+
813
+ </div>
814
+
815
+
816
+
817
+
818
+ </div>
819
+
820
+
821
+ <div id="validate_storage_params-method" class="method-detail ">
822
+ <a name="method-i-validate_storage_params"></a>
823
+
824
+
825
+ <div class="method-heading">
826
+ <span class="method-name">validate_storage_params</span><span
588
827
  class="method-args">(job_data)</span>
589
828
  <span class="method-click-advice">click to toggle source</span>
590
829
  </div>
@@ -592,48 +831,99 @@ end</pre>
592
831
 
593
832
  <div class="method-description">
594
833
 
595
- <p>This preprocessing method copies over the user’s MPI code to the master
596
- node in AppScale - this node will then copy it to whoever will run the MPI
597
- job.</p>
834
+
598
835
 
599
836
 
600
837
 
601
838
  <div class="method-source-code"
602
- id="preprocess_mpi-source">
839
+ id="validate_storage_params-source">
603
840
  <pre>
604
- <span class="ruby-comment"># File lib/neptune.rb, line 125</span>
605
- def preprocess_mpi(job_data)
606
- if job_data[<span class="ruby-string">&quot;@procs_to_use&quot;</span>]
607
- p = job_data[<span class="ruby-string">&quot;@procs_to_use&quot;</span>]
608
- n = job_data[<span class="ruby-string">&quot;@nodes_to_use&quot;</span>]
609
- if p &lt; n
610
- not_enough_procs = <span class="ruby-string">&quot;When specifying both :procs_to_use and :nodes_to_use&quot;</span> +
611
- <span class="ruby-string">&quot;, :procs_to_use must be at least as large as :nodes_to_use. Please &quot;</span> +
612
- &quot;change this and try again. You specified :procs_to_use = #{p} and&quot; +
613
- &quot;:nodes_to_use = #{n}.&quot;
614
- abort(not_enough_procs)
615
- end
841
+ <span class="ruby-comment"># File lib/neptune.rb, line 186</span>
842
+ def validate_storage_params(job_data)
843
+ if !job_data[<span class="ruby-string">&quot;@storage&quot;</span>]
844
+ job_data[<span class="ruby-string">&quot;@storage&quot;</span>] = <span class="ruby-string">&quot;appdb&quot;</span>
616
845
  end
617
846
 
618
- source_code = <span class="ruby-constant">File</span>.expand_path(job_data[<span class="ruby-string">&quot;@code&quot;</span>])
619
- unless <span class="ruby-constant">File</span>.exists?(source_code)
620
- file_not_found = &quot;The specified code, #{source_code},&quot; +
621
- <span class="ruby-string">&quot; didn't exist. Please specify one that exists and try again&quot;</span>
622
- abort(file_not_found)
847
+ storage = job_data[<span class="ruby-string">&quot;@storage&quot;</span>]
848
+ if !<span class="ruby-constant">ALLOWED_STORAGE_TYPES</span>.include?(storage)
849
+ abort(&quot;Supported storage types are #{ALLOWED_STORAGE_TYPES.join(', ')}&quot; +
850
+ &quot; - we do not support #{storage}.&quot;)
623
851
  end
624
852
 
625
- unless <span class="ruby-constant">File</span>.file?(source_code)
626
- should_be_file = &quot;The specified code, #{source_code}, was not a file - &quot; +
627
- <span class="ruby-string">&quot; it was a directory or symbolic link. Please specify a file and try again.&quot;</span>
628
- abort(should_be_file)
853
+ <span class="ruby-comment"># Our implementation for storing / retrieving via Google Storage</span>
854
+ <span class="ruby-comment"># and Walrus uses</span>
855
+ <span class="ruby-comment"># the same library as we do for S3 - so just tell it that it's S3</span>
856
+ if storage == <span class="ruby-string">&quot;gstorage&quot;</span> or storage == <span class="ruby-string">&quot;walrus&quot;</span>
857
+ storage = <span class="ruby-string">&quot;s3&quot;</span>
858
+ job_data[<span class="ruby-string">&quot;@storage&quot;</span>] = <span class="ruby-string">&quot;s3&quot;</span>
859
+ end
860
+
861
+ if storage == <span class="ruby-string">&quot;s3&quot;</span>
862
+ [<span class="ruby-string">&quot;EC2_ACCESS_KEY&quot;</span>, <span class="ruby-string">&quot;EC2_SECRET_KEY&quot;</span>, <span class="ruby-string">&quot;S3_URL&quot;</span>].each { |item|
863
+ if job_data[&quot;@#{item}&quot;]
864
+ puts &quot;Using specified #{item}&quot;
865
+ else
866
+ if <span class="ruby-constant">ENV</span>[item]
867
+ puts &quot;Using #{item} from environment&quot;
868
+ job_data[&quot;@#{item}&quot;] = <span class="ruby-constant">ENV</span>[item]
869
+ else
870
+ abort(&quot;When storing data to S3, #{item} must be specified or be in &quot; +
871
+ <span class="ruby-string">&quot;your environment. Please do so and try again.&quot;</span>)
872
+ end
873
+ end
874
+ }
629
875
  end
630
876
 
631
- dest_code = <span class="ruby-string">&quot;/tmp/thempicode&quot;</span>
877
+ return job_data
878
+ end</pre>
879
+ </div>
880
+
881
+ </div>
882
+
883
+
632
884
 
633
- keyname = job_data[<span class="ruby-string">&quot;@keyname&quot;</span>]
634
- puts <span class="ruby-string">&quot;Copying over code...&quot;</span>
635
- <span class="ruby-constant">CommonFunctions</span>.scp_to_shadow(source_code, dest_code, keyname)
636
- puts <span class="ruby-string">&quot;Done copying code!&quot;</span>
885
+
886
+ </div>
887
+
888
+
889
+ <div id="wait_for_compilation_to_finish-method" class="method-detail ">
890
+ <a name="method-i-wait_for_compilation_to_finish"></a>
891
+
892
+
893
+ <div class="method-heading">
894
+ <span class="method-name">wait_for_compilation_to_finish</span><span
895
+ class="method-args">(ssh_args, shadow_ip, compiled_location, shell=Kernel.method(:`))</span>
896
+ <span class="method-click-advice">click to toggle source</span>
897
+ </div>
898
+
899
+
900
+ <div class="method-description">
901
+
902
+ <p>This method waits for AppScale to finish compiling the user’s code,
903
+ indicated by AppScale copying the finished code to a pre-determined
904
+ location.</p>
905
+
906
+
907
+
908
+ <div class="method-source-code"
909
+ id="wait_for_compilation_to_finish-source">
910
+ <pre>
911
+ <span class="ruby-comment"># File lib/neptune.rb, line 260</span>
912
+ def wait_for_compilation_to_finish(ssh_args, shadow_ip, compiled_location,
913
+ shell=<span class="ruby-constant">Kernel</span>.method(:`))
914
+ loop {
915
+ ssh_command = &quot;ssh #{ssh_args} root@#{shadow_ip} 'ls #{compiled_location}' 2&gt;&amp;1&quot;
916
+ puts ssh_command
917
+ ssh_result = shell.call(ssh_command)
918
+ puts &quot;result was [#{ssh_result}]&quot;
919
+ if ssh_result =~ <span class="ruby-regexp">/No such file or directory/</span>
920
+ puts <span class="ruby-string">&quot;Still waiting for code to be compiled...&quot;</span>
921
+ else
922
+ puts &quot;compilation complete! Copying compiled code to #{copy_to}&quot;
923
+ return
924
+ end
925
+ sleep(5)
926
+ }
637
927
  end</pre>
638
928
  </div>
639
929