drbqs 0.0.8 → 0.0.9

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/lib/drbqs/client.rb CHANGED
@@ -18,9 +18,21 @@ module DRbQS
18
18
  @process_continue = opts[:continue]
19
19
  end
20
20
 
21
+ def transfer_file
22
+ until FileTransfer.empty?
23
+ path = FileTransfer.dequeue
24
+ unless @transfer.scp(path)
25
+ raise "Can not send file: #{path}"
26
+ end
27
+ end
28
+ end
29
+ private :transfer_file
30
+
21
31
  def execute_task(marshal_obj, method_sym, args)
22
32
  obj = Marshal.load(marshal_obj)
23
- obj.__send__(method_sym, *args)
33
+ result = obj.__send__(method_sym, *args)
34
+ transfer_file
35
+ result
24
36
  end
25
37
  private :execute_task
26
38
 
@@ -29,6 +41,7 @@ module DRbQS
29
41
  @connection = ConnectionClient.new(obj[:message], @logger)
30
42
  node_id = @connection.get_id
31
43
  @task_client = TaskClient.new(node_id, obj[:queue], obj[:result], @logger)
44
+ @transfer = obj[:transfer]
32
45
  if ary = @connection.get_initialization
33
46
  execute_task(*ary)
34
47
  end
data/lib/drbqs/config.rb CHANGED
@@ -3,10 +3,14 @@ require 'singleton'
3
3
 
4
4
  module DRbQS
5
5
 
6
+ ACL_DEFAULT_PATH = 'acl.txt'
7
+ ACL_SAMPLE_PATH = 'acl.txt.sample'
8
+ HOST_FILE_DIRECTORY = 'host'
9
+
6
10
  class Config
7
11
 
8
12
  @@data = {
9
- :dir => ENV['HOME'] + '/.drbqs/'
13
+ :dir => ENV['HOME'] + '/.drbqs/',
10
14
  }
11
15
 
12
16
  ACL_SAMPLE =<<SAMPLE
@@ -25,22 +29,30 @@ SAMPLE
25
29
  @@data[:dir] = dir
26
30
  end
27
31
 
32
+ def get_host_file_directory
33
+ get_path(HOST_FILE_DIRECTORY)
34
+ end
35
+
28
36
  def check_directory_create
29
37
  unless File.exist?(@@data[:dir])
30
38
  FileUtils.mkdir_p(@@data[:dir])
31
39
  FileUtils.chmod(0700, @@data[:dir])
32
40
  end
41
+ host = get_host_file_directory
42
+ unless File.exist?(host)
43
+ FileUtils.mkdir_p(host)
44
+ end
33
45
  end
34
46
 
35
47
  def save_sample
36
- path = get_path('acl.txt.sample')
48
+ path = get_path(ACL_SAMPLE_PATH)
37
49
  unless File.exist?(path)
38
50
  open(path, 'w') { |f| f.print ACL_SAMPLE }
39
51
  end
40
52
  end
41
53
 
42
54
  def get_acl_file
43
- path = File.join(@@data[:dir], 'acl.txt')
55
+ path = File.join(@@data[:dir], ACL_DEFAULT_PATH)
44
56
  if File.exist?(path)
45
57
  return path
46
58
  end
data/lib/drbqs/manage.rb CHANGED
@@ -2,6 +2,40 @@ require 'socket'
2
2
 
3
3
  module DRbQS
4
4
 
5
+ class SendCommand
6
+ MAX_WAIT_TIME = 10
7
+
8
+ def initialize(message)
9
+ @message = message
10
+ end
11
+
12
+ def get_hostname
13
+ "Command of #{Socket.gethostname}"
14
+ end
15
+ private :get_hostname
16
+
17
+ def send_exit_signal
18
+ @message.write([:exit_server, get_hostname])
19
+ end
20
+
21
+ def get_status
22
+ @message.write([:request_status, get_hostname])
23
+ i = 0
24
+ loop do
25
+ begin
26
+ mes = @message.take([:status, String], 0)
27
+ return mes[1]
28
+ rescue Rinda::RequestExpiredError
29
+ i += 1
30
+ if i > MAX_WAIT_TIME
31
+ return nil
32
+ end
33
+ sleep(1)
34
+ end
35
+ end
36
+ end
37
+ end
38
+
5
39
  class Manage
6
40
  def self.split_arguments(argv, split = '--')
7
41
  if n = argv.index(split)
