nera 0.0.4 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/History.txt CHANGED
@@ -1,3 +1,9 @@
1
+ == 0.1.0
2
+ * 1 major enahncement:
3
+ * remote connection function is supported
4
+ * 2 bug fixes
5
+ * bug fix for multi-lined job scripts.
6
+
1
7
  == 0.0.4
2
8
  * 1 major enhancement:
3
9
  * multi-lined simulation command becomes available
data/Manifest.txt CHANGED
@@ -3,6 +3,7 @@ Manifest.txt
3
3
  README.rdoc
4
4
  Rakefile
5
5
  bin/nera
6
+ bin/nera_addhost
6
7
  bin/nera_addsim
7
8
  lib/nera.rb
8
9
  lib/nera/nera_cui.rb
@@ -14,11 +15,13 @@ lib/nera/nera_job_records.rb
14
15
  lib/nera/nera_job_script.rb
15
16
  lib/nera/nera_parameter_layer_controller.rb
16
17
  lib/nera/nera_parameter_records.rb
18
+ lib/nera/nera_remote_connector.rb
17
19
  lib/nera/nera_run_layer_controller.rb
18
20
  lib/nera/nera_run_records.rb
19
21
  lib/nera/nera_simulator.rb
20
22
  lib/nera/nera_simulator_layer_controller.rb
21
23
  lib/nera/nera_simulator_records.rb
24
+ lib/nera_addhost/add_hosts.rb
22
25
  lib/nera_addsim/make_simulator.rb
23
26
  scripts/console
24
27
  scripts/destroy
@@ -33,6 +36,7 @@ test/test_nera_job_layer_controller.rb
33
36
  test/test_nera_job_records.rb
34
37
  test/test_nera_parameter_layer_controller.rb
35
38
  test/test_nera_parameter_records.rb
39
+ test/test_nera_remote_connector.rb
36
40
  test/test_nera_run_layer_controller.rb
37
41
  test/test_nera_run_records.rb
38
42
  test/test_nera_simulator.rb
data/README.rdoc CHANGED
@@ -17,6 +17,10 @@ To add your own simulators,
17
17
 
18
18
  nera_addsim 'neradb'
19
19
 
20
+ To edit your host informations,
21
+
22
+ nera_addhost 'neradb'
23
+
20
24
  == REQUIREMENTS:
21
25
 
22
26
  Ruby 1.8.0 or later
data/Rakefile CHANGED
@@ -7,9 +7,9 @@ $hoe = Hoe.new('nera', NERA::VERSION) do |p|
7
7
  p.developer('Yohsuke Murase', 'murase@serow.t.u-tokyo.ac.jp')
8
8
  p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
9
9
  p.rubyforge_name = p.name # TODO this is default value
10
- # p.extra_deps = [
11
- # ['activesupport','>= 2.0.2'],
12
- # ]
10
+ p.extra_deps = [
11
+ ['net-ssh','>= 2.0.11'],
12
+ ]
13
13
  p.extra_dev_deps = [
14
14
  ['newgem', ">= #{::Newgem::VERSION}"]
15
15
  ]
data/bin/nera_addhost ADDED
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Created by Yohsuke Murase on 2009-4-28.
4
+ # Copyright (c) 2009. All rights reserved.
5
+ require 'optparse'
6
+ require File.expand_path(File.dirname(__FILE__) + "/../lib/nera")
7
+
8
+ parser = OptionParser.new do |opts|
9
+ opts.banner = <<-BANNER.gsub(/^ /,'')
10
+
11
+ Usage: #{File.basename($0)} [options] 'nera_db_folder'
12
+
13
+ BANNER
14
+ opts.separator ""
15
+ opts.on("-h", "--help",
16
+ "Show this help message.") { $stdout.puts opts; exit }
17
+ opts.on("-v", "--version", "Show version.") { $stdout.puts NERA::VERSION; exit}
18
+ opts.parse!(ARGV)
19
+ end
20
+
21
+ unless ARGV.size == 1
22
+ raise "\n\nUsage :\t nera_addhost 'nera_db_folder'"
23
+ end
24
+
25
+ require File.expand_path(File.dirname(__FILE__) + "/../lib/nera_addhost/add_hosts")
26
+ NERA::CUI_Hosts_Editor.new(ARGV[0])
data/lib/nera/nera_cui.rb CHANGED
@@ -351,9 +351,13 @@ HEADER
351
351
  action_list = ["Back to simulator layer",
352
352
  "Show job infos",
353
353
  "Cancel jobs",
354
+ "Show host infos",
355
+ "Upload jobs",
356
+ "Download data",
354
357
  "Include data",
355
358
  "Exit"]
356
359
  jlc = NERA::JobLayerController.new( @path_db_folder)
360
+ rc = NERA::RemoteConnector.new( @path_db_folder)
357
361
 
358
362
  selected = 0
