mcproc 2016.2.20

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.
Files changed (143) hide show
  1. checksums.yaml +7 -0
  2. data/Announce.txt +135 -0
  3. data/Gemfile +9 -0
  4. data/History.txt +469 -0
  5. data/LICENSE +22 -0
  6. data/README.md +37 -0
  7. data/Rakefile +185 -0
  8. data/TODO.md +37 -0
  9. data/bin/mcproc +134 -0
  10. data/doc/intro.asciidoc +20 -0
  11. data/doc/mcproc.asciidoc +1592 -0
  12. data/ext/god/.gitignore +5 -0
  13. data/ext/god/extconf.rb +56 -0
  14. data/ext/god/kqueue_handler.c +133 -0
  15. data/ext/god/netlink_handler.c +182 -0
  16. data/lib/god.rb +780 -0
  17. data/lib/god/behavior.rb +52 -0
  18. data/lib/god/behaviors/clean_pid_file.rb +21 -0
  19. data/lib/god/behaviors/clean_unix_socket.rb +21 -0
  20. data/lib/god/behaviors/notify_when_flapping.rb +51 -0
  21. data/lib/god/cli/command.rb +268 -0
  22. data/lib/god/cli/run.rb +170 -0
  23. data/lib/god/cli/version.rb +23 -0
  24. data/lib/god/compat19.rb +33 -0
  25. data/lib/god/condition.rb +96 -0
  26. data/lib/god/conditions/always.rb +36 -0
  27. data/lib/god/conditions/complex.rb +86 -0
  28. data/lib/god/conditions/cpu_usage.rb +80 -0
  29. data/lib/god/conditions/degrading_lambda.rb +52 -0
  30. data/lib/god/conditions/disk_usage.rb +32 -0
  31. data/lib/god/conditions/file_mtime.rb +28 -0
  32. data/lib/god/conditions/file_touched.rb +44 -0
  33. data/lib/god/conditions/flapping.rb +128 -0
  34. data/lib/god/conditions/http_response_code.rb +184 -0
  35. data/lib/god/conditions/lambda.rb +25 -0
  36. data/lib/god/conditions/memory_usage.rb +82 -0
  37. data/lib/god/conditions/process_exits.rb +66 -0
  38. data/lib/god/conditions/process_running.rb +63 -0
  39. data/lib/god/conditions/socket_responding.rb +142 -0
  40. data/lib/god/conditions/tries.rb +44 -0
  41. data/lib/god/configurable.rb +57 -0
  42. data/lib/god/contact.rb +114 -0
  43. data/lib/god/contacts/airbrake.rb +44 -0
  44. data/lib/god/contacts/campfire.rb +121 -0
  45. data/lib/god/contacts/email.rb +130 -0
  46. data/lib/god/contacts/hipchat.rb +117 -0
  47. data/lib/god/contacts/jabber.rb +75 -0
  48. data/lib/god/contacts/prowl.rb +57 -0
  49. data/lib/god/contacts/scout.rb +55 -0
  50. data/lib/god/contacts/sensu.rb +59 -0
  51. data/lib/god/contacts/slack.rb +98 -0
  52. data/lib/god/contacts/statsd.rb +46 -0
  53. data/lib/god/contacts/twitter.rb +51 -0
  54. data/lib/god/contacts/webhook.rb +74 -0
  55. data/lib/god/driver.rb +238 -0
  56. data/lib/god/errors.rb +24 -0
  57. data/lib/god/event_handler.rb +112 -0
  58. data/lib/god/event_handlers/dummy_handler.rb +13 -0
  59. data/lib/god/event_handlers/kqueue_handler.rb +17 -0
  60. data/lib/god/event_handlers/netlink_handler.rb +13 -0
  61. data/lib/god/logger.rb +109 -0
  62. data/lib/god/metric.rb +87 -0
  63. data/lib/god/process.rb +381 -0
  64. data/lib/god/registry.rb +32 -0
  65. data/lib/god/simple_logger.rb +59 -0
  66. data/lib/god/socket.rb +113 -0
  67. data/lib/god/sugar.rb +62 -0
  68. data/lib/god/sys_logger.rb +45 -0
  69. data/lib/god/system/portable_poller.rb +42 -0
  70. data/lib/god/system/process.rb +50 -0
  71. data/lib/god/system/slash_proc_poller.rb +92 -0
  72. data/lib/god/task.rb +552 -0
  73. data/lib/god/timeline.rb +25 -0
  74. data/lib/god/trigger.rb +43 -0
  75. data/lib/god/watch.rb +340 -0
  76. data/mcproc.gemspec +192 -0
  77. data/test/configs/child_events/child_events.god +44 -0
  78. data/test/configs/child_events/simple_server.rb +3 -0
  79. data/test/configs/child_polls/child_polls.god +37 -0
  80. data/test/configs/child_polls/simple_server.rb +12 -0
  81. data/test/configs/complex/complex.god +59 -0
  82. data/test/configs/complex/simple_server.rb +3 -0
  83. data/test/configs/contact/contact.god +118 -0
  84. data/test/configs/contact/simple_server.rb +3 -0
  85. data/test/configs/daemon_events/daemon_events.god +37 -0
  86. data/test/configs/daemon_events/simple_server.rb +8 -0
  87. data/test/configs/daemon_events/simple_server_stop.rb +11 -0
  88. data/test/configs/daemon_polls/daemon_polls.god +17 -0
  89. data/test/configs/daemon_polls/simple_server.rb +6 -0
  90. data/test/configs/degrading_lambda/degrading_lambda.god +31 -0
  91. data/test/configs/degrading_lambda/tcp_server.rb +15 -0
  92. data/test/configs/keepalive/keepalive.god +9 -0
  93. data/test/configs/keepalive/keepalive.rb +12 -0
  94. data/test/configs/lifecycle/lifecycle.god +25 -0
  95. data/test/configs/matias/matias.god +50 -0
  96. data/test/configs/real.rb +59 -0
  97. data/test/configs/running_load/running_load.god +16 -0
  98. data/test/configs/stop_options/simple_server.rb +12 -0
  99. data/test/configs/stop_options/stop_options.god +39 -0
  100. data/test/configs/stress/simple_server.rb +3 -0
  101. data/test/configs/stress/stress.god +15 -0
  102. data/test/configs/task/logs/.placeholder +0 -0
  103. data/test/configs/task/task.god +26 -0
  104. data/test/configs/test.rb +61 -0
  105. data/test/configs/usr1_trapper.rb +10 -0
  106. data/test/helper.rb +172 -0
  107. data/test/suite.rb +6 -0
  108. data/test/test_airbrake.rb +14 -0
  109. data/test/test_behavior.rb +18 -0
  110. data/test/test_campfire.rb +22 -0
  111. data/test/test_condition.rb +52 -0
  112. data/test/test_conditions_disk_usage.rb +50 -0
  113. data/test/test_conditions_http_response_code.rb +109 -0
  114. data/test/test_conditions_process_running.rb +40 -0
  115. data/test/test_conditions_socket_responding.rb +176 -0
  116. data/test/test_conditions_tries.rb +67 -0
  117. data/test/test_contact.rb +109 -0
  118. data/test/test_driver.rb +26 -0
  119. data/test/test_email.rb +34 -0
  120. data/test/test_event_handler.rb +82 -0
  121. data/test/test_god.rb +710 -0
  122. data/test/test_god_system.rb +201 -0
  123. data/test/test_handlers_kqueue_handler.rb +16 -0
  124. data/test/test_hipchat.rb +23 -0
  125. data/test/test_jabber.rb +29 -0
  126. data/test/test_logger.rb +55 -0
  127. data/test/test_metric.rb +74 -0
  128. data/test/test_process.rb +263 -0
  129. data/test/test_prowl.rb +15 -0
  130. data/test/test_registry.rb +15 -0
  131. data/test/test_sensu.rb +11 -0
  132. data/test/test_slack.rb +57 -0
  133. data/test/test_socket.rb +34 -0
  134. data/test/test_statsd.rb +22 -0
  135. data/test/test_sugar.rb +42 -0
  136. data/test/test_system_portable_poller.rb +17 -0
  137. data/test/test_system_process.rb +30 -0
  138. data/test/test_task.rb +246 -0
  139. data/test/test_timeline.rb +37 -0
  140. data/test/test_trigger.rb +63 -0
  141. data/test/test_watch.rb +286 -0
  142. data/test/test_webhook.rb +22 -0
  143. metadata +475 -0
