implement god remove to delete tasks altogether
[god.git] / lib / god / cli / command.rb
blobeff99489842e1edd536af2643b1431d0ecda7d83
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           t = Time.at(0)
81           loop do
82             print @server.running_log(name, t)
83             t = Time.now
84             sleep 1
85           end
86         rescue God::NoSuchWatchError
87           puts "No such watch"
88         rescue DRb::DRbConnError
89           puts "The server went away"
90         end
91       end
92       
93       def quit_command
94         begin
95           @server.terminate
96           abort 'Could not stop god'
97         rescue DRb::DRbConnError
98           puts 'Stopped god'
99         end
100       end
101       
102       def terminate_command
103         t = Thread.new { loop { STDOUT.print('.'); STDOUT.flush; sleep(1) } }
104         if @server.stop_all
105           t.kill; STDOUT.puts
106           puts 'Stopped all watches'
107         else
108           t.kill; STDOUT.puts
109           puts 'Could not stop all watches within 10 seconds'
110         end
111         
112         begin
113           @server.terminate
114           abort 'Could not stop god'
115         rescue DRb::DRbConnError
116           puts 'Stopped god'
117         end
118       end
119       
120       def check_command
121         Thread.new do
122           begin
123             event_system = God::EventHandler.event_system
124             puts "using event system: #{event_system}"
125             
126             if God::EventHandler.loaded?
127               puts "starting event handler"
128               God::EventHandler.start
129             else
130               puts "[fail] event system did not load"
131               exit(1)
132             end
133             
134             puts 'forking off new process'
135             
136             pid = fork do
137               loop { sleep(1) }
138             end
139             
140             puts "forked process with pid = #{pid}"
141             
142             God::EventHandler.register(pid, :proc_exit) do
143               puts "[ok] process exit event received"
144               exit(0)
145             end
146             
147             sleep(1)
148             
149             puts "killing process"
150             
151             ::Process.kill('KILL', pid)
152           rescue => e
153             puts e.message
154             puts e.backtrace.join("\n")
155           end
156         end
157         
158         sleep(2)
159         
160         puts "[fail] never received process exit event"
161         exit(1)
162       end
163       
164       def lifecycle_command
165         # get the name of the watch/group
166         name = @args[1]
167         
168         puts "Sending '#{@command}' command"
169         
170         t = Thread.new { loop { sleep(1); STDOUT.print('.'); STDOUT.flush; sleep(1) } }
171         
172         # send @command
173         watches = @server.control(name, @command)
174         
175         # output response
176         t.kill; STDOUT.puts
177         unless watches.empty?
178           puts 'The following watches were affected:'
179           watches.each do |w|
180             puts '  ' + w
181           end
182         else
183           puts 'No matching task or group'
184         end
185       end
186     end # Command
187     
188   end