@@ -16,15 +50,28 @@ module DRbQS
16
50
  Config.save_sample
17
51
  end
18
52
 
19
- def send_exit_signal(access_uri)
53
+ def command_client(access_uri)
20
54
  obj = DRbObject.new_with_uri(access_uri)
21
- obj[:message].write([:exit_server, "Command of #{Socket.gethostname}"])
55
+ DRbQS::SendCommand.new(obj[:message])
56
+ end
57
+ private :command_client
58
+
59
+ def send_exit_signal(access_uri)
60
+ command_client(access_uri).send_exit_signal
61
+ end
62
+
63
+ def get_status(access_uri)
64
+ command_client(access_uri).get_status
22
65
  end
23
66
 
24
67
  def execute_over_ssh(dest, opts, command)
25
68
  ssh = DRbQS::SSHShell.new(dest, opts)
26
- ssh.get_environment
27
69
  ssh.start(command)
28
70
  end
71
+
72
+ def get_ssh_environment(dest, opts)
73
+ ssh = DRbQS::SSHShell.new(dest, opts)
74
+ ssh.get_environment
75
+ end
29
76
  end
30
77
  end
data/lib/drbqs/message.rb CHANGED
@@ -28,11 +28,13 @@ module DRbQS
28
28
  @node_list.set_alive(arg)
29
29
  when :exit_server
30
30
  @logger.info("Get exit message from #{arg.to_s}") if @logger
31
- return :exit_server
31
+ when :request_status
32
+ @logger.info("Get status request from #{arg.to_s}") if @logger
32
33
  else
33
34
  @logger.error("Invalid message from #{arg.to_s}") if @logger
34
35
  return nil
35
36
  end
37
+ return mes
36
38
  end
37
39
  private :manage_message
38
40
 
@@ -52,6 +54,29 @@ module DRbQS
52
54
  end
53
55
  end
54
56
 
57
+ def time_to_string(t)
58
+ t.strftime("%Y-%m-%d %H:%M:%S")
59
+ end
60
+ private :time_to_string
61
+
62
+ def send_status(calculating_task_id)
63
+ s = ''
64
+ @node_list.history.each do |node_id, hist|
65
+ s << sprintf("%4d %s\t", node_id, hist[0])
66
+ if hist.size == 3
67
+ s << "disconnected: (#{time_to_string(hist[1])} - #{time_to_string(hist[1])})\n"
68
+ else
69
+ task_ids = calculating_task_id[node_id]
70
+ s << "task: #{task_ids.map { |num| num.to_s }.join(', ')} (#{time_to_string(hist[1])})\n"
71
+ end
72
+ end
73
+ begin
74
+ @message.take([:status, nil], 0)
75
+ rescue Rinda::RequestExpiredError
76
+ end
77
+ @message.write([:status, s])
78
+ end
79
+
55
80
  def node_not_exist?
56
81
  @node_list.empty?
57
82
  end
@@ -1,14 +1,38 @@
1
1
  module DRbQS
2
+ class NodeHistory
3
+ def initialize
4
+ @data = {}
5
+ end
6
+
7
+ def add(id, id_str)
8
+ @data[id] = [id_str, Time.now]
9
+ end
10
+
11
+ def disconnect(id)
12
+ if @data[id]
13
+ @data[id] << Time.now
14
+ end
15
+ end
16
+
17
+ def each(&block)
18
+ @data.each(&block)
19
+ end
20
+ end
21
+
2
22
  class NodeList
23
+ attr_reader :history
24
+
3
25
  def initialize
4
26
  @id = 0
5
27
  @list = {}
6
28
  @check = []
29
+ @history = NodeHistory.new
7
30
  end
8
31
 
9
32
  def get_new_id(id_str)
10
33
  @id += 1
11
34
  @list[@id] = id_str
35
+ @history.add(@id, id_str)
12
36
  @id
13
37
  end
14
38
 
@@ -23,6 +47,7 @@ module DRbQS
23
47
  def delete_not_alive
24
48
  @check.each do |id|
25
49
  @list.delete(id)
50
+ @history.disconnect(id)
26
51
  end
27
52
  deleted = @check
28
53
  @check = []
data/lib/drbqs/queue.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  module DRbQS
2
2
 
3
3
  class QueueServer
4
+ attr_reader :calculating
4
5
 
5
6
  def initialize(queue, result, logger = nil)
6
7
  @queue = queue
