up to 0.6.2
[god.git] / lib / god / cli / command.rb
blobba40af85c0a205bd57f095b300b34781e099084c
1 module God
2   module CLI
3     
4     class Command
5       def initialize(command, options, args)
6         @command = command
7         @options = options
8         @args = args
9         
10         dispatch
11       end
12       
13       def setup
14         # connect to drb unix socket
15         DRb.start_service
16         @server = DRbObject.new(nil, God::Socket.socket(@options[:port]))
17         
18         # ping server to ensure that it is responsive
19         begin
20           @server.ping
21         rescue DRb::DRbConnError
22           puts "The server is not available (or you do not have permissions to access it)"
23           abort
24         end
25       end
26       
27       def dispatch
28         if %w{load status log quit terminate}.include?(@command)
29           setup
30           send("#{@command}_command")
31         elsif %w{start stop restart monitor unmonitor remove}.include?(@command)
32           setup
33           lifecycle_command
34         elsif @command == 'check'
35           check_command
36         else
37           puts "Command '#{@command}' is not valid. Run 'god --help' for usage"
38           abort
39         end
40       end
41       
42       def load_command
43         file = @args[1]
44           
45         puts "Sending '#{@command}' command"
46         puts
47         
48         unless File.exist?(file)
49           abort "File not found: #{file}"
50         end
51         
52         names, errors = *@server.running_load(File.read(file), File.expand_path(file))
53         
54         # output response
55         unless names.empty?
56           puts 'The following tasks were affected:'
57           names.each do |w|
58             puts '  ' + w
59           end
60         end
61         
62         unless errors.empty?
63           puts errors
64           exit(1)
65         end
66       end
67       
68       def status_command
69         watches = @server.status
70         watches.keys.sort.each do |name|
71           state = watches[name][:state]
72           puts "#{name}: #{state}"
73         end
74       end
75       
76       def log_command
77         begin
78           Signal.trap('INT') { exit }
79           name = @args[1]
80           
81           unless name
82             puts "You must specify a Task or Group name"
83             exit!
84           end
85           
86           t = Time.at(0)
87           loop do
88             print @server.running_log(name, t)
89             t = Time.now
90             sleep 1
91           end
92         rescue God::NoSuchWatchError
93           puts "No such watch"
94         rescue DRb::DRbConnError
95           puts "The server went away"
96         end
97       end
98       
99       def quit_command
100         begin
101           @server.terminate
102           abort 'Could not stop god'
103         rescue DRb::DRbConnError
104           puts 'Stopped god'
105         end
106       end
107       
108       def terminate_command
109         t = Thread.new { loop { STDOUT.print('.'); STDOUT.flush; sleep(1) } }
110         if @server.stop_all
111           t.kill; STDOUT.puts
112           puts 'Stopped all watches'
113         else
114           t.kill; STDOUT.puts
115           puts 'Could not stop all watches within 10 seconds'
116         end
117         
118         begin
119           @server.terminate
120           abort 'Could not stop god'
121         rescue DRb::DRbConnError
122           puts 'Stopped god'
123         end
124       end
125       
126       def check_command
127         Thread.new do
128           begin
129             event_system = God::EventHandler.event_system
130             puts "using event system: #{event_system}"
131             
132             if God::EventHandler.loaded?
133               puts "starting event handler"
134               God::EventHandler.start
135             else
136               puts "[fail] event system did not load"
137               exit(1)
138             end
139             
140             puts 'forking off new process'
141             
142             pid = fork do
143               loop { sleep(1) }
144             end
145             
146             puts "forked process with pid = #{pid}"
147             
148             God::EventHandler.register(pid, :proc_exit) do
149               puts "[ok] process exit event received"
150               exit(0)
151             end
152             
153             sleep(1)
154             
155             puts "killing process"
156             
157             ::Process.kill('KILL', pid)
158           rescue => e
159             puts e.message
160             puts e.backtrace.join("\n")
161           end
162         end
163         
164         sleep(2)
165         
166         puts "[fail] never received process exit event"
167         exit(1)
168       end
169       
170       def lifecycle_command
171         # get the name of the watch/group
172         name = @args[1]
173         
174         puts "Sending '#{@command}' command"
175         
176         t = Thread.new { loop { sleep(1); STDOUT.print('.'); STDOUT.flush; sleep(1) } }
177         
178         # send @command
179         watches = @server.control(name, @command)
180         
181         # output response
182         t.kill; STDOUT.puts
183         unless watches.empty?
184           puts 'The following watches were affected:'
185           watches.each do |w|
186             puts '  ' + w
187           end
188         else
189           puts 'No matching task or group'
190         end
191       end
192     end # Command
193     
194   end