@@ -0,0 +1,25 @@
1
+ God::Contacts::Twitter.settings = {
2
+ # this is for my 'mojombo2' twitter test account
3
+ # feel free to use it for testing your conditions
4
+ :username => 'mojombo@gmail.com',
5
+ :password => 'gok9we3ot1av2e'
6
+ }
7
+
8
+ God.contact(:twitter) do |c|
9
+ c.name = 'tom2'
10
+ c.group = 'developers'
11
+ end
12
+
13
+ God.watch do |w|
14
+ w.name = "lifecycle"
15
+ w.interval = 5.seconds
16
+ w.start = "/dev/null"
17
+
18
+ # lifecycle
19
+ w.lifecycle do |on|
20
+ on.condition(:always) do |c|
21
+ c.what = true
22
+ c.notify = "tom2"
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,50 @@
1
+ $pid_file = "/tmp/matias.pid"
2
+
3
+ God.task do |w|
4
+ w.name = "watcher"
5
+ w.interval = 5.seconds
6
+ w.valid_states = [:init, :up, :down]
7
+ w.initial_state = :init
8
+
9
+ # determine the state on startup
10
+ w.transition(:init, { true => :up, false => :down }) do |on|
11
+ on.condition(:process_running) do |c|
12
+ c.running = true
13
+ c.pid_file = $pid_file
14
+ end
15
+ end
16
+
17
+ # when process is up
18
+ w.transition(:up, :down) do |on|
19
+ # transition to 'start' if process goes down
20
+ on.condition(:process_running) do |c|
21
+ c.running = false
22
+ c.pid_file = $pid_file
23
+ end
24
+
25
+ # send up info
26
+ on.condition(:lambda) do |c|
27
+ c.lambda = lambda do
28
+ puts 'yay I am up'
29
+ false
30
+ end
31
+ end
32
+ end
33
+
34
+ # when process is down
35
+ w.transition(:down, :up) do |on|
36
+ # transition to 'up' if process comes up
37
+ on.condition(:process_running) do |c|
38
+ c.running = true
39
+ c.pid_file = $pid_file
40
+ end
41
+
42
+ # send down info
43
+ on.condition(:lambda) do |c|
44
+ c.lambda = lambda do
45
+ puts 'boo I am down'
46
+ false
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,59 @@
1
+ if $0 == __FILE__
2
+ require File.join(File.dirname(__FILE__), *%w[.. .. lib god])
3
+ end
4
+
5
+ RAILS_ROOT = "/Users/tom/dev/git/helloworld"
6
+
7
+ God.watch do |w|
8
+ w.name = "local-3000"
9
+ w.interval = 5 # seconds
10
+ w.start = "mongrel_rails start -P ./log/mongrel.pid -c #{RAILS_ROOT} -d"
11
+ w.stop = "mongrel_rails stop -P ./log/mongrel.pid -c #{RAILS_ROOT}"
12
+ w.grace = 5
13
+
14
+ pid_file = File.join(RAILS_ROOT, "log/mongrel.pid")
15
+
16
+ # clean pid files before start if necessary
17
+ w.behavior(:clean_pid_file) do |b|
18
+ b.pid_file = pid_file
19
+ end
20
+
21
+ # start if process is not running
22
+ w.start_if do |start|
23
+ start.condition(:process_running) do |c|
24
+ c.running = false
25
+ c.pid_file = pid_file
26
+ end
27
+ end
28
+
29
+ # restart if memory or cpu is too high
30
+ w.restart_if do |restart|
31
+ restart.condition(:memory_usage) do |c|
32
+ c.interval = 20
33
+ c.pid_file = pid_file
34
+ c.above = (50 * 1024) # 50mb
35
+ c.times = [3, 5]
36
+ end
37
+
38
+ restart.condition(:cpu_usage) do |c|
39
+ c.interval = 10
40
+ c.pid_file = pid_file
41
+ c.above = 10 # percent
42
+ c.times = [3, 5]
43
+ end
44
+ end
45
+ end
46
+
47
+ # clear old session files
48
+ # god.watch do |w|
49
+ # w.name = "local-session-cleanup"
50
+ # w.start = lambda do
51
+ # Dir["#{RAILS_ROOT}/tmp/sessions/ruby_sess.*"].select do |f|
52
+ # File.mtime(f) < Time.now - (7 * 24 * 60 * 60)
53
+ # end.each { |f| File.delete(f) }
54
+ # end
55
+ #
56
+ # w.start_if do |start|
57
+ # start.condition(:always)
58
+ # end
59
+ # end
@@ -0,0 +1,16 @@
1
+ God.watch do |w|
2
+ w.name = 'running-load'
3
+ w.start = '/Users/tom/dev/god/test/configs/child_polls/simple_server.rb'
4
+ w.stop = ''
5
+ w.interval = 5
6
+ w.grace = 2
7
+ w.uid = 'tom'
8
+ w.gid = 'tom'
9
+ w.group = 'test'
10
+
11
+ w.start_if do |start|
12
+ start.condition(:process_running) do |c|
13
+ c.running = false
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ trap :USR1 do
4
+
5
+ end
6
+
7
+ loop do
8
+ STDOUT.puts('server');
9
+ STDOUT.flush;
10
+
11
+ sleep 10
12
+ end
@@ -0,0 +1,39 @@
1
+ God.watch do |w|
2
+ w.name = 'stop-options'
3
+ w.start = File.join(GOD_ROOT, *%w[test configs stop_options simple_server.rb])
4
+ w.stop_signal = 'USR1'
5
+ w.stop_timeout = 5
6
+ w.interval = 5
7
+ w.grace = 2
8
+
9
+ w.start_if do |start|
10
+ start.condition(:process_running) do |c|
11
+ c.running = false
12
+ end
13
+ end
14
+
15
+ w.restart_if do |restart|
16
+ restart.condition(:cpu_usage) do |c|
17
+ c.above = 30.percent
18
+ c.times = [3, 5]
19
+ end
20
+
21
+ restart.condition(:memory_usage) do |c|
22
+ c.above = 10.megabytes
23
+ c.times = [3, 5]
24
+ end
25
+ end
26
+
27
+ # lifecycle
28
+ w.lifecycle do |on|
29
+ on.condition(:flapping) do |c|
30
+ c.to_state = [:start, :restart]
31
+ c.times = 3
32
+ c.within = 60.seconds
33
+ c.transition = :unmonitored
34
+ c.retry_in = 10.seconds
35
+ c.retry_times = 2
36
+ c.retry_within = 5.minutes
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,3 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ loop { puts 'server'; sleep 1 }
@@ -0,0 +1,15 @@
1
+ ('01'..'08').each do |i|
2
+ God.watch do |w|
3
+ w.name = "stress-#{i}"
4
+ w.start = "ruby " + File.join(File.dirname(__FILE__), *%w[simple_server.rb])
5
+ w.interval = 0
6
+ w.grace = 2
7
+ w.group = 'test'
8
+
9
+ w.start_if do |start|
10
+ start.condition(:process_running) do |c|
11
+ c.running = false
12
+ end
13
+ end
14
+ end
15
+ end
File without changes
@@ -0,0 +1,26 @@
1
+ LOG_DIR = File.join(File.dirname(__FILE__), *%w[logs])
2
+
3
+ God.task do |t|
4
+ t.name = 'task'
5
+ t.valid_states = [:ok, :clean]
6
+ t.initial_state = :ok
7
+ t.interval = 5
8
+
9
+ # t.clean = lambda do
10
+ # Dir[File.join(LOG_DIR, '*.log')].each do |f|
11
+ # File.delete(f)
12
+ # end
13
+ # end
14
+
15
+ t.clean = "rm #{File.join(LOG_DIR, '*.log')}"
16
+
17
+ t.transition(:clean, :ok)
18
+
19
+ t.transition(:ok, :clean) do |on|
20
+ on.condition(:lambda) do |c|
21
+ c.lambda = lambda do
22
+ Dir[File.join(LOG_DIR, '*.log')].size > 1
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,61 @@
1
+ ENV['GOD_TEST_RAILS_ROOT'] || abort("Set a rails root for testing in an environment variable called GOD_TEST_RAILS_ROOT")
2
+
3
+ RAILS_ROOT = ENV['GOD_TEST_RAILS_ROOT']
4
+
5
+ port = 5000
6
+
7
+ God.watch do |w|
8
+ w.name = "local-#{port}"
9
+ w.interval = 5.seconds
10
+ w.start = "mongrel_rails start -P ./log/mongrel.pid -c #{RAILS_ROOT} -p #{port} -d"
11
+ w.restart = "mongrel_rails restart -P ./log/mongrel.pid -c #{RAILS_ROOT}"
12
+ w.stop = "mongrel_rails stop -P ./log/mongrel.pid -c #{RAILS_ROOT}"
13
+ w.group = 'mongrels'
14
+ w.pid_file = File.join(RAILS_ROOT, "log/mongrel.pid")
15
+
16
+ # clean pid files before start if necessary
17
+ w.behavior(:clean_pid_file)
18
+
19
+ # determine the state on startup
20
+ w.transition(:init, { true => :up, false => :start }) do |on|
21
+ on.condition(:process_running) do |c|
22
+ c.running = true
23
+ end
24
+ end
25
+
26
+ # determine when process has finished starting
27
+ w.transition([:start, :restart], :up) do |on|
28
+ on.condition(:process_running) do |c|
29
+ c.running = true
30
+ end
31
+ end
32
+
33
+ # start if process is not running
34
+ w.transition(:up, :start) do |on|
35
+ on.condition(:process_exits)
36
+ end
37
+
38
+ # restart if memory or cpu is too high
39
+ w.transition(:up, :restart) do |on|
40
+ on.condition(:memory_usage) do |c|
41
+ c.interval = 1
42
+ c.above = 50.megabytes
43
+ c.times = [3, 5]
44
+ end
45
+
46
+ on.condition(:cpu_usage) do |c|
47
+ c.interval = 1
48
+ c.above = 10.percent
49
+ c.times = [3, 5]
50
+ end
51
+
52
+ on.condition(:http_response_code) do |c|
53
+ c.host = 'localhost'
54
+ c.port = port
55
+ c.path = '/'
56
+ c.code_is_not = 200
57
+ c.timeout = 10.seconds
58
+ c.times = [3, 5]
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,10 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ Signal.trap 'USR1' do
4
+ puts "can't stop won't stop"
5
+ end
6
+
7
+ loop do
8
+ puts 'server'
9
+ sleep 1
10
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,172 @@
1
+ $:.unshift File.expand_path('../../lib', __FILE__) # For use/testing when no gem is installed
2
+
3
+ # Use this flag to actually load all of the god infrastructure
4
+ $load_god = true
5
+
6
+ require File.join(File.dirname(__FILE__), *%w[.. lib god sys_logger])
7
+ require File.join(File.dirname(__FILE__), *%w[.. lib god])
8
+ God::EventHandler.load
9
+
10
+ require 'minitest/autorun'
11
+ require 'minitest/unit'
12
+ require 'set'
13
+
14
+ include God
15
+
16
+ if Process.uid != 0 and RbConfig::CONFIG['host_os'] == "linux"
17
+ abort <<-EOF
18
+ \n
19
+ *********************************************************************
20
+ * *
21
+ * You need to run these tests as root *
22
+ * chroot and netlink (linux only) require it *
23
+ * *
24
+ *********************************************************************
25
+ EOF
26
+ end
27
+
28
+ begin
29
+ require 'mocha/setup'
30
+ rescue LoadError
31
+ unless gems ||= false
32
+ require 'rubygems'
33
+ gems = true
34
+ retry
35
+ else
36
+ abort "=> You need the Mocha gem to run these tests."
37
+ end
38
+ end
39
+
40
+ module God
41
+ module Conditions
42
+ class FakeCondition < Condition
43
+ def test
44
+ true
45
+ end
46
+ end
47
+
48
+ class FakePollCondition < PollCondition
49
+ def test
50
+ true
51
+ end
52
+ end
53
+
54
+ class FakeEventCondition < EventCondition
55
+ def register
56
+ end
57
+ def deregister
58
+ end
59
+ end
60
+ end
61
+
62
+ module Behaviors
63
+ class FakeBehavior < Behavior
64
+ def before_start
65
+ 'foo'
66
+ end
67
+ def after_start
68
+ 'bar'
69
+ end
70
+ end
71
+ end
72
+
73
+ module Contacts
74
+ class FakeContact < Contact
75
+ end
76
+
77
+ class InvalidContact
78
+ end
79
+ end
80
+
81
+ def self.reset
82
+ self.watches = nil
83
+ self.groups = nil
84
+ self.server = nil
85
+ self.inited = nil
86
+ self.host = nil
87
+ self.port = nil
88
+ self.pid_file_directory = nil
89
+ self.registry.reset
90
+ end
91
+ end
92
+
93
+ def silence_warnings
94
+ old_verbose, $VERBOSE = $VERBOSE, nil
95
+ yield
96
+ ensure
97
+ $VERBOSE = old_verbose
98
+ end
99
+
100
+ LOG.instance_variable_set(:@io, StringIO.new())
101
+
102
+ def output_logs
103
+ io = LOG.instance_variable_get(:@io)
104
+ LOG.instance_variable_set(:@io, $stderr)
105
+ yield
106
+ ensure
107
+ LOG.instance_variable_set(:@io, io)
108
+ end
109
+
110
+ # module Kernel
111
+ # def abort(text)
112
+ # raise SystemExit, text
113
+ # end
114
+ # def exit(code)
115
+ # raise SystemExit, "Exit code: #{code}"
116
+ # end
117
+ # end
118
+
119
+ module Minitest::Assertions
120
+ def assert_abort
121
+ assert_raises SystemExit do
122
+ yield
123
+ end
124
+ end
125
+
126
+ def assert_nothing_raised
127
+ yield
128
+ end
129
+ end
130
+
131
+ # This allows you to be a good OOP citizen and honor encapsulation, but
132
+ # still make calls to private methods (for testing) by doing
133
+ #
134
+ # obj.bypass.private_thingie(arg1, arg2)
135
+ #
136
+ # Which is easier on the eye than
137
+ #
138
+ # obj.send(:private_thingie, arg1, arg2)
139
+ #
140
+ class Object
141
+ class Bypass
142
+ instance_methods.each do |m|
143
+ undef_method m unless m =~ /^(__|object_id)/
144
+ end
145
+
146
+ def initialize(ref)
147
+ @ref = ref
148
+ end
149
+
150
+ def method_missing(sym, *args)
151
+ @ref.__send__(sym, *args)
152
+ end
153
+ end
154
+
155
+ def bypass
156
+ Bypass.new(self)
157
+ end
158
+ end
159
+
160
+ # Make sure we return valid exit codes
161
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby" && RUBY_VERSION >= "1.9"
162
+ module Kernel
163
+ alias :__at_exit :at_exit
164
+ def at_exit(&block)
165
+ __at_exit do
166
+ exit_status = $!.status if $!.is_a?(SystemExit)
167
+ block.call
168
+ exit exit_status if exit_status
169
+ end
170
+ end
171
+ end
172
+ end