data/lib/drbqs/server.rb CHANGED
@@ -49,7 +49,8 @@ module DRbQS
49
49
  @ts = {
50
50
  :message => Rinda::TupleSpace.new,
51
51
  :queue => Rinda::TupleSpace.new,
52
- :result => Rinda::TupleSpace.new
52
+ :result => Rinda::TupleSpace.new,
53
+ :transfer => nil
53
54
  }
54
55
  if opts[:log_file]
55
56
  @logger = Logger.new(opts[:log_file])
@@ -162,9 +163,16 @@ module DRbQS
162
163
  end
163
164
  end
164
165
 
166
+ def set_file_transfer(user, host, directory)
167
+ @ts[:transfer] = DRbQS::Transfer.new(user, host, directory)
168
+ end
169
+
165
170
  def check_message
166
- if @message.get_message == :exit_server
171
+ case @message.get_message
172
+ when :exit_server
167
173
  self.exit
174
+ when :request_status
175
+ @message.send_status(@queue.calculating)
168
176
  end
169
177
  end
170
178
  private :check_message
@@ -0,0 +1,26 @@
1
+ require 'yaml'
2
+ require 'drbqs/config'
3
+
4
+ module DRbQS
5
+ class SSHHost
6
+ def initialize
7
+ @dir = DRbQS::Config.get_host_file_directory
8
+ @host_files = (Dir.glob("#{@dir}/*.yaml") + Dir.glob("#{@dir}/*.yml")).map { |s| File.basename(s) }
9
+ end
10
+
11
+ def get(name)
12
+ if (name.size > 0) && (host = @host_files.find { |s| /^#{name}/ =~ s })
13
+ return File.join(@dir, host)
14
+ end
15
+ return nil
16
+ end
17
+ private :get
18
+
19
+ def get_options(name)
20
+ if path = get(name)
21
+ return [path, YAML.load_file(path)]
22
+ end
23
+ return [nil, {}]
24
+ end
25
+ end
26
+ end
@@ -31,8 +31,11 @@ module DRbQS
31
31
  if (@rvm || @rvm_init) && !(String === @rvm_init)
32
32
  @rvm_init = DEFAULT_RVM_SCRIPT
33
33
  end
34
- @out = opts[:output] || DEFAULT_OUTPUT_FILE
34
+ @nohup_output = opts[:output] || DEFAULT_OUTPUT_FILE
35
35
  @directory = opts[:dir]
36
+ @out = $stdout
37
+ @nice = opts[:nice]
38
+ @nohup = opts[:nohup]
36
39
  end
37
40
 
38
41
  def split_destination(dest)
@@ -55,38 +58,82 @@ module DRbQS
55
58
  end
56
59
  private :split_destination
57
60
 
61
+ def output_command(cmd, result)
62
+ @out.puts "#{@user}@#{@host}$ #{cmd}" if @out
63
+ @out.print result
64
+ end
65
+ private :output_command
66
+
67
+ def shell_exec_get_output(sh, cmd)
68
+ result = ''
69
+ pr_cmd = sh.execute!(cmd) do |sh_proc|
70
+ sh_proc.on_output do |pr, data|
71
+ result << data
72
+ end
73
+ sh_proc.on_error_output do |pr, data|
74
+ result << data
75
+ end
76
+ end
77
+ [pr_cmd, result]
78
+ end
79
+ private :shell_exec_get_output
80
+
58
81
  def shell_exec(sh, cmd)
59
- pr = sh.execute!(cmd)
60
- if pr.exit_status != 0
82
+ ary = shell_exec_get_output(sh, cmd)
83
+ output_command(cmd, ary[1])
84
+ ary
85
+ end
86
+ private :shell_exec
87
+
88
+ def shell_exec_check(sh, cmd)
89
+ ary = shell_exec(sh, cmd)
90
+ if ary[0].exit_status != 0
61
91
  raise GetInvalidExitStatus, "Can not execute '#{cmd}' on #{@host} properly."
62
92
  end
93
+ ary
63
94
  end
64
- private :shell_exec
95
+ private :shell_exec_check
65
96
 
66
- def execute_command(*cmds)
97
+ def execute_command(&block)
67
98
  Net::SSH.start(@host, @user, :port => @port) do |ssh|
68
99
  ssh.shell(@shell) do |sh|
69
- shell_exec(sh, "cd #{@directory}") if @directory
70
- shell_exec(sh, "source #{@rvm_init}") if @rvm_init
71
- shell_exec(sh, "rvm use #{@rvm}") if @rvm
72
- cmds.each do |c|
73
- sh.execute c
74
- end
75
- sh.execute "exit"
100
+ shell_exec_check(sh, "cd #{@directory}") if @directory
101
+ shell_exec_check(sh, "source #{@rvm_init}") if @rvm_init
102
+ shell_exec_check(sh, "rvm use #{@rvm}") if @rvm
103
+ yield(sh)
104
+ shell_exec(sh, "exit")
76
105
  end
77
106
  end
78
107
  end
79
108
  private :execute_command
80
109
 
81
110
  def get_environment
82
- execute_command('echo "directory: " `pwd`',
83
- 'echo "files:"',
84
- 'ls',
85
- 'if which rvm > /dev/null; then rvm info; else ruby -v; fi')
111
+ execute_command do |sh|
112
+ ['echo "directory: " `pwd`',
113
+ 'echo "files:"',
114
+ 'ls',
115
+ 'if which rvm > /dev/null; then rvm info; else ruby -v; fi'].each do |cmd|
116
+ shell_exec(sh, cmd)
117
+ end
118
+ end
86
119
  end
87
120
 
88
121
  def start(*args)
89
- execute_command("nohup #{args.join(' ')} > #{@out} 2>&1 &")
122
+ cmd = args.join(' ')
123
+ if @nice
124
+ if Integer === @nice
125
+ cmd = "nice -n #{@nice.to_s} " + cmd
126
+ else
127
+ cmd = "nice " + cmd
128
+ end
129
+ end
130
+ execute_command do |sh|
131
+ if @nohup
132
+ pr, path = shell_exec_check(sh, "drbqs-manage new-filename #{@nohup_output}")
133
+ cmd = "nohup #{cmd} > #{path.strip} 2>&1 &"
134
+ end
135
+ shell_exec(sh, cmd)
136
+ end
90
137
  end
91
138
  end
92
139
  end
@@ -0,0 +1,70 @@
1
+ require 'fileutils'
2
+
3
+ module DRbQS
4
+
5
+ # Transfer files to directory on DRbQS server.
6
+ # In this class we use scp command.
7
+ # Note that after we transfer files we delete the files.
8
+ class Transfer
9
+
10
+ # options
11
+ # :mkdir true or nil
12
+ def initialize(user, host, directory)
13
+ @user = user
14
+ @host = host
15
+ @directory = File.expand_path(directory)
16
+ FileUtils.mkdir_p(@directory)
17
+ end
18
+
19
+ def scp(path)
20
+ name = File.basename(path)
21
+ unless File.exist?(path)
22
+ raise ArgumentError, "File #{path} does not exist."
23
+ end
24
+ if system("scp -r #{path} #{@user}@#{@host}:#{File.join(@directory, name)} > /dev/null 2>&1")
25
+ FileUtils.rm_r(path)
26
+ return true
27
+ end
28
+ return false
29
+ end
30
+ end
31
+
32
+ # To compress files, we use gzip and tar command.
33
+ # Note that if we compress files then we delete the source files.
34
+ module FileTransfer
35
+ @@files = Queue.new
36
+
37
+ def self.enqueue(path, compress = false)
38
+ if compress
39
+ if File.directory?(path)
40
+ gz_path = "#{path.sub(/\/$/, '')}.tar.gz"
41
+ cmd = "tar czf #{gz_path} -C #{File.dirname(path)} #{File.basename(path)} > /dev/null 2>&1"
42
+ else
43
+ gz_path = path + '.gz'
44
+ cmd = "gzip --best #{path} > /dev/null 2>&1"
45
+ end
46
+ if File.exist?(gz_path)
47
+ raise "File has already existed: #{gz_path}"
48
+ elsif !system(cmd)
49
+ raise "Can not compress: #{path}"
50
+ end
51
+ FileUtils.rm_r(path) if File.exist?(path)
52
+ @@files.enq(gz_path)
53
+ else
54
+ @@files.enq(path)
55
+ end
56
+ end
57
+
58
+ def self.compress_enqueue(path)
59
+ self.enqueue(path, true)
60
+ end
61
+
62
+ def self.dequeue
63
+ @@files.deq
64
+ end
65
+
66
+ def self.empty?
67
+ @@files.empty?
68
+ end
69
+ end
70
+ end