resurrected_god 0.14.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +559 -0
- data/README.md +9 -4
- data/bin/god +26 -28
- data/ext/god/extconf.rb +9 -9
- data/lib/god/behavior.rb +3 -5
- data/lib/god/behaviors/clean_pid_file.rb +4 -6
- data/lib/god/behaviors/clean_unix_socket.rb +4 -6
- data/lib/god/behaviors/notify_when_flapping.rb +13 -15
- data/lib/god/cli/command.rb +109 -89
- data/lib/god/cli/run.rb +51 -75
- data/lib/god/cli/version.rb +2 -4
- data/lib/god/condition.rb +12 -14
- data/lib/god/conditions/always.rb +3 -2
- data/lib/god/conditions/complex.rb +23 -24
- data/lib/god/conditions/cpu_usage.rb +12 -16
- data/lib/god/conditions/degrading_lambda.rb +15 -19
- data/lib/god/conditions/disk_usage.rb +7 -8
- data/lib/god/conditions/file_mtime.rb +3 -7
- data/lib/god/conditions/file_touched.rb +4 -5
- data/lib/god/conditions/flapping.rb +57 -62
- data/lib/god/conditions/http_response_code.rb +27 -32
- data/lib/god/conditions/lambda.rb +3 -5
- data/lib/god/conditions/memory_usage.rb +12 -16
- data/lib/god/conditions/process_exits.rb +12 -12
- data/lib/god/conditions/process_running.rb +8 -10
- data/lib/god/conditions/socket_responding.rb +23 -28
- data/lib/god/conditions/tries.rb +12 -14
- data/lib/god/configurable.rb +7 -10
- data/lib/god/contact.rb +41 -52
- data/lib/god/contacts/airbrake.rb +10 -12
- data/lib/god/contacts/campfire.rb +18 -20
- data/lib/god/contacts/email.rb +27 -28
- data/lib/god/contacts/prowl.rb +16 -17
- data/lib/god/contacts/scout.rb +2 -5
- data/lib/god/contacts/sensu.rb +15 -11
- data/lib/god/contacts/slack.rb +23 -33
- data/lib/god/contacts/statsd.rb +8 -8
- data/lib/god/contacts/twitter.rb +2 -2
- data/lib/god/contacts/webhook.rb +21 -24
- data/lib/god/driver.rb +12 -18
- data/lib/god/errors.rb +0 -2
- data/lib/god/event_handler.rb +40 -49
- data/lib/god/event_handlers/dummy_handler.rb +1 -1
- data/lib/god/event_handlers/kqueue_handler.rb +2 -2
- data/lib/god/event_handlers/netlink_handler.rb +1 -1
- data/lib/god/logger.rb +5 -13
- data/lib/god/metric.rb +13 -15
- data/lib/god/process.rb +93 -98
- data/lib/god/simple_logger.rb +13 -15
- data/lib/god/socket.rb +21 -23
- data/lib/god/sugar.rb +8 -8
- data/lib/god/sys_logger.rb +6 -8
- data/lib/god/system/portable_poller.rb +1 -9
- data/lib/god/system/process.rb +4 -6
- data/lib/god/system/slash_proc_poller.rb +17 -19
- data/lib/god/task.rb +110 -136
- data/lib/god/timeline.rb +2 -4
- data/lib/god/trigger.rb +7 -11
- data/lib/god/version.rb +1 -1
- data/lib/god/watch.rb +51 -57
- data/lib/god.rb +122 -148
- metadata +17 -370
- data/Announce.txt +0 -135
- data/Gemfile +0 -5
- data/Rakefile +0 -129
- data/doc/god.asciidoc +0 -1592
- data/doc/intro.asciidoc +0 -20
- data/ext/god/.gitignore +0 -5
- data/lib/god/compat19.rb +0 -33
- data/lib/god/contacts/hipchat.rb +0 -117
- data/lib/god/contacts/jabber.rb +0 -75
- data/test/configs/child_events/child_events.god +0 -44
- data/test/configs/child_events/simple_server.rb +0 -3
- data/test/configs/child_polls/child_polls.god +0 -37
- data/test/configs/child_polls/simple_server.rb +0 -12
- data/test/configs/complex/complex.god +0 -59
- data/test/configs/complex/simple_server.rb +0 -3
- data/test/configs/contact/contact.god +0 -118
- data/test/configs/contact/simple_server.rb +0 -3
- data/test/configs/daemon_events/daemon_events.god +0 -37
- data/test/configs/daemon_events/simple_server.rb +0 -8
- data/test/configs/daemon_events/simple_server_stop.rb +0 -11
- data/test/configs/daemon_polls/daemon_polls.god +0 -17
- data/test/configs/daemon_polls/simple_server.rb +0 -6
- data/test/configs/degrading_lambda/degrading_lambda.god +0 -31
- data/test/configs/degrading_lambda/tcp_server.rb +0 -15
- data/test/configs/keepalive/keepalive.god +0 -9
- data/test/configs/keepalive/keepalive.rb +0 -12
- data/test/configs/lifecycle/lifecycle.god +0 -25
- data/test/configs/matias/matias.god +0 -50
- data/test/configs/real.rb +0 -59
- data/test/configs/running_load/running_load.god +0 -16
- data/test/configs/stop_options/simple_server.rb +0 -12
- data/test/configs/stop_options/stop_options.god +0 -39
- data/test/configs/stress/simple_server.rb +0 -3
- data/test/configs/stress/stress.god +0 -15
- data/test/configs/task/logs/.placeholder +0 -0
- data/test/configs/task/task.god +0 -26
- data/test/configs/test.rb +0 -61
- data/test/configs/usr1_trapper.rb +0 -10
- data/test/helper.rb +0 -172
- data/test/suite.rb +0 -6
- data/test/test_airbrake.rb +0 -14
- data/test/test_behavior.rb +0 -18
- data/test/test_campfire.rb +0 -22
- data/test/test_condition.rb +0 -52
- data/test/test_conditions_disk_usage.rb +0 -50
- data/test/test_conditions_http_response_code.rb +0 -109
- data/test/test_conditions_process_running.rb +0 -40
- data/test/test_conditions_socket_responding.rb +0 -176
- data/test/test_conditions_tries.rb +0 -67
- data/test/test_contact.rb +0 -109
- data/test/test_driver.rb +0 -26
- data/test/test_email.rb +0 -34
- data/test/test_event_handler.rb +0 -82
- data/test/test_god.rb +0 -710
- data/test/test_god_system.rb +0 -201
- data/test/test_handlers_kqueue_handler.rb +0 -16
- data/test/test_hipchat.rb +0 -23
- data/test/test_jabber.rb +0 -29
- data/test/test_logger.rb +0 -55
- data/test/test_metric.rb +0 -74
- data/test/test_process.rb +0 -263
- data/test/test_prowl.rb +0 -15
- data/test/test_registry.rb +0 -15
- data/test/test_sensu.rb +0 -11
- data/test/test_slack.rb +0 -57
- data/test/test_socket.rb +0 -34
- data/test/test_statsd.rb +0 -22
- data/test/test_sugar.rb +0 -42
- data/test/test_system_portable_poller.rb +0 -17
- data/test/test_system_process.rb +0 -30
- data/test/test_task.rb +0 -246
- data/test/test_timeline.rb +0 -37
- data/test/test_trigger.rb +0 -63
- data/test/test_watch.rb +0 -286
- data/test/test_webhook.rb +0 -22
data/lib/god.rb
CHANGED
@@ -8,15 +8,6 @@ if $load_god
|
|
8
8
|
require 'stringio'
|
9
9
|
require 'fileutils'
|
10
10
|
|
11
|
-
begin
|
12
|
-
require 'fastthread'
|
13
|
-
rescue LoadError
|
14
|
-
ensure
|
15
|
-
require 'thread'
|
16
|
-
end
|
17
|
-
|
18
|
-
# stdlib
|
19
|
-
|
20
11
|
# internal requires
|
21
12
|
require 'god/errors'
|
22
13
|
require 'god/simple_logger'
|
@@ -65,14 +56,10 @@ if $load_god
|
|
65
56
|
require 'god/registry'
|
66
57
|
require 'god/process'
|
67
58
|
|
59
|
+
require 'god/version'
|
68
60
|
require 'god/cli/version'
|
69
61
|
require 'god/cli/command'
|
70
62
|
|
71
|
-
# ruby 1.8 specific configuration
|
72
|
-
if RUBY_VERSION < '1.9'
|
73
|
-
$KCODE = 'u'
|
74
|
-
end
|
75
|
-
|
76
63
|
CONTACT_DEPS = {}
|
77
64
|
CONTACT_LOAD_SUCCESS = {}
|
78
65
|
|
@@ -85,9 +72,7 @@ if $load_god
|
|
85
72
|
|
86
73
|
require 'god/contact'
|
87
74
|
load_contact(:campfire)
|
88
|
-
load_contact(:hipchat)
|
89
75
|
load_contact(:email)
|
90
|
-
load_contact(:jabber)
|
91
76
|
load_contact(:prowl)
|
92
77
|
load_contact(:scout)
|
93
78
|
load_contact(:statsd)
|
@@ -97,7 +82,7 @@ if $load_god
|
|
97
82
|
load_contact(:slack)
|
98
83
|
load_contact(:sensu)
|
99
84
|
|
100
|
-
|
85
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), *%w[.. ext god])
|
101
86
|
|
102
87
|
# App wide logging system
|
103
88
|
LOG = God::Logger.new
|
@@ -120,7 +105,7 @@ if $load_god
|
|
120
105
|
end
|
121
106
|
|
122
107
|
module Kernel
|
123
|
-
|
108
|
+
alias abort_orig abort
|
124
109
|
|
125
110
|
def abort(text = nil)
|
126
111
|
$run = false
|
@@ -128,7 +113,7 @@ if $load_god
|
|
128
113
|
exit(1)
|
129
114
|
end
|
130
115
|
|
131
|
-
|
116
|
+
alias exit_orig exit
|
132
117
|
|
133
118
|
def exit(code = 0)
|
134
119
|
$run = false
|
@@ -139,43 +124,38 @@ if $load_god
|
|
139
124
|
class Module
|
140
125
|
def safe_attr_accessor(*args)
|
141
126
|
args.each do |arg|
|
142
|
-
define_method(
|
143
|
-
if !
|
144
|
-
abort "God.#{arg} must be set before any Tasks are defined"
|
145
|
-
end
|
127
|
+
define_method("#{arg}=".intern) do |other|
|
128
|
+
abort "God.#{arg} must be set before any Tasks are defined" if !running && inited
|
146
129
|
|
147
|
-
if
|
130
|
+
if running && inited
|
148
131
|
applog(nil, :warn, "God.#{arg} can't be set while god is running")
|
149
132
|
return
|
150
133
|
end
|
151
134
|
|
152
|
-
instance_variable_set(
|
135
|
+
instance_variable_set("@#{arg}".intern, other)
|
153
136
|
end
|
154
137
|
|
155
138
|
define_method(arg) do
|
156
|
-
instance_variable_get(
|
139
|
+
instance_variable_get("@#{arg}".intern)
|
157
140
|
end
|
158
141
|
end
|
159
142
|
end
|
160
143
|
end
|
161
144
|
|
162
|
-
module God
|
163
|
-
# The String version number for this package.
|
164
|
-
VERSION = '0.14.0'
|
165
|
-
|
145
|
+
module God
|
166
146
|
# The Integer number of lines of backlog to keep for the logger.
|
167
147
|
LOG_BUFFER_SIZE_DEFAULT = 100
|
168
148
|
|
169
149
|
# An Array of directory paths to be used as the default PID file directory.
|
170
150
|
# This list will be searched in order and the first one that has write
|
171
151
|
# permissions will be used.
|
172
|
-
PID_FILE_DIRECTORY_DEFAULTS = ['/var/run/god', '~/.god/pids']
|
152
|
+
PID_FILE_DIRECTORY_DEFAULTS = ['/var/run/god', '~/.god/pids'].freeze
|
173
153
|
|
174
|
-
# The default Integer port number for the DRb
|
154
|
+
# The default Integer port number for the DRb communications channel.
|
175
155
|
DRB_PORT_DEFAULT = 17165
|
176
156
|
|
177
157
|
# The default Array of String IPs that will allow DRb communication access.
|
178
|
-
DRB_ALLOW_DEFAULT = ['127.0.0.1']
|
158
|
+
DRB_ALLOW_DEFAULT = ['127.0.0.1'].freeze
|
179
159
|
|
180
160
|
# The default Symbol log level.
|
181
161
|
LOG_LEVEL_DEFAULT = :info
|
@@ -188,7 +168,7 @@ module God
|
|
188
168
|
STOP_TIMEOUT_DEFAULT = 10
|
189
169
|
|
190
170
|
# The default String signal to send for the stop command.
|
191
|
-
STOP_SIGNAL_DEFAULT = 'TERM'
|
171
|
+
STOP_SIGNAL_DEFAULT = 'TERM'.freeze
|
192
172
|
|
193
173
|
class << self
|
194
174
|
# user configurable
|
@@ -237,7 +217,7 @@ module God
|
|
237
217
|
# Returns nothing.
|
238
218
|
def self.internal_init
|
239
219
|
# Only do this once.
|
240
|
-
return if
|
220
|
+
return if inited
|
241
221
|
|
242
222
|
# Variable init.
|
243
223
|
self.watches = {}
|
@@ -255,14 +235,14 @@ module God
|
|
255
235
|
self.terminate_timeout ||= TERMINATE_TIMEOUT_DEFAULT
|
256
236
|
|
257
237
|
# Additional setup.
|
258
|
-
|
238
|
+
setup
|
259
239
|
|
260
240
|
# Log level.
|
261
|
-
log_level_map = { :
|
262
|
-
:
|
263
|
-
:
|
264
|
-
:
|
265
|
-
:
|
241
|
+
log_level_map = { debug: Logger::DEBUG,
|
242
|
+
info: Logger::INFO,
|
243
|
+
warn: Logger::WARN,
|
244
|
+
error: Logger::ERROR,
|
245
|
+
fatal: Logger::FATAL }
|
266
246
|
LOG.level = log_level_map[self.log_level]
|
267
247
|
|
268
248
|
# Init has been executed.
|
@@ -278,7 +258,7 @@ module God
|
|
278
258
|
#
|
279
259
|
# Returns nothing.
|
280
260
|
def self.watch(&block)
|
281
|
-
|
261
|
+
task(Watch, &block)
|
282
262
|
end
|
283
263
|
|
284
264
|
# Instantiate a new, empty Task object and yield it to the mandatory block.
|
@@ -288,7 +268,7 @@ module God
|
|
288
268
|
# Returns nothing.
|
289
269
|
def self.task(klass = Task)
|
290
270
|
# Ensure internal init has run.
|
291
|
-
|
271
|
+
internal_init
|
292
272
|
|
293
273
|
t = klass.new
|
294
274
|
yield(t)
|
@@ -298,44 +278,40 @@ module God
|
|
298
278
|
|
299
279
|
# If running, completely remove the watch (if necessary) to prepare for
|
300
280
|
# the reload
|
301
|
-
existing_watch =
|
302
|
-
if
|
303
|
-
|
304
|
-
|
281
|
+
existing_watch = watches[t.name]
|
282
|
+
if running && existing_watch
|
283
|
+
pending_watch_states[existing_watch.name] = existing_watch.state
|
284
|
+
unwatch(existing_watch)
|
305
285
|
end
|
306
286
|
|
307
287
|
# Ensure the new watch has a unique name.
|
308
|
-
if
|
309
|
-
abort "Task name '#{t.name}' already used for a Task or Group"
|
310
|
-
end
|
288
|
+
abort "Task name '#{t.name}' already used for a Task or Group" if watches[t.name] || groups[t.name]
|
311
289
|
|
312
290
|
# Ensure watch is internally valid.
|
313
291
|
t.valid? || abort("Task '#{t.name}' is not valid (see above)")
|
314
292
|
|
315
293
|
# Add to list of watches.
|
316
|
-
|
294
|
+
watches[t.name] = t
|
317
295
|
|
318
296
|
# Add to pending watches.
|
319
|
-
|
297
|
+
pending_watches << t
|
320
298
|
|
321
299
|
# Add to group if specified.
|
322
300
|
if t.group
|
323
301
|
# Ensure group name hasn't been used for a watch already.
|
324
|
-
if
|
325
|
-
abort "Group name '#{t.group}' already used for a Task"
|
326
|
-
end
|
302
|
+
abort "Group name '#{t.group}' already used for a Task" if watches[t.group]
|
327
303
|
|
328
|
-
|
329
|
-
|
304
|
+
groups[t.group] ||= []
|
305
|
+
groups[t.group] << t
|
330
306
|
end
|
331
307
|
|
332
308
|
# Register watch.
|
333
309
|
t.register!
|
334
310
|
|
335
311
|
# Log.
|
336
|
-
if
|
312
|
+
if running && existing_watch
|
337
313
|
applog(t, :info, "#{t.name} Reloaded config")
|
338
|
-
elsif
|
314
|
+
elsif running
|
339
315
|
applog(t, :info, "#{t.name} Loaded config")
|
340
316
|
end
|
341
317
|
end
|
@@ -353,12 +329,10 @@ module God
|
|
353
329
|
watch.unregister!
|
354
330
|
|
355
331
|
# Remove from watches.
|
356
|
-
|
332
|
+
watches.delete(watch.name)
|
357
333
|
|
358
334
|
# Remove from groups.
|
359
|
-
if watch.group
|
360
|
-
self.groups[watch.group].delete(watch)
|
361
|
-
end
|
335
|
+
groups[watch.group].delete(watch) if watch.group
|
362
336
|
|
363
337
|
applog(watch, :info, "#{watch.name} unwatched")
|
364
338
|
end
|
@@ -372,12 +346,12 @@ module God
|
|
372
346
|
# Returns nothing.
|
373
347
|
def self.contact(kind)
|
374
348
|
# Ensure internal init has run.
|
375
|
-
|
349
|
+
internal_init
|
376
350
|
|
377
351
|
# Verify contact has been loaded.
|
378
352
|
if CONTACT_LOAD_SUCCESS[kind] == false
|
379
353
|
applog(nil, :error, "A required dependency for the #{kind} contact is unavailable.")
|
380
|
-
applog(nil, :error,
|
354
|
+
applog(nil, :error, 'Run the following commands to install the dependencies:')
|
381
355
|
CONTACT_DEPS[kind].each do |d|
|
382
356
|
applog(nil, :error, " [sudo] gem install #{d}")
|
383
357
|
end
|
@@ -398,36 +372,30 @@ module God
|
|
398
372
|
c.prepare
|
399
373
|
|
400
374
|
# Remove existing contacts of same name.
|
401
|
-
existing_contact =
|
402
|
-
if
|
403
|
-
self.uncontact(existing_contact)
|
404
|
-
end
|
375
|
+
existing_contact = contacts[c.name]
|
376
|
+
uncontact(existing_contact) if running && existing_contact
|
405
377
|
|
406
378
|
# Warn and noop if the contact has been defined before.
|
407
|
-
if
|
379
|
+
if contacts[c.name] || contact_groups[c.name]
|
408
380
|
applog(nil, :warn, "Contact name '#{c.name}' already used for a Contact or Contact Group")
|
409
381
|
return
|
410
382
|
end
|
411
383
|
|
412
384
|
# Abort if the Contact is invalid, the Contact will have printed out its
|
413
385
|
# own error messages by now.
|
414
|
-
unless Contact.valid?(c) && c.valid?
|
415
|
-
abort "Exiting on invalid contact"
|
416
|
-
end
|
386
|
+
abort 'Exiting on invalid contact' unless Contact.valid?(c) && c.valid?
|
417
387
|
|
418
388
|
# Add to list of contacts.
|
419
|
-
|
389
|
+
contacts[c.name] = c
|
420
390
|
|
421
391
|
# Add to contact group if specified.
|
422
|
-
|
423
|
-
# Ensure group name hasn't been used for a contact already.
|
424
|
-
if self.contacts[c.group]
|
425
|
-
abort "Contact Group name '#{c.group}' already used for a Contact"
|
426
|
-
end
|
392
|
+
return unless c.group
|
427
393
|
|
428
|
-
|
429
|
-
|
430
|
-
|
394
|
+
# Ensure group name hasn't been used for a contact already.
|
395
|
+
abort "Contact Group name '#{c.group}' already used for a Contact" if contacts[c.group]
|
396
|
+
|
397
|
+
contact_groups[c.group] ||= []
|
398
|
+
contact_groups[c.group] << c
|
431
399
|
end
|
432
400
|
|
433
401
|
# Remove the given contact from god.
|
@@ -436,16 +404,16 @@ module God
|
|
436
404
|
#
|
437
405
|
# Returns nothing.
|
438
406
|
def self.uncontact(contact)
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
407
|
+
contacts.delete(contact.name)
|
408
|
+
return unless contact.group
|
409
|
+
|
410
|
+
contact_groups[contact.group].delete(contact)
|
443
411
|
end
|
444
412
|
|
445
413
|
def self.watches_by_name(name)
|
446
414
|
case name
|
447
|
-
when
|
448
|
-
else Array(
|
415
|
+
when '', nil then watches.values.dup
|
416
|
+
else Array(watches[name] || groups[name]).dup
|
449
417
|
end
|
450
418
|
end
|
451
419
|
|
@@ -458,29 +426,34 @@ module God
|
|
458
426
|
# Returns an Array of String task names affected by the command.
|
459
427
|
def self.control(name, command)
|
460
428
|
# Get the list of items.
|
461
|
-
items =
|
429
|
+
items = watches_by_name(name)
|
462
430
|
|
463
431
|
jobs = []
|
464
432
|
|
465
433
|
# Do the command.
|
466
434
|
case command
|
467
|
-
when
|
435
|
+
when 'start', 'monitor'
|
468
436
|
items.each { |w| jobs << Thread.new { w.monitor if w.state != :up } }
|
469
|
-
when
|
437
|
+
when 'restart'
|
470
438
|
items.each { |w| jobs << Thread.new { w.move(:restart) } }
|
471
|
-
when
|
472
|
-
items.each
|
473
|
-
|
439
|
+
when 'stop'
|
440
|
+
items.each do |w|
|
441
|
+
jobs << Thread.new do
|
442
|
+
w.action(:stop)
|
443
|
+
w.unmonitor if w.state != :unmonitored
|
444
|
+
end
|
445
|
+
end
|
446
|
+
when 'unmonitor'
|
474
447
|
items.each { |w| jobs << Thread.new { w.unmonitor if w.state != :unmonitored } }
|
475
|
-
when
|
476
|
-
items.each { |w|
|
448
|
+
when 'remove'
|
449
|
+
items.each { |w| unwatch(w) }
|
477
450
|
else
|
478
|
-
raise InvalidCommandError
|
451
|
+
raise InvalidCommandError
|
479
452
|
end
|
480
453
|
|
481
|
-
jobs.each
|
454
|
+
jobs.each(&:join)
|
482
455
|
|
483
|
-
items.map
|
456
|
+
items.map(&:name)
|
484
457
|
end
|
485
458
|
|
486
459
|
# Unmonitor and stop all tasks.
|
@@ -488,7 +461,7 @@ module God
|
|
488
461
|
# Returns true on success, false if all tasks could not be stopped within 10
|
489
462
|
# seconds
|
490
463
|
def self.stop_all
|
491
|
-
|
464
|
+
watches.sort.each do |_name, w|
|
492
465
|
Thread.new do
|
493
466
|
w.action(:stop)
|
494
467
|
w.unmonitor if w.state != :unmonitored
|
@@ -496,11 +469,12 @@ module God
|
|
496
469
|
end
|
497
470
|
|
498
471
|
terminate_timeout.times do
|
499
|
-
return true
|
472
|
+
return true if watches.none? { |_name, w| w.alive? }
|
473
|
+
|
500
474
|
sleep 1
|
501
475
|
end
|
502
476
|
|
503
|
-
|
477
|
+
false
|
504
478
|
end
|
505
479
|
|
506
480
|
# Force the termination of god.
|
@@ -510,8 +484,8 @@ module God
|
|
510
484
|
#
|
511
485
|
# Never returns because the process will no longer exist!
|
512
486
|
def self.terminate
|
513
|
-
FileUtils.rm_f(
|
514
|
-
|
487
|
+
FileUtils.rm_f(pid) if pid
|
488
|
+
server&.stop
|
515
489
|
exit!(0)
|
516
490
|
end
|
517
491
|
|
@@ -526,8 +500,8 @@ module God
|
|
526
500
|
# Symbol status.
|
527
501
|
def self.status
|
528
502
|
info = {}
|
529
|
-
|
530
|
-
info[name] = { :
|
503
|
+
watches.map do |name, w|
|
504
|
+
info[name] = { state: w.state, group: w.group }
|
531
505
|
end
|
532
506
|
info
|
533
507
|
end
|
@@ -542,8 +516,8 @@ module God
|
|
542
516
|
items = watches_by_name(name)
|
543
517
|
jobs = []
|
544
518
|
items.each { |w| jobs << Thread.new { w.signal(signal) } }
|
545
|
-
jobs.each
|
546
|
-
items.map
|
519
|
+
jobs.each(&:join)
|
520
|
+
items.map(&:name)
|
547
521
|
end
|
548
522
|
|
549
523
|
# Log lines for the given task since the specified time.
|
@@ -554,11 +528,9 @@ module God
|
|
554
528
|
# Raises God::NoSuchWatchError if no tasks matched.
|
555
529
|
# Returns the String of newline separated log lines.
|
556
530
|
def self.running_log(watch_name, since)
|
557
|
-
matches = pattern_match(watch_name,
|
531
|
+
matches = pattern_match(watch_name, watches.keys)
|
558
532
|
|
559
|
-
unless matches.first
|
560
|
-
raise NoSuchWatchError.new
|
561
|
-
end
|
533
|
+
raise NoSuchWatchError unless matches.first
|
562
534
|
|
563
535
|
LOG.watch_log_since(matches.first, since)
|
564
536
|
end
|
@@ -581,7 +553,7 @@ module God
|
|
581
553
|
# from the system (if 'remove' or 'stop' was
|
582
554
|
# specified as the action).
|
583
555
|
def self.running_load(code, filename, action = nil)
|
584
|
-
errors =
|
556
|
+
errors = ''
|
585
557
|
loaded_watches = []
|
586
558
|
unloaded_watches = []
|
587
559
|
jobs = []
|
@@ -590,27 +562,30 @@ module God
|
|
590
562
|
LOG.start_capture
|
591
563
|
|
592
564
|
Gem.clear_paths
|
593
|
-
eval(code, root_binding, filename)
|
594
|
-
|
595
|
-
if previous_state =
|
565
|
+
eval(code, root_binding, filename) # rubocop:disable Security/Eval
|
566
|
+
pending_watches.each do |w|
|
567
|
+
if (previous_state = pending_watch_states[w.name])
|
596
568
|
w.monitor unless previous_state == :unmonitored
|
597
|
-
|
598
|
-
w.monitor
|
569
|
+
elsif w.autostart?
|
570
|
+
w.monitor
|
599
571
|
end
|
600
572
|
end
|
601
|
-
loaded_watches =
|
602
|
-
|
603
|
-
|
573
|
+
loaded_watches = pending_watches.map(&:name)
|
574
|
+
pending_watches.clear
|
575
|
+
pending_watch_states.clear
|
604
576
|
|
605
|
-
|
577
|
+
watches.each do |name, watch|
|
606
578
|
next if loaded_watches.include?(name)
|
607
579
|
|
608
580
|
case action
|
609
581
|
when 'stop'
|
610
|
-
jobs << Thread.new(watch)
|
582
|
+
jobs << Thread.new(watch) do |w|
|
583
|
+
w.action(:stop)
|
584
|
+
unwatch(w)
|
585
|
+
end
|
611
586
|
unloaded_watches << name
|
612
587
|
when 'remove'
|
613
|
-
jobs << Thread.new(watch) { |w|
|
588
|
+
jobs << Thread.new(watch) { |w| unwatch(w) }
|
614
589
|
unloaded_watches << name
|
615
590
|
when 'leave', '', nil
|
616
591
|
# Do nothing
|
@@ -631,7 +606,7 @@ module God
|
|
631
606
|
end
|
632
607
|
end
|
633
608
|
|
634
|
-
jobs.each
|
609
|
+
jobs.each(&:join)
|
635
610
|
|
636
611
|
[loaded_watches, errors, unloaded_watches]
|
637
612
|
end
|
@@ -651,19 +626,19 @@ module God
|
|
651
626
|
#
|
652
627
|
# Returns nothing.
|
653
628
|
def self.setup
|
654
|
-
if
|
629
|
+
if pid_file_directory
|
630
|
+
dir = File.expand_path(pid_file_directory)
|
655
631
|
# Pid file dir was specified, ensure it is created and writable.
|
656
|
-
unless File.exist?(
|
632
|
+
unless File.exist?(dir)
|
657
633
|
begin
|
658
|
-
FileUtils.mkdir_p(
|
659
|
-
rescue Errno::EACCES => e
|
634
|
+
FileUtils.mkdir_p(dir)
|
635
|
+
rescue Errno::EACCES => e # rubocop:disable Metrics/BlockNesting
|
660
636
|
abort "Failed to create pid file directory: #{e.message}"
|
661
637
|
end
|
662
638
|
end
|
639
|
+
abort "The pid file directory (#{dir}) is not writable by #{Etc.getlogin}" unless File.writable?(dir)
|
663
640
|
|
664
|
-
|
665
|
-
abort "The pid file directory (#{self.pid_file_directory}) is not writable by #{Etc.getlogin}"
|
666
|
-
end
|
641
|
+
self.pid_file_directory = dir
|
667
642
|
else
|
668
643
|
# No pid file dir specified, try defaults.
|
669
644
|
PID_FILE_DIRECTORY_DEFAULTS.each do |idir|
|
@@ -674,39 +649,40 @@ module God
|
|
674
649
|
self.pid_file_directory = dir
|
675
650
|
break
|
676
651
|
end
|
677
|
-
rescue Errno::EACCES
|
652
|
+
rescue Errno::EACCES
|
653
|
+
# Ignore errors on directory creation failure here.
|
678
654
|
end
|
679
655
|
end
|
680
656
|
|
681
|
-
unless
|
657
|
+
unless pid_file_directory
|
682
658
|
dirs = PID_FILE_DIRECTORY_DEFAULTS.map { |x| File.expand_path(x) }
|
683
659
|
abort "No pid file directory exists, could be created, or is writable at any of #{dirs.join(', ')}"
|
684
660
|
end
|
685
661
|
end
|
686
662
|
|
687
663
|
if God::Logger.syslog
|
688
|
-
LOG.info(
|
664
|
+
LOG.info('Syslog enabled.')
|
689
665
|
else
|
690
|
-
LOG.info(
|
666
|
+
LOG.info('Syslog disabled.')
|
691
667
|
end
|
692
668
|
|
693
|
-
applog(nil, :info, "Using pid file directory: #{
|
669
|
+
applog(nil, :info, "Using pid file directory: #{pid_file_directory}")
|
694
670
|
end
|
695
671
|
|
696
672
|
# Initialize and startup the machinery that makes god work.
|
697
673
|
#
|
698
674
|
# Returns nothing.
|
699
675
|
def self.start
|
700
|
-
|
676
|
+
internal_init
|
701
677
|
|
702
678
|
# Instantiate server.
|
703
|
-
self.server = Socket.new(self.port,
|
679
|
+
self.server = Socket.new(self.port, socket_user, socket_group, socket_perms)
|
704
680
|
|
705
681
|
# Start monitoring any watches set to autostart.
|
706
|
-
|
682
|
+
watches.each_value { |w| w.monitor if w.autostart? }
|
707
683
|
|
708
684
|
# Clear pending watches.
|
709
|
-
|
685
|
+
pending_watches.clear
|
710
686
|
|
711
687
|
# Mark as running.
|
712
688
|
self.running = true
|
@@ -724,7 +700,7 @@ module God
|
|
724
700
|
#
|
725
701
|
# Returns nothing.
|
726
702
|
def self.join
|
727
|
-
|
703
|
+
main&.join
|
728
704
|
end
|
729
705
|
|
730
706
|
# Returns the version String.
|
@@ -736,8 +712,8 @@ module God
|
|
736
712
|
#
|
737
713
|
# Returns nothing.
|
738
714
|
def self.at_exit
|
739
|
-
|
740
|
-
|
715
|
+
start
|
716
|
+
join
|
741
717
|
end
|
742
718
|
|
743
719
|
# private
|
@@ -758,11 +734,9 @@ module God
|
|
758
734
|
#
|
759
735
|
# Returns the Array of matching name Strings.
|
760
736
|
def self.pattern_match(pattern, list)
|
761
|
-
regex = pattern.
|
737
|
+
regex = pattern.chars.join('.*')
|
762
738
|
|
763
|
-
list.
|
764
|
-
item =~ Regexp.new(regex)
|
765
|
-
end.sort_by { |x| x.size }
|
739
|
+
list.grep(Regexp.new(regex)).sort_by(&:size)
|
766
740
|
end
|
767
741
|
end
|
768
742
|
|