nera 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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