drbqs 0.0.8 → 0.0.9

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