359
363
  Dir.chdir( jlc.path_to_job_layer) {
@@ -388,6 +392,80 @@ HEADER
388
392
  end
389
393
  end
390
394
  return :job_layer
395
+ when "Show host infos"
396
+ h_list = ["Cancel", "All"] + rc.hostnames
397
+ sel = Dialog::select_many( h_list)
398
+ if sel.include?(0)
399
+ return :job_layer
400
+ elsif sel.include?(1)
401
+ rc.hostnames.each do |hname|
402
+ Dialog::message("Information of the host #{hname} =========================")
403
+ Dialog::message( rc.show_status( hname) )
404
+ end
405
+ else
406
+ sel.each do |num|
407
+ Dialog::message("Information of the host #{h_list[num]} =========================")
408
+ Dialog::message( rc.show_status( h_list[num]) )
409
+ end
410
+ end
411
+ return :job_layer
412
+ when "Upload jobs"
413
+ header,list = jlc.not_finished_list_in_csv
414
+ list.unshift("Cancel")
415
+ selected_jobs = Dialog::select_many( list, header).map do |num|
416
+ list[num].split(',')[0].to_i
417
+ end
418
+ return :job_layer if selected_jobs.include?(0)
419
+
420
+ h_list = ["Cancel"] + rc.hostnames
421
+ sel = Dialog::select_one( h_list, "Select the host")
422
+ return :job_layer if sel == 0
423
+ selected_host = h_list[sel]
424
+
425
+ Dialog::message("Information of the host #{selected_host} =========================")
426
+ Dialog::message( rc.show_status( selected_host) + "\n" )
427
+ if Dialog::ask("Will you upload the script?", true)
428
+ if rc.submittable_hostnames.include?(selected_host) and Dialog::ask("Will you submit the jobs?", true)
429
+ v = rc.submit( selected_jobs, selected_host)
430
+ Dialog::message(v.to_s)
431
+ else
432
+ v = rc.transfer( selected_jobs, selected_host)
433
+ Dialog::message(v.to_s)
434
+ end
435
+ end
436
+ return :job_layer
437
+ when "Download data"
438
+ d_hash = rc.check_completion_all
439
+ list = ["Cancel", "All"]
440
+ d_hash.each_pair do |host, d_files|
441
+ if d_files.is_a?(Array)
442
+ d_files.each do |f|
443
+ list << "#{f} @ #{host}"
444
+ end
445
+ end
446
+ end
447
+ sel = Dialog::select_many( list)
448
+ if sel.include?(0)
449
+ return :job_layer
450
+ elsif sel.include?(1)
451
+ d_hash.each_pair do |host, d_files|
452
+ res = rc.download( d_files, host)
453
+ if res.is_a?(Array)
454
+ Dialog::message("#{res.join(', ')} have been downloaded.")
455
+ else
456
+ Dialog::message(res.to_s)
457
+ end
458
+ end
459
+ else
460
+ downloaded = []
461
+ sel.each do |num|
462
+ a = list[num].split('@')
463
+ res = rc.download( [ a[0].strip ], a[1].strip)
464
+ downloaded += res if res.is_a?(Array)
465
+ end
466
+ Dialog::message("#{downloaded.join(', ')} have been downloaded.")
467
+ end
468
+ return :job_layer
391
469
  when "Include data"
392
470
  list = jlc.include_list
393
471
  list = ["Cancel","All"] + list
@@ -220,7 +220,11 @@ module NERA
220
220
  def path_to_finished_jobs_file
221
221
  return @db_folder + "Tables/finished_jobs.yml"
222
222
  end
223
-
223
+
224
+ def path_to_hosts_yaml
225
+ return @db_folder + "Tables/hosts.yml"
226
+ end
227
+
224
228
  end
225
229
  end
226
230
 
@@ -200,6 +200,33 @@ module Dialog
200
200
  end
201
201
  end
202
202
  end
203
+
204
+ # -----------------
205
+ def ask( message = "Input y or n.", default = true)
206
+ while true
207
+ m = "(y/N)"
208
+ m = "(Y/n)" if default
209
+ $stdout.puts( "#{message} : #{m}")
210
+
211
+ buf = Readline.readline(PROMPT).chomp.strip.downcase
212
+ if buf == ''
213
+ if default
214
+ return true
215
+ else
216
+ return false
217
+ end
218
+ end
219
+
220
+ if buf.match(/^y$/) or buf.match(/^yes$/)
221
+ return true
222
+ elsif buf.match(/^n$/) or buf.match(/^no$/)
223
+ return false
224
+ else
225
+ $stdout.puts "The input is not valid. Try again"
226
+ redo
227
+ end
228
+ end
229
+ end
203
230
 
204
- module_function :select_one, :select_one_or_return_string, :select_many, :message, :set_multiple_values, :get_integer
231
+ module_function :select_one, :select_one_or_return_string, :select_many, :message, :set_multiple_values, :get_integer, :ask
205
232
  end
@@ -66,7 +66,7 @@ echo \"NERA_START_AT\" >> nera_status.rb
66
66
  echo \"#{job_info[:execs][i]}\"
67
67
  mkdir -p #{run_id}
68
68
  cd #{run_id}
69
- { time -p #{job_info[:execs][i]}; } 2>> ../nera_status.rb
69
+ { time -p { #{job_info[:execs][i]};} } 2>> ../nera_status.rb
70
70
  if test $? -ne 0; then { echo \"Exit abnormally!\" >> ../nera_status.rb; exit; } fi
71
71
  cd ..
72
72
  echo \"NERA_OUTPUT\" >> nera_status.rb
@@ -146,7 +146,7 @@ BODY
146
146
  :run_ids => run_ids,
147
147
  :seeds => seeds,
148
148
  :execs => seeds.map do |sed|
149
- sim_inst.simulate_command( sed).split("\n").join('; ').sub(/;$/,'')
149
+ sim_inst.simulate_command( sed).split("\n").join(' && ').sub(/;$/,'')
150
150
  end
151
151
  }
152
152
 
@@ -0,0 +1,337 @@
1
+ require 'nera_db_folders'
2
+ require 'nera_job_records'
3
+ require 'nera_job_script'
4
+ require 'fileutils'
5
+ require 'yaml'
6
+ require 'rubygems'
7
+ require 'net/ssh'
8
+ require 'net/sftp'
9
+
10
+ module NERA
11
+
12
+ # A class for remote connection
13
+ class RemoteConnector
14
+
15
+ # instance of NERA::DbFolders
16
+ @db_folders
17
+ # instance of NERA::JobRecords
18
+ @job_records
19
+ # hosts (Array of Hashes)
20
+ @hosts
21
+
22
+ public
23
+ def initialize( path_db_folder)
24
+ raise ArgumentError unless path_db_folder.is_a?(String)
25
+
26
+ @db_folders = NERA::DbFolders.new( path_db_folder)
27
+ if File.exist?( @db_folders.path_to_hosts_yaml)
28
+ File.open( @db_folders.path_to_hosts_yaml, 'r') do |io|
29
+ @hosts = YAML.load( io)
30
+ end
31
+ else
32
+ @hosts = []
33
+ end
34
+ raise "Invalid format of hosts.yml" unless valid_hosts?
35
+ @job_records = NERA::JobRecords.new( @db_folders.path_to_jobs_table)
36
+ end
37
+
38
+ private
39
+ def valid_hosts?
40
+ @hosts.each do |host|
41
+ return false unless host.has_key?(:name)
42
+ return false unless host[:name].is_a?(String)
43
+ return false unless host.has_key?(:host_url)
44
+ return false unless host[:host_url].is_a?(String)
45
+ return false unless host.has_key?(:user)
46
+ return false unless host[:user].is_a?(String)
47
+ host[:job_path] = '~/' unless host.has_key?(:job_path)
48
+ host[:port] = 22 unless host.has_key?(:port)
49
+ end
50
+ end
51
+
52
+ public
53
+ def hostnames
54
+ @hosts.map do |host| host[:name] end
55
+ end
56
+
57
+ def submittable_hostnames
58
+ arr = []
59
+ @hosts.each do |host|
60
+ arr << host[:name] if host[:submission_command]
61
+ end
62
+ return arr
63
+ end
64
+
65
+ def show_status( hostname)
66
+ found = @hosts.find do |host|
67
+ host[:name] == hostname
68
+ end
69
+ return :connection_failed unless found
70
+ h = { :port => found[:port], :timeout => 10 }
71
+ h[:keys] = found[:keys] if found.has_key?(:keys)
72
+ cmd = 'ps au'
73
+ cmd = found[:show_status_command] if found.has_key?(:show_status_command)
74
+ str = ''
75
+ begin
76
+ $stderr.print "Connecting with #{found[:name]}.....\t"
77
+ Net::SSH.start( found[:host_url], found[:user], h) do |ssh|
78
+ str = ssh.exec!( cmd)
79
+ end
80
+ rescue Errno::ECONNREFUSED
81
+ $stderr.puts "failed"
82
+ return :connection_failed
83
+ rescue Errno::ENETUNREACH
84
+ $stderr.puts "failed"
85
+ return :connection_failed
86
+ rescue Net::SSH::Exception
87
+ $stderr.puts "failed"
88
+ return :connection_failed
89
+ rescue SocketError
90
+ $stderr.puts "failed"
91
+ return :connection_failed
92
+ end
93
+ $stderr.puts "done"
94
+ return str
95
+ end
96
+
97
+ def transfer( jobids, hostname)
98
+ raise ArgumentError unless jobids.is_a?(Array)
99
+ jobids.each do |jid|
100
+ raise ArgumentError unless jid.is_a?(Integer)
101
+ end
102
+ raise ArgumentError unless hostname.is_a?(String)
103
+
104
+ host = @hosts.find do |h| h[:name] == hostname end
105
+ return :connection_failed unless host
106
+
107
+ @job_records.transaction {
108
+ jids = []
109
+ jobids.each do |jid|
110
+ jids << jid if @job_records.find_by_id(jid)
111
+ end
112
+ return :no_such_jobs if jids.size == 0
113
+
114
+ h = { :port => host[:port] }
115
+ h[:keys] = host[:keys] if host.has_key?(:keys)
116
+
117
+ begin
118
+ $stderr.print "Connecting with #{host[:name]}.....\t"
119
+ Net::SSH.start( host[:host_url], host[:user], h) do |ssh|
120
+ ssh.exec("mkdir -p #{host[:job_path]}")
121
+ target_home = ssh.exec!('echo $HOME').chomp
122
+ target_dir = host[:job_path].sub(/^~/,target_home)
123
+ ssh.sftp.connect do |sftp|
124
+ jids.each do |jid|
125
+ pjs = @db_folders.path_to_job_script(jid)
126
+ target_path = target_dir + '/' + File.basename(pjs)
127
+ next unless File.exist?( pjs)
128
+ contents = ''
129
+ File.open( pjs, 'r') do |io| contents = io.readlines end
130
+ contents[0] += "cd #{target_dir}\n"
131
+ sftp.file.open(target_path, "w") do |f| f.puts contents end
132
+ ssh.exec!("chmod +x #{target_path}")
133
+ @job_records.update_to_state_copied( jid, host[:name])
134
+ end
135
+ end
136
+ end
137
+ rescue Errno::ECONNREFUSED
138
+ $stderr.puts "failed"
139
+ return :connection_failed
140
+ rescue Errno::ENETUNREACH
141
+ $stderr.puts "failed"
142
+ return :connection_failed
143
+ rescue SocketError
144
+ $stderr.puts "failed"
145
+ return :connection_failed
146
+ rescue Net::SSH::Exception
147
+ $stderr.puts "failed"
148
+ return :connection_failed
149
+ end
150
+ $stderr.puts "done"
151
+ }
152
+ return :succeeded
153
+ end
154
+
155
+ private
156
+ def convert_shell_script
157
+
158
+ end
159
+
160
+ public
161
+ def submit( jobids, hostname)
162
+ raise ArgumentError unless jobids.is_a?(Array)
163
+ jobids.each do |jid|
164
+ raise ArgumentError unless jid.is_a?(Integer)
165
+ end
166
+ raise ArgumentError unless hostname.is_a?(String)
167
+
168
+ host = @hosts.find do |h| h[:name] == hostname end
169
+ return :connection_failed unless host
170
+
171
+ return :no_submission_command unless host.has_key?(:submission_command)
172
+
173
+ @job_records.transaction {
174
+ jids = []
175
+ jobids.each do |jid|
176
+ jids << jid if @job_records.find_by_id(jid)
177
+ end
178
+ return :no_such_jobs if jids.size == 0
179
+
180
+ h = { :port => host[:port] }
181
+ h[:keys] = host[:keys] if host.has_key?(:keys)
182
+
183
+ begin
184
+ $stderr.print "Connecting with #{host[:name]}.....\t"
185
+ Net::SSH.start( host[:host_url], host[:user], h) do |ssh|
186
+ ssh.exec("mkdir -p #{host[:job_path]}")
187
+ target_home = ssh.exec!('echo $HOME').chomp
188
+ target_dir = host[:job_path].sub(/^~/,target_home)
189
+ ssh.sftp.connect do |sftp|
190
+ jids.each do |jid|
191
+ pjs = @db_folders.path_to_job_script(jid)
192
+ next unless File.exist?( pjs)
193
+ target_path = target_dir + '/' + File.basename(pjs)
194
+ contents = ''
195
+ File.open( pjs, 'r') do |io| contents = io.readlines end
196
+ contents[0] += "cd #{target_dir}\n"
197
+ sftp.file.open(target_path, "w") do |f| f.puts contents end
198
+ ssh.exec!("chmod +x #{target_path}")
199
+ @job_records.update_to_state_copied( jid, host[:name])
200
+ ssh.exec!("cd #{target_dir} && #{host[:submission_command]} #{target_path} &")
201
+ @job_records.update_to_state_submitted( jid, host[:name])
202
+ end
203
+ end
204
+ end
205
+ rescue Errno::ECONNREFUSED
206
+ $stderr.puts "failed"
207
+ return :connection_failed
208
+ rescue Errno::ENETUNREACH
209
+ $stderr.puts "failed"
210
+ return :connection_failed
211
+ rescue SocketError
212
+ $stderr.puts "failed"
213
+ return :connection_failed
214
+ rescue Net::SSH::Exception
215
+ $stderr.puts "failed"
216
+ return :connection_failed
217
+ end
218
+ $stderr.puts "done"
219
+ }
220
+ return :succeeded
221
+ end
222
+
223
+ def check_completion( hostname)
224
+ raise ArgumentError unless hostname.is_a?(String)
225
+
226
+ host = @hosts.find do |h| h[:name] == hostname end
227
+ return :connection_failed unless host
228
+
229
+ h = { :port => host[:port] }
230
+ h[:keys] = host[:keys] if host.has_key?(:keys)
231
+
232
+ ls_str = ''
233
+ begin
234
+ $stderr.print "Connecting with #{host[:name]}.....\t"
235
+ Net::SSH.start( host[:host_url], host[:user], h) do |ssh|
236
+ ls_str = ssh.exec!("ls #{host[:job_path]}")
237
+ end
238
+ rescue Errno::ECONNREFUSED
239
+ $stderr.puts "failed"
240
+ return :connection_failed
241
+ rescue Errno::ENETUNREACH
242
+ $stderr.puts "failed"
243
+ return :connection_failed
244
+ rescue SocketError
245
+ $stderr.puts "failed"
246
+ return :connection_failed
247
+ rescue Net::SSH::Exception
248
+ $stderr.puts "failed"
249
+ return :connection_failed
250
+ end
251
+ $stderr.puts "done"
252
+ return finished_list( ls_str)
253
+ end
254
+
255
+ private
256
+ def finished_list( ls_str)
257
+ ls_list = ls_str.to_s.split("\n")
258
+ return ls_list.find_all do |fname|
259
+ flag = false
260
+ if fname =~ /^(j[0-9]+).tar.bz2$/
261
+ flag = true unless ls_list.find do |f| f == $1 end
262
+ end
263
+ flag
264
+ end
265
+ end
266
+
267
+ public
268
+ def check_completion_all
269
+ h = {}
270
+ hostnames.each do |hname|
271
+ h[hname] = check_completion(hname)
272
+ end
273
+ return h
274
+ end
275
+
276
+
277
+ def download( filenames, hostname)
278
+ raise ArgumentError unless filenames.is_a?(Array)
279
+ filenames.each do |fname|
280
+ raise ArgumentError unless fname.is_a?(String)
281
+ raise ArgumentError unless fname =~ /.tar.bz2$/
282
+ end
283
+ raise ArgumentError unless hostname.is_a?(String)
284
+
285
+ host = @hosts.find do |h| h[:name] == hostname end
286
+ return :connection_failed unless host
287
+
288
+ h = { :port => host[:port] }
289
+ h[:keys] = host[:keys] if host.has_key?(:keys)
290
+
291
+ downloaded = []
292
+
293
+ begin
294
+ $stderr.puts "Connecting with #{host[:name]}.....\t"
295
+ Net::SSH.start( host[:host_url], host[:user], h) do |ssh|
296
+ target_home = ssh.exec!('echo $HOME').chomp
297
+ target_dir = host[:job_path].sub(/^~/,target_home)
298
+ ls_str = ssh.exec!("ls #{target_dir}")
299
+ d_list = filenames.find_all do |fname| ls_str.include?( fname) end
300
+ ssh.sftp.connect do |sftp|
301
+ d_list.each do |d_file|
302
+ #download
303
+ $stderr.print " downloading #{d_file}.....\t"
304
+ sftp.download!( target_dir + '/' + d_file, @db_folders.path_to_include_layer + d_file)
305
+ $stderr.puts "done"
306
+ downloaded << d_file
307
+ #delete data file and job script
308
+ $stderr.print " deleting #{d_file}.....\t"
309
+ sftp.remove!(target_dir + '/' + d_file)
310
+ $stderr.puts "done"
311
+ sh_file = d_file.sub(/tar.bz2$/,'sh')
312
+ $stderr.print " deleting #{sh_file}.....\t"
313
+ sftp.remove!(target_dir + '/' + sh_file)
314
+ $stderr.puts "done"
315
+ end
316
+ end
317
+ end
318
+ rescue Errno::ECONNREFUSED
319
+ $stderr.puts "failed"
320
+ return :connection_failed
321
+ rescue Errno::ENETUNREACH
322
+ $stderr.puts "failed"
323
+ return :connection_failed
324
+ rescue SocketError
325
+ $stderr.puts "failed"
326
+ return :connection_failed
327
+ rescue Net::SSH::Exception
328
+ $stderr.puts "failed"
329
+ return :connection_failed
330
+ end
331
+ $stderr.puts "done"
332
+
333
+ return downloaded
334
+ end
335
+
336
+ end
337
+ end
data/lib/nera.rb CHANGED
@@ -19,7 +19,8 @@ require 'nera_run_records'
19
19
  require 'nera_simulator'
20
20
  require 'nera_simulator_layer_controller'
21
21
  require 'nera_simulator_records'
22
+ require 'nera_remote_connector'
22
23
 
23
24
  module NERA
24
- VERSION = '0.0.4'
25
+ VERSION = '0.1.0'
25
26
  end
@@ -0,0 +1,193 @@
1
+ require 'nera_dialog'
2
+ require 'yaml'
3
+ require 'fileutils'
4
+
5
+ module NERA
6
+
7
+ class CUI_Hosts_Editor
8
+
9
+ HOST_INFO = [ [:host_url,String,"localhost"], [:user,String,ENV['USER']], [:job_path,String,"~/"],
10
+ [:port,Integer,22], [:keys,String,"~/.ssh/id_rsa"],
11
+ [:submission_command,String,"nohup"], [:show_status_command,String,"ps au"]]
12
+
13
+
14
+ #----- the unique module funciton -----
15
+ def initialize( db_folder_path)
16
+ unless valid_nera_db?( db_folder_path)
17
+ raise "\n\n#{db_folder_path} is not a valid nera_db folder."
18
+ end
19
+
20
+ dbf = NERA::DbFolders.new( db_folder_path)
21
+ @@hosts = Hash.new
22
+ h_yml = dbf.path_to_hosts_yaml
23
+ @@hosts = YAML.load( File.open( h_yml,'r') ) if File.exists?( h_yml)
24
+
25
+ edit_hosts_yaml
26
+ YAML.dump( @@hosts, File.open(h_yml,'w') )
27
+ end
28
+
29
+ private
30
+ #------- private methods ------------
31
+ def valid_nera_db?( db_folder_path)
32
+ return false unless File.directory?( db_folder_path)
33
+ return false unless File.directory?( db_folder_path + '/Tables/')
34
+ return false unless File.directory?( db_folder_path + '/Jobs/')
35
+ return false unless File.directory?( db_folder_path + '/Simulator_classes/')
36
+ return false unless File.exist?( db_folder_path + '/simulators.yml')
37
+ return true
38
+ end
39
+
40
+ def edit_hosts_yaml
41
+ loop do
42
+ names = @@hosts.map do |host| host[:name] end
43
+ names = [:"add a new host"] + names + [:exit]
44
+ sel = Dialog::select_one( names, "Select the host to edit.")
45
+ case names[sel]
46
+ when :"add a new host"
47
+ add_a_new_host
48
+ when :exit
49
+ return true
50
+ else
51
+ edit_host_info( names[sel])
52
+ end
53
+ end
54
+ end
55
+
56
+ def add_a_new_host
57
+ $stdout.puts <<HEA
58
+ ==========================================
59
+ Enter the new hostname (1/3)
60
+ ==========================================
61
+ HEA
62
+ used_names = @@hosts.map do |host| host[:name] end
63
+ name = Readline.readline(">").chomp.strip
64
+ while name.size == 0 or used_names.include?(name)
65
+ $stdout.puts "The given hostname is not valid."
66
+ name = Readline.readline(">").chomp.strip
67
+ end
68
+ new_host = { :name => name}
69
+
70
+ $stdout.puts <<HEA
71
+ ==========================================
72
+ Edit the host information of #{name} (2/3)
73
+ ==========================================
74
+ HEA
75
+ info = Dialog.set_multiple_values( HOST_INFO, "Set host information")
76
+ new_host.merge!( info)
77
+
78
+ $stdout.puts <<HEA
79
+ ==========================================
80
+ Check connection with #{name} (3/3)
81
+ ==========================================
82
+ HEA
83
+ h = { :port => new_host[:port], :keys => new_host[:keys] }
84
+ flag = false
85
+ begin
86
+ Net::SSH.start( new_host[:host_url], new_host[:user], h) do |ssh|
87
+ $stdout.puts ssh.exec!( new_host[:show_status_command])
88
+ end
89
+ rescue Errno::ECONNREFUSED then
90
+ puts "Connection refused. Check server state again."
91
+ flag = false
92
+ rescue Errno::ENETUNREACH then
93
+ puts "Network is unreachable."
94
+ flag = false
95
+ rescue SocketError then
96
+ puts "Can not resolve host name. Is network active?"
97
+ flag = false
98
+ rescue Net::SSH::Exception then
99
+ puts "Connection failed."
100
+ flag = false
101
+ rescue Exception then
102
+ puts "Conncetion error."
103
+ flag = false
104
+ else
105
+ puts "Connect successfully."
106
+ flag = true
107
+ end
108
+
109
+ unless flag
110
+ unless Dialog::ask( "Do you continue anyway?", true)
111
+ $stdout.puts "Addition of #{name} is aborted."
112
+ return nil
113
+ end
114
+ end
115
+
116
+ @@hosts << new_host
117
+ $stdout.puts <<HEA
118
+ ==========================================
119
+ Host #{name} is successfully added.
120
+ ==========================================
121
+ HEA
122
+ end
123
+
124
+ # ==============================
125
+ def edit_host_info( hostname)
126
+ $stdout.puts <<HEA
127
+ ==========================================
128
+ Edit the host information of #{hostname} (1/2)
129
+ ==========================================
130
+ HEA
131
+ h_info = HOST_INFO.dup
132
+ found = @@hosts.find do |h| h[:name] == hostname end
133
+ h_info.each_with_index do |info,i|
134
+ if found[info[0]]
135
+ info[2] = found[info[0]]
136
+ else
137
+ info[2] = HOST_INFO[i][2]
138
+ end
139
+ end
140
+
141
+ new_host = Dialog.set_multiple_values( h_info, "Set host information")
142
+ new_host[:name] = hostname
143
+
144
+ $stdout.puts <<HEA
145
+ ==========================================
146
+ Check connection with #{hostname} (2/2)
147
+ ==========================================
148
+ HEA
149
+ h = { :port => new_host[:port], :keys => new_host[:keys] }
150
+ flag = false
151
+ begin
152
+ Net::SSH.start( new_host[:host_url], new_host[:user], h) do |ssh|
153
+ $stdout.puts ssh.exec!( new_host[:show_status_command])
154
+ end
155
+ rescue Errno::ECONNREFUSED then
156
+ puts "Connection refused. Check server state again."
157
+ flag = false
158
+ rescue Errno::ENETUNREACH then
159
+ puts "Network is unreachable."
160
+ flag = false
161
+ rescue SocketError then
162
+ puts "Can not resolve host name. Is network active?"
163
+ flag = false
164
+ rescue Net::SSH::Exception then
165
+ puts "Connection failed."
166
+ flag = false
167
+ rescue Exception then
168
+ puts "Conncetion error."
169
+ flag = false
170
+ else
171
+ puts "Connect successfully."
172
+ flag = true
173
+ end
174
+
175
+ unless flag
176
+ unless Dialog::ask( "Do you continue anyway?", true)
177
+ $stdout.puts "Addition of #{name} is aborted."
178
+ return nil
179
+ end
180
+ end
181
+
182
+ idx = @@hosts.index do |h| h[:name] == hostname end
183
+ @@hosts[idx] = new_host.dup
184
+ $stdout.puts <<HEA
185
+ ==========================================
186
+ Information of #{hostname} is successfully updated.
187
+ ==========================================
188
+ HEA
189
+
190
+ end
191
+
192
+ end
193
+ end
@@ -205,5 +205,10 @@ class TC_NERA_DB_FOLDERS < Test::Unit::TestCase
205
205
  assert_equal( @db_folder+"/Tables/finished_jobs.yml", p)
206
206
  end
207
207
 
208
+ def test_path_to_hosts_yaml
209
+ p = @dbf.path_to_hosts_yaml
210
+ assert_equal( @db_folder+"/Tables/hosts.yml",p)
211
+ end
212
+
208
213
  end
209
214
 
@@ -130,5 +130,11 @@ class TC_NERA_DIALOG < Test::Unit::TestCase
130
130
  Dialog::get_integer( "Input a number", "hoge")
131
131
  }
132
132
  end
133
-
134
- end
133
+
134
+ def test_ask
135
+ s = Dialog::ask("Input yes or no", true)
136
+ assert_equal( s, true)
137
+ s = Dialog::ask("Input yes or no", false)
138
+ assert_equal( s, false)
139
+ end
140
+ end
@@ -32,7 +32,7 @@ class TC_NERA_JOB_LAYER_CONTROLLER < Test::Unit::TestCase
32
32
  def test_path_to_job_layer
33
33
  assert_equal( @dbf.path_to_job_layer, @jlc.path_to_job_layer)
34
34
  end
35
-
35
+
36
36
  def test_not_finished_list_in_csv
37
37
  h, l = @jlc.not_finished_list_in_csv
38
38
  assert_equal( "id, state, simulator, param_id, run_id, num_runs, created_at, updated_at, host_name", h)
@@ -0,0 +1,239 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class TC_NERA_RM_CONNECTOR < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @testdir = 'test_remote_connector'
7
+ FileUtils.mkdir(@testdir)
8
+ FileUtils.chdir(@testdir)
9
+ @db_folder = "nera_db"
10
+ NERA::DbFolders.create_db( @db_folder)
11
+ @dbf = NERA::DbFolders.new( @db_folder)
12
+ @slc = NERA::SimulatorLayerController.new( @db_folder)
13
+ @plc = NERA::ParameterLayerController.new( @db_folder, Ising)
14
+ pid = @plc.create_a_new_parameter_set({:L => 32, :K => 0.01, :tmax => 1})
15
+ @rlc = NERA::RunLayerController.new( @db_folder, Ising, pid)
16
+ @rlc.create_jobs( 3, 1)
17
+ @jlc = NERA::JobLayerController.new( @db_folder)
18
+
19
+ @hosts = []
20
+ @hosts << { :name => "localhost",:host_url => "localhost",:user => ENV['USER'], :job_path => FileUtils.pwd + '/job1'}
21
+ @hosts << { :name => "localhost_submittable",:host_url => "localhost",:user => ENV['USER'], :job_path => FileUtils.pwd + '/job2', :submission_command => "nohup", :show_status_command => 'ps au' }
22
+ @hosts << { :name => "unconnectable",:host_url => "unconnectable_host",:user => "hoge", :job_path => '~/job_test', :submission_command => 'qsub', :show_status_command => 'qstat; qstatlist;'}
23
+ File.open( @dbf.path_to_hosts_yaml, 'w') do |io|
24
+ YAML.dump( @hosts, io)
25
+ io.flush
26
+ end
27
+
28
+ @rc = NERA::RemoteConnector.new( @db_folder)
29
+ end
30
+
31
+ def teardown
32
+ FileUtils.chdir('..')
33
+ FileUtils.rm_r(@testdir)
34
+ end
35
+
36
+ def test_constructor
37
+ assert_raise( ArgumentError) {
38
+ NERA::RemoteConnector.new( @dbf)
39
+ }
40
+ end
41
+
42
+ def test_hostnames
43
+ a = @rc.hostnames
44
+ names = @hosts.map do |h| h[:name] end
45
+ assert_equal( a, names)
46
+ end
47
+
48
+ def test_submittable_hostnames
49
+ a = @rc.submittable_hostnames
50
+ assert_equal( ["localhost_submittable","unconnectable"], a)
51
+ end
52
+
53
+ def test_show_status
54
+ s = @rc.show_status("localhost")
55
+ assert( s.is_a?(String) )
56
+ ret = @rc.show_status("unconnectable")
57
+ assert_equal( :connection_failed, ret)
58
+ end
59
+
60
+ def test_transfer
61
+ assert_raise( ArgumentError) {
62
+ @rc.transfer( 1, "localhost")
63
+ }
64
+ assert_raise( ArgumentError) {
65
+ @rc.transfer( [1,"j000001.sh"], "localhost")
66
+ }
67
+ assert_raise( ArgumentError) {
68
+ @rc.transfer( [1,2], 1)
69
+ }
70
+
71
+ ret = @rc.transfer( [999,1000], "localhost")
72
+ assert_equal( :no_such_jobs, ret)
73
+
74
+ ret = @rc.transfer( [1,2], "unknown_host")
75
+ assert_equal( :connection_failed, ret)
76
+
77
+ ret = @rc.transfer( [1], "unconnectable")
78
+ assert_equal( :connection_failed, ret)
79
+
80
+ ret = @rc.transfer( [1,2], "localhost")
81
+ assert_equal( :succeeded, ret)
82
+ h,l = @jlc.not_finished_list_in_csv
83
+ stat = l[0].split(',')[1].strip
84
+ assert_equal( :copied.to_s, stat)
85
+ stat = l[0].split(',')[-1].strip
86
+ assert_equal( "localhost", stat)
87
+ stat = l[1].split(',')[1].strip
88
+ assert_equal( :copied.to_s, stat)
89
+ stat = l[1].split(',')[-1].strip
90
+ assert_equal( "localhost", stat)
91
+ stat = l[2].split(',')[1].strip
92
+ assert_equal( :created.to_s, stat)
93
+ stat = l[2].split(',')[-1].strip
94
+ assert_equal( '', stat)
95
+
96
+
97
+ assert( File.directory?("job1") )
98
+ assert( File.exist?("job1/j000001.sh") )
99
+ assert( File.exist?("job1/j000002.sh") )
100
+ assert( ! File.exist?("job1/j000003.sh") )
101
+ end
102
+
103
+ def test_submit
104
+ assert_raise( ArgumentError) {
105
+ @rc.submit( 1, "localhost")
106
+ }
107
+ assert_raise( ArgumentError) {
108
+ @rc.submit( ["j000001.sh"], "localhost")
109
+ }
110
+ assert_raise( ArgumentError) {
111
+ @rc.submit( [1,2], 1)
112
+ }
113
+
114
+ ret = @rc.submit( [999,1000], "localhost_submittable")
115
+ assert_equal( :no_such_jobs, ret)
116
+
117
+ ret = @rc.submit( [1,2], "localhost")
118
+ assert_equal( :no_submission_command, ret)
119
+
120
+ ret = @rc.submit( [1,2], "unknown_host")
121
+ assert_equal( :connection_failed, ret)
122
+
123
+ ret = @rc.submit( [1], "unconnectable")
124
+ assert_equal( :connection_failed, ret)
125
+
126
+ ret = @rc.submit( [1,2], "localhost_submittable")
127
+ assert_equal( :succeeded, ret)
128
+
129
+ h,l = @jlc.not_finished_list_in_csv
130
+ stat = l[0].split(',')[1].strip
131
+ assert_equal( :submitted.to_s, stat)
132
+ stat = l[0].split(',')[-1].strip
133
+ assert_equal( "localhost_submittable", stat)
134
+ stat = l[1].split(',')[1].strip
135
+ assert_equal( :submitted.to_s, stat)
136
+ stat = l[1].split(',')[-1].strip
137
+ assert_equal( "localhost_submittable", stat)
138
+ stat = l[2].split(',')[1].strip
139
+ assert_equal( :created.to_s, stat)
140
+ stat = l[2].split(',')[-1].strip
141
+ assert_equal( '', stat)
142
+
143
+ assert( File.directory?("job2") )
144
+ assert( File.exist?("job2/j000001.sh") )
145
+ assert( File.exist?("job2/j000002.sh") )
146
+ assert( ! File.exist?("job2/j000003.sh") )
147
+
148
+ sleep 3 # wait for completion
149
+
150
+ assert( File.exist?("job2/j000001.tar.bz2") )
151
+ assert( File.exist?("job2/j000002.tar.bz2") )
152
+
153
+ end
154
+
155
+ def test_check_completion
156
+ fs = @rc.check_completion( "localhost_submittable")
157
+ assert_equal( [], fs)
158
+ fs = @rc.check_completion( "unconnectable")
159
+ assert_equal( :connection_failed, fs)
160
+ fs = @rc.check_completion( "unknown_host")
161
+ assert_equal( :connection_failed, fs)
162
+ assert_raise( ArgumentError) {
163
+ @rc.check_completion( 1)
164
+ }
165
+
166
+ ret = @rc.submit( [2,3], "localhost_submittable")
167
+ sleep 3 # wait for completion
168
+ fs = @rc.check_completion( "localhost_submittable")
169
+ assert( fs, ["j000001.tar.bz2", "j000002.tar.bz2"] )
170
+ end
171
+
172
+
173
+ def test_check_completion_all
174
+ ret = @rc.submit( [1,2], "localhost_submittable")
175
+ sleep 3 # wait for completion
176
+ comp = @rc.check_completion_all
177
+ comp.has_key?( "localhost_submittable")
178
+ assert( comp["localhost_submittable"], ["j000001.tar.bz2", "j000002.tar.bz2"] )
179
+ end
180
+
181
+ def test_download
182
+ assert_raise( ArgumentError) {
183
+ @rc.download( "j000001.tar.bz2", "localhost")
184
+ }
185
+ assert_raise( ArgumentError) {
186
+ @rc.download( [1,"j000001.tar.bz2"], "localhost")
187
+ }
188
+ assert_raise( ArgumentError) {
189
+ @rc.download( [1,2], "localhost")
190
+ }
191
+ assert_raise( ArgumentError) {
192
+ @rc.download( ["j000001.sh"], "localhost")
193
+ }
194
+ assert_raise( ArgumentError) {
195
+ @rc.download( ["j000001.tar.bz2","j000002.tar.bz2"], 1)
196
+ }
197
+
198
+ ret = @rc.download( ["j000001.tar.bz2"], "unknown_host")
199
+ assert_equal( :connection_failed, ret)
200
+
201
+ ret = @rc.download( ["j000001.tar.bz2"], "unconnectable")
202
+ assert_equal( :connection_failed, ret)
203
+
204
+ ret = @rc.download( ["j000001.tar.bz2"], "localhost_submittable")
205
+ assert_equal( [], ret)
206
+
207
+ ret = @rc.submit( [1,2], "localhost_submittable")
208
+ sleep 3 # wait for completion
209
+ downloadable = @rc.check_completion("localhost_submittable")
210
+ ret = @rc.download( downloadable, "localhost_submittable")
211
+ assert_equal( ["j000001.tar.bz2", "j000002.tar.bz2"], ret)
212
+
213
+ downloadable = @rc.check_completion("localhost_submittable")
214
+ assert_equal( downloadable, [])
215
+
216
+ assert( FileTest.exist?(@db_folder+"/Jobs/Include/j000001.tar.bz2") )
217
+ assert( FileTest.exist?(@db_folder+"/Jobs/Include/j000002.tar.bz2") )
218
+ end
219
+
220
+ =begin
221
+ def test_remote
222
+ @hosts << { :name => "cruijff",:host_url => "cruijff.t.u-tokyo.ac.jp",:user => 'murase', :job_path => '~/job1', :submission_command => 'qsub', :show_status_command => 'qstatlist'}
223
+ File.open( "hosts.yml", 'w') do |io|
224
+ YAML.dump( @hosts, io)
225
+ io.flush
226
+ end
227
+ @rc = NERA::RemoteConnector.new( @db_folder, "hosts.yml")
228
+
229
+ puts @rc.show_status("cruijff")
230
+
231
+ @rc.submit( [1,2], "cruijff")
232
+ sleep 3
233
+ a = @rc.check_completion("cruijff")
234
+ @rc.download( a, "cruijff")
235
+
236
+ end
237
+ =end
238
+
239
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nera
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yohsuke Murase
@@ -9,9 +9,19 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-04-16 00:00:00 +09:00
12
+ date: 2009-04-30 00:00:00 +09:00
13
13
  default_executable:
14
14
  dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: net-ssh
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 2.0.11
24
+ version:
15
25
  - !ruby/object:Gem::Dependency
16
26
  name: newgem
17
27
  type: :development
@@ -37,6 +47,7 @@ email:
37
47
  - murase@serow.t.u-tokyo.ac.jp
38
48
  executables:
39
49
  - nera
50
+ - nera_addhost
40
51
  - nera_addsim
41
52
  extensions: []
42
53
 
@@ -50,6 +61,7 @@ files:
50
61
  - README.rdoc
51
62
  - Rakefile
52
63
  - bin/nera
64
+ - bin/nera_addhost
53
65
  - bin/nera_addsim
54
66
  - lib/nera.rb
55
67
  - lib/nera/nera_cui.rb
@@ -61,11 +73,13 @@ files:
61
73
  - lib/nera/nera_job_script.rb
62
74
  - lib/nera/nera_parameter_layer_controller.rb
63
75
  - lib/nera/nera_parameter_records.rb
76
+ - lib/nera/nera_remote_connector.rb
64
77
  - lib/nera/nera_run_layer_controller.rb
65
78
  - lib/nera/nera_run_records.rb
66
79
  - lib/nera/nera_simulator.rb
67
80
  - lib/nera/nera_simulator_layer_controller.rb
68
81
  - lib/nera/nera_simulator_records.rb
82
+ - lib/nera_addhost/add_hosts.rb
69
83
  - lib/nera_addsim/make_simulator.rb
70
84
  - scripts/console
71
85
  - scripts/destroy
@@ -80,6 +94,7 @@ files:
80
94
  - test/test_nera_job_records.rb
81
95
  - test/test_nera_parameter_layer_controller.rb
82
96
  - test/test_nera_parameter_records.rb
97
+ - test/test_nera_remote_connector.rb
83
98
  - test/test_nera_run_layer_controller.rb
84
99
  - test/test_nera_run_records.rb
85
100
  - test/test_nera_simulator.rb
@@ -121,6 +136,7 @@ test_files:
121
136
  - test/test_nera_job_records.rb
122
137
  - test/test_nera_parameter_layer_controller.rb
123
138
  - test/test_nera_parameter_records.rb
139
+ - test/test_nera_remote_connector.rb
124
140
  - test/test_nera_run_layer_controller.rb
125
141
  - test/test_nera_run_records.rb
126
142
  - test/test_nera_simulator.rb