resurrected_god 0.14.0

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 (141) hide show
  1. checksums.yaml +7 -0
  2. data/Announce.txt +135 -0
  3. data/Gemfile +5 -0
  4. data/LICENSE +22 -0
  5. data/README.md +33 -0
  6. data/Rakefile +129 -0
  7. data/bin/god +134 -0
  8. data/doc/god.asciidoc +1592 -0
  9. data/doc/intro.asciidoc +20 -0
  10. data/ext/god/.gitignore +5 -0
  11. data/ext/god/extconf.rb +56 -0
  12. data/ext/god/kqueue_handler.c +133 -0
  13. data/ext/god/netlink_handler.c +182 -0
  14. data/lib/god/behavior.rb +52 -0
  15. data/lib/god/behaviors/clean_pid_file.rb +21 -0
  16. data/lib/god/behaviors/clean_unix_socket.rb +21 -0
  17. data/lib/god/behaviors/notify_when_flapping.rb +51 -0
  18. data/lib/god/cli/command.rb +268 -0
  19. data/lib/god/cli/run.rb +170 -0
  20. data/lib/god/cli/version.rb +23 -0
  21. data/lib/god/compat19.rb +33 -0
  22. data/lib/god/condition.rb +96 -0
  23. data/lib/god/conditions/always.rb +36 -0
  24. data/lib/god/conditions/complex.rb +86 -0
  25. data/lib/god/conditions/cpu_usage.rb +80 -0
  26. data/lib/god/conditions/degrading_lambda.rb +52 -0
  27. data/lib/god/conditions/disk_usage.rb +32 -0
  28. data/lib/god/conditions/file_mtime.rb +28 -0
  29. data/lib/god/conditions/file_touched.rb +44 -0
  30. data/lib/god/conditions/flapping.rb +128 -0
  31. data/lib/god/conditions/http_response_code.rb +184 -0
  32. data/lib/god/conditions/lambda.rb +25 -0
  33. data/lib/god/conditions/memory_usage.rb +82 -0
  34. data/lib/god/conditions/process_exits.rb +66 -0
  35. data/lib/god/conditions/process_running.rb +63 -0
  36. data/lib/god/conditions/socket_responding.rb +142 -0
  37. data/lib/god/conditions/tries.rb +44 -0
  38. data/lib/god/configurable.rb +57 -0
  39. data/lib/god/contact.rb +114 -0
  40. data/lib/god/contacts/airbrake.rb +44 -0
  41. data/lib/god/contacts/campfire.rb +121 -0
  42. data/lib/god/contacts/email.rb +130 -0
  43. data/lib/god/contacts/hipchat.rb +117 -0
  44. data/lib/god/contacts/jabber.rb +75 -0
  45. data/lib/god/contacts/prowl.rb +57 -0
  46. data/lib/god/contacts/scout.rb +55 -0
  47. data/lib/god/contacts/sensu.rb +59 -0
  48. data/lib/god/contacts/slack.rb +98 -0
  49. data/lib/god/contacts/statsd.rb +46 -0
  50. data/lib/god/contacts/twitter.rb +51 -0
  51. data/lib/god/contacts/webhook.rb +74 -0
  52. data/lib/god/driver.rb +238 -0
  53. data/lib/god/errors.rb +24 -0
  54. data/lib/god/event_handler.rb +112 -0
  55. data/lib/god/event_handlers/dummy_handler.rb +13 -0
  56. data/lib/god/event_handlers/kqueue_handler.rb +17 -0
  57. data/lib/god/event_handlers/netlink_handler.rb +13 -0
  58. data/lib/god/logger.rb +109 -0
  59. data/lib/god/metric.rb +87 -0
  60. data/lib/god/process.rb +381 -0
  61. data/lib/god/registry.rb +32 -0
  62. data/lib/god/simple_logger.rb +59 -0
  63. data/lib/god/socket.rb +113 -0
  64. data/lib/god/sugar.rb +62 -0
  65. data/lib/god/sys_logger.rb +45 -0
  66. data/lib/god/system/portable_poller.rb +42 -0
  67. data/lib/god/system/process.rb +50 -0
  68. data/lib/god/system/slash_proc_poller.rb +92 -0
  69. data/lib/god/task.rb +552 -0
  70. data/lib/god/timeline.rb +25 -0
  71. data/lib/god/trigger.rb +43 -0
  72. data/lib/god/version.rb +4 -0
  73. data/lib/god/watch.rb +340 -0
  74. data/lib/god.rb +777 -0
  75. data/test/configs/child_events/child_events.god +44 -0
  76. data/test/configs/child_events/simple_server.rb +3 -0
  77. data/test/configs/child_polls/child_polls.god +37 -0
  78. data/test/configs/child_polls/simple_server.rb +12 -0
  79. data/test/configs/complex/complex.god +59 -0
  80. data/test/configs/complex/simple_server.rb +3 -0
  81. data/test/configs/contact/contact.god +118 -0
  82. data/test/configs/contact/simple_server.rb +3 -0
  83. data/test/configs/daemon_events/daemon_events.god +37 -0
  84. data/test/configs/daemon_events/simple_server.rb +8 -0
  85. data/test/configs/daemon_events/simple_server_stop.rb +11 -0
  86. data/test/configs/daemon_polls/daemon_polls.god +17 -0
  87. data/test/configs/daemon_polls/simple_server.rb +6 -0
  88. data/test/configs/degrading_lambda/degrading_lambda.god +31 -0
  89. data/test/configs/degrading_lambda/tcp_server.rb +15 -0
  90. data/test/configs/keepalive/keepalive.god +9 -0
  91. data/test/configs/keepalive/keepalive.rb +12 -0
  92. data/test/configs/lifecycle/lifecycle.god +25 -0
  93. data/test/configs/matias/matias.god +50 -0
  94. data/test/configs/real.rb +59 -0
  95. data/test/configs/running_load/running_load.god +16 -0
  96. data/test/configs/stop_options/simple_server.rb +12 -0
  97. data/test/configs/stop_options/stop_options.god +39 -0
  98. data/test/configs/stress/simple_server.rb +3 -0
  99. data/test/configs/stress/stress.god +15 -0
  100. data/test/configs/task/logs/.placeholder +0 -0
  101. data/test/configs/task/task.god +26 -0
  102. data/test/configs/test.rb +61 -0
  103. data/test/configs/usr1_trapper.rb +10 -0
  104. data/test/helper.rb +172 -0
  105. data/test/suite.rb +6 -0
  106. data/test/test_airbrake.rb +14 -0
  107. data/test/test_behavior.rb +18 -0
  108. data/test/test_campfire.rb +22 -0
  109. data/test/test_condition.rb +52 -0
  110. data/test/test_conditions_disk_usage.rb +50 -0
  111. data/test/test_conditions_http_response_code.rb +109 -0
  112. data/test/test_conditions_process_running.rb +40 -0
  113. data/test/test_conditions_socket_responding.rb +176 -0
  114. data/test/test_conditions_tries.rb +67 -0
  115. data/test/test_contact.rb +109 -0
  116. data/test/test_driver.rb +26 -0
  117. data/test/test_email.rb +34 -0
  118. data/test/test_event_handler.rb +82 -0
  119. data/test/test_god.rb +710 -0
  120. data/test/test_god_system.rb +201 -0
  121. data/test/test_handlers_kqueue_handler.rb +16 -0
  122. data/test/test_hipchat.rb +23 -0
  123. data/test/test_jabber.rb +29 -0
  124. data/test/test_logger.rb +55 -0
  125. data/test/test_metric.rb +74 -0
  126. data/test/test_process.rb +263 -0
  127. data/test/test_prowl.rb +15 -0
  128. data/test/test_registry.rb +15 -0
  129. data/test/test_sensu.rb +11 -0
  130. data/test/test_slack.rb +57 -0
  131. data/test/test_socket.rb +34 -0
  132. data/test/test_statsd.rb +22 -0
  133. data/test/test_sugar.rb +42 -0
  134. data/test/test_system_portable_poller.rb +17 -0
  135. data/test/test_system_process.rb +30 -0
  136. data/test/test_task.rb +246 -0
  137. data/test/test_timeline.rb +37 -0
  138. data/test/test_trigger.rb +63 -0
  139. data/test/test_watch.rb +286 -0
  140. data/test/test_webhook.rb +22 -0
  141. metadata +476 -0
@@ -0,0 +1,20 @@
1
+ God: The Ruby Framework for Process Management
2
+ ==============================================
3
+ Tom Preston-Werner <tom@mojombo.com>
4
+
5
+ God is an easy to configure, easy to extend monitoring framework written in
6
+ Ruby.
7
+
8
+ Keeping your server processes and tasks running should be a simple part of
9
+ your deployment process. God aims to be the simplest, most powerful monitoring
10
+ application available.
11
+
12
+ Features
13
+ --------
14
+
15
+ * Config file is written in Ruby
16
+ * Easily write your own custom conditions in Ruby
17
+ * Supports both poll and event based conditions
18
+ * Different poll conditions can have different intervals
19
+ * Integrated notification system (write your own too!)
20
+ * Easily control non-daemonizing scripts
@@ -0,0 +1,5 @@
1
+ Makefile
2
+ kqueue_handler_ext.bundle
3
+ kqueue_handler.o
4
+ netlink_handler_ext.bundle
5
+ netlink_handler.o
@@ -0,0 +1,56 @@
1
+ require 'mkmf'
2
+
3
+ fail = false
4
+
5
+ def create_dummy_makefile
6
+ File.open("Makefile", 'w') do |f|
7
+ f.puts "all:"
8
+ f.puts "install:"
9
+ end
10
+ end
11
+
12
+ have_func('rb_wait_for_single_fd')
13
+ case RUBY_PLATFORM
14
+ when /bsd/i, /darwin/i
15
+ unless have_header('sys/event.h')
16
+ puts
17
+ puts "Missing 'sys/event.h' header"
18
+ fail = true
19
+ end
20
+
21
+ if fail
22
+ puts
23
+ puts "Events handler could not be compiled (see above error). Your god installation will not support event conditions."
24
+ create_dummy_makefile
25
+ else
26
+ create_makefile 'kqueue_handler_ext'
27
+ end
28
+ when /linux/i
29
+ unless have_header('linux/netlink.h')
30
+ puts
31
+ puts "Missing 'linux/netlink.h' header(s)"
32
+ puts "You may need to install a header package for your system"
33
+ fail = true
34
+ end
35
+
36
+ unless have_header('linux/connector.h') && have_header('linux/cn_proc.h')
37
+ puts
38
+ puts "Missing 'linux/connector.h', or 'linux/cn_proc.h' header(s)"
39
+ puts "These are only available in Linux kernel 2.6.15 and later (run `uname -a` to find yours)"
40
+ puts "You may need to install a header package for your system"
41
+ fail = true
42
+ end
43
+
44
+ if fail
45
+ puts
46
+ puts "Events handler could not be compiled (see above error). Your god installation will not support event conditions."
47
+ create_dummy_makefile
48
+ else
49
+ create_makefile 'netlink_handler_ext'
50
+ end
51
+ else
52
+ puts
53
+ puts "Unsupported platform '#{RUBY_PLATFORM}'. Supported platforms are BSD, DARWIN, and LINUX."
54
+ puts "Your god installation will not support event conditions."
55
+ create_dummy_makefile
56
+ end
@@ -0,0 +1,133 @@
1
+ #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__)
2
+
3
+ #include <ruby.h>
4
+ #include <sys/event.h>
5
+ #include <sys/time.h>
6
+ #include <errno.h>
7
+
8
+ #ifdef HAVE_RB_WAIT_FOR_SINGLE_FD
9
+ #include <ruby/io.h>
10
+ #endif
11
+
12
+ static VALUE mGod;
13
+ static VALUE cKQueueHandler;
14
+ static VALUE cEventHandler;
15
+
16
+ static ID proc_exit;
17
+ static ID proc_fork;
18
+ static ID m_call;
19
+ static ID m_size;
20
+ static ID m_deregister;
21
+
22
+ static int kq;
23
+ int num_events;
24
+
25
+ #define NUM_EVENTS FIX2INT(rb_funcall(rb_cv_get(cEventHandler, "@@actions"), m_size, 0))
26
+
27
+ VALUE
28
+ kqh_event_mask(VALUE klass, VALUE sym)
29
+ {
30
+ ID id = SYM2ID(sym);
31
+ if (proc_exit == id) {
32
+ return UINT2NUM(NOTE_EXIT);
33
+ } else if (proc_fork == id) {
34
+ return UINT2NUM(NOTE_FORK);
35
+ } else {
36
+ rb_raise(rb_eNotImpError, "Event `%s` not implemented", rb_id2name(id));
37
+ }
38
+
39
+ return Qnil;
40
+ }
41
+
42
+
43
+ VALUE
44
+ kqh_monitor_process(VALUE klass, VALUE pid, VALUE mask)
45
+ {
46
+ struct kevent new_event;
47
+ ID event;
48
+
49
+ (void)event; //!< Silence warning about unused var, should be removed?
50
+
51
+ u_int fflags = NUM2UINT(mask);
52
+
53
+ EV_SET(&new_event, FIX2UINT(pid), EVFILT_PROC,
54
+ EV_ADD | EV_ENABLE, fflags, 0, 0);
55
+
56
+ if (-1 == kevent(kq, &new_event, 1, NULL, 0, NULL)) {
57
+ rb_raise(rb_eStandardError, "%s", strerror(errno));
58
+ }
59
+
60
+ num_events = NUM_EVENTS;
61
+
62
+ return Qnil;
63
+ }
64
+
65
+ VALUE
66
+ kqh_handle_events()
67
+ {
68
+ int nevents, i, num_to_fetch;
69
+ struct kevent *events;
70
+
71
+ #ifdef HAVE_RB_WAIT_FOR_SINGLE_FD
72
+ rb_wait_for_single_fd(kq, RB_WAITFD_IN, NULL);
73
+ #else
74
+ fd_set read_set;
75
+
76
+ FD_ZERO(&read_set);
77
+ FD_SET(kq, &read_set);
78
+
79
+ // Don't actually run this method until we've got an event
80
+ rb_thread_select(kq + 1, &read_set, NULL, NULL, NULL);
81
+ #endif
82
+ // Grabbing num_events once for thread safety
83
+ num_to_fetch = num_events;
84
+ events = (struct kevent*)malloc(num_to_fetch * sizeof(struct kevent));
85
+
86
+ if (NULL == events) {
87
+ rb_raise(rb_eStandardError, "%s", strerror(errno));
88
+ }
89
+
90
+ nevents = kevent(kq, NULL, 0, events, num_to_fetch, NULL);
91
+
92
+ if (-1 == nevents) {
93
+ free(events);
94
+ rb_raise(rb_eStandardError, "%s", strerror(errno));
95
+ } else {
96
+ for (i = 0; i < nevents; i++) {
97
+ if (events[i].fflags & NOTE_EXIT) {
98
+ rb_funcall(cEventHandler, m_call, 2, INT2NUM(events[i].ident), ID2SYM(proc_exit));
99
+ } else if (events[i].fflags & NOTE_FORK) {
100
+ rb_funcall(cEventHandler, m_call, 2, INT2NUM(events[i].ident), ID2SYM(proc_fork));
101
+ }
102
+ }
103
+ }
104
+
105
+ free(events);
106
+
107
+ return INT2FIX(nevents);
108
+ }
109
+
110
+ void
111
+ Init_kqueue_handler_ext()
112
+ {
113
+ kq = kqueue();
114
+
115
+ if (kq == -1) {
116
+ rb_raise(rb_eStandardError, "kqueue initialization failed");
117
+ }
118
+
119
+ proc_exit = rb_intern("proc_exit");
120
+ proc_fork = rb_intern("proc_fork");
121
+ m_call = rb_intern("call");
122
+ m_size = rb_intern("size");
123
+ m_deregister = rb_intern("deregister");
124
+
125
+ mGod = rb_const_get(rb_cObject, rb_intern("God"));
126
+ cEventHandler = rb_const_get(mGod, rb_intern("EventHandler"));
127
+ cKQueueHandler = rb_define_class_under(mGod, "KQueueHandler", rb_cObject);
128
+ rb_define_singleton_method(cKQueueHandler, "monitor_process", kqh_monitor_process, 2);
129
+ rb_define_singleton_method(cKQueueHandler, "handle_events", kqh_handle_events, 0);
130
+ rb_define_singleton_method(cKQueueHandler, "event_mask", kqh_event_mask, 1);
131
+ }
132
+
133
+ #endif
@@ -0,0 +1,182 @@
1
+ #ifdef __linux__ /* only build on linux */
2
+
3
+ #include <ruby.h>
4
+
5
+ #ifdef HAVE_RB_WAIT_FOR_SINGLE_FD
6
+ #include <ruby/io.h>
7
+ #endif
8
+
9
+
10
+ #include <sys/types.h>
11
+ #include <unistd.h>
12
+ #include <sys/socket.h>
13
+ #include <linux/netlink.h>
14
+ #include <linux/connector.h>
15
+ #define _LINUX_TIME_H
16
+ #include <linux/cn_proc.h>
17
+ #include <errno.h>
18
+
19
+ static VALUE mGod;
20
+ static VALUE cNetlinkHandler;
21
+ static VALUE cEventHandler;
22
+
23
+ static ID proc_exit;
24
+ static ID proc_fork;
25
+ static ID m_call;
26
+ static ID m_watching_pid;
27
+
28
+ static int nl_sock; /* socket for netlink connection */
29
+
30
+
31
+ VALUE
32
+ nlh_handle_events()
33
+ {
34
+ char buff[CONNECTOR_MAX_MSG_SIZE];
35
+ struct nlmsghdr *hdr;
36
+ struct proc_event *event;
37
+
38
+ VALUE extra_data;
39
+
40
+ #ifdef HAVE_RB_WAIT_FOR_SINGLE_FD
41
+ int ret;
42
+ if((ret = rb_wait_for_single_fd(nl_sock, RB_WAITFD_IN, NULL)) < 0){
43
+ rb_raise(rb_eStandardError, "%s", strerror(errno));
44
+ }
45
+ /* If there were no events detected, return */
46
+ if(!(ret & RB_WAITFD_IN)){
47
+ return INT2FIX(0);
48
+ }
49
+ #else
50
+ fd_set fds;
51
+
52
+ FD_ZERO(&fds);
53
+ FD_SET(nl_sock, &fds);
54
+
55
+ if (0 > rb_thread_select(nl_sock + 1, &fds, NULL, NULL, NULL)) {
56
+ rb_raise(rb_eStandardError, "%s", strerror(errno));
57
+ }
58
+
59
+ /* If there were no events detected, return */
60
+ if (! FD_ISSET(nl_sock, &fds)) {
61
+ return INT2FIX(0);
62
+ }
63
+ #endif
64
+
65
+ /* if there are events, make calls */
66
+ if (-1 == recv(nl_sock, buff, sizeof(buff), 0)) {
67
+ rb_raise(rb_eStandardError, "%s", strerror(errno));
68
+ }
69
+
70
+ hdr = (struct nlmsghdr *)buff;
71
+
72
+ if (NLMSG_ERROR == hdr->nlmsg_type) {
73
+ rb_raise(rb_eStandardError, "%s", strerror(errno));
74
+ } else if (NLMSG_DONE == hdr->nlmsg_type) {
75
+
76
+ event = (struct proc_event *)((struct cn_msg *)NLMSG_DATA(hdr))->data;
77
+
78
+ switch(event->what) {
79
+ case PROC_EVENT_EXIT:
80
+ if (Qnil == rb_funcall(cEventHandler, m_watching_pid, 1, INT2FIX(event->event_data.exit.process_pid))) {
81
+ return INT2FIX(0);
82
+ }
83
+
84
+ extra_data = rb_hash_new();
85
+ rb_hash_aset(extra_data, ID2SYM(rb_intern("pid")), INT2FIX(event->event_data.exit.process_pid));
86
+ rb_hash_aset(extra_data, ID2SYM(rb_intern("exit_code")), INT2FIX(event->event_data.exit.exit_code));
87
+ rb_hash_aset(extra_data, ID2SYM(rb_intern("exit_signal")), INT2FIX(event->event_data.exit.exit_signal));
88
+ rb_hash_aset(extra_data, ID2SYM(rb_intern("thread_group_id")), INT2FIX(event->event_data.exit.process_tgid));
89
+
90
+ rb_funcall(cEventHandler, m_call, 3, INT2FIX(event->event_data.exit.process_pid), ID2SYM(proc_exit), extra_data);
91
+ return INT2FIX(1);
92
+
93
+ case PROC_EVENT_FORK:
94
+ if (Qnil == rb_funcall(cEventHandler, m_watching_pid, 1, INT2FIX(event->event_data.fork.parent_pid))) {
95
+ return INT2FIX(0);
96
+ }
97
+
98
+ extra_data = rb_hash_new();
99
+ rb_hash_aset(extra_data, ID2SYM(rb_intern("parent_pid")), INT2FIX(event->event_data.fork.parent_pid));
100
+ rb_hash_aset(extra_data, ID2SYM(rb_intern("parent_thread_group_id")), INT2FIX(event->event_data.fork.parent_tgid));
101
+ rb_hash_aset(extra_data, ID2SYM(rb_intern("child_pid")), INT2FIX(event->event_data.fork.child_pid));
102
+ rb_hash_aset(extra_data, ID2SYM(rb_intern("child_thread_group_id")), INT2FIX(event->event_data.fork.child_tgid));
103
+
104
+ rb_funcall(cEventHandler, m_call, 3, INT2FIX(event->event_data.fork.parent_pid), ID2SYM(proc_fork), extra_data);
105
+ return INT2FIX(1);
106
+
107
+ default:
108
+ break;
109
+ }
110
+ }
111
+
112
+ return Qnil;
113
+ }
114
+
115
+
116
+ #define NL_MESSAGE_SIZE (sizeof(struct nlmsghdr) + sizeof(struct cn_msg) + \
117
+ sizeof(int))
118
+
119
+ void
120
+ connect_to_netlink()
121
+ {
122
+ struct sockaddr_nl sa_nl; /* netlink interface info */
123
+ char buff[NL_MESSAGE_SIZE];
124
+ struct nlmsghdr *hdr; /* for telling netlink what we want */
125
+ struct cn_msg *msg; /* the actual connector message */
126
+
127
+ /* connect to netlink socket */
128
+ nl_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
129
+
130
+ if (-1 == nl_sock) {
131
+ rb_raise(rb_eStandardError, "%s", strerror(errno));
132
+ }
133
+
134
+ bzero(&sa_nl, sizeof(sa_nl));
135
+ sa_nl.nl_family = AF_NETLINK;
136
+ sa_nl.nl_groups = CN_IDX_PROC;
137
+ sa_nl.nl_pid = getpid();
138
+
139
+ if (-1 == bind(nl_sock, (struct sockaddr *)&sa_nl, sizeof(sa_nl))) {
140
+ rb_raise(rb_eStandardError, "%s", strerror(errno));
141
+ }
142
+
143
+ /* Fill header */
144
+ hdr = (struct nlmsghdr *)buff;
145
+ hdr->nlmsg_len = NL_MESSAGE_SIZE;
146
+ hdr->nlmsg_type = NLMSG_DONE;
147
+ hdr->nlmsg_flags = 0;
148
+ hdr->nlmsg_seq = 0;
149
+ hdr->nlmsg_pid = getpid();
150
+
151
+ /* Fill message */
152
+ msg = (struct cn_msg *)NLMSG_DATA(hdr);
153
+ msg->id.idx = CN_IDX_PROC; /* Connecting to process information */
154
+ msg->id.val = CN_VAL_PROC;
155
+ msg->seq = 0;
156
+ msg->ack = 0;
157
+ msg->flags = 0;
158
+ msg->len = sizeof(int);
159
+ *(int*)msg->data = PROC_CN_MCAST_LISTEN;
160
+
161
+ if (-1 == send(nl_sock, hdr, hdr->nlmsg_len, 0)) {
162
+ rb_raise(rb_eStandardError, "%s", strerror(errno));
163
+ }
164
+ }
165
+
166
+ void
167
+ Init_netlink_handler_ext()
168
+ {
169
+ proc_exit = rb_intern("proc_exit");
170
+ proc_fork = rb_intern("proc_fork");
171
+ m_call = rb_intern("call");
172
+ m_watching_pid = rb_intern("watching_pid?");
173
+
174
+ mGod = rb_const_get(rb_cObject, rb_intern("God"));
175
+ cEventHandler = rb_const_get(mGod, rb_intern("EventHandler"));
176
+ cNetlinkHandler = rb_define_class_under(mGod, "NetlinkHandler", rb_cObject);
177
+ rb_define_singleton_method(cNetlinkHandler, "handle_events", nlh_handle_events, 0);
178
+
179
+ connect_to_netlink();
180
+ }
181
+
182
+ #endif
@@ -0,0 +1,52 @@
1
+ module God
2
+
3
+ class Behavior
4
+ include Configurable
5
+
6
+ attr_accessor :watch
7
+
8
+ # Generate a Behavior of the given kind. The proper class is found by camel casing the
9
+ # kind (which is given as an underscored symbol).
10
+ # +kind+ is the underscored symbol representing the class (e.g. foo_bar for God::Behaviors::FooBar)
11
+ def self.generate(kind, watch)
12
+ sym = kind.to_s.capitalize.gsub(/_(.)/){$1.upcase}.intern
13
+ b = God::Behaviors.const_get(sym).new
14
+ b.watch = watch
15
+ b
16
+ rescue NameError
17
+ raise NoSuchBehaviorError.new("No Behavior found with the class name God::Behaviors::#{sym}")
18
+ end
19
+
20
+ def valid?
21
+ true
22
+ end
23
+
24
+ #######
25
+
26
+ def before_start
27
+ end
28
+
29
+ def after_start
30
+ end
31
+
32
+ def before_restart
33
+ end
34
+
35
+ def after_restart
36
+ end
37
+
38
+ def before_stop
39
+ end
40
+
41
+ def after_stop
42
+ end
43
+
44
+ # Construct the friendly name of this Behavior, looks like:
45
+ #
46
+ # Behavior FooBar on Watch 'baz'
47
+ def friendly_name
48
+ "Behavior " + super + " on Watch '#{self.watch.name}'"
49
+ end
50
+ end
51
+
52
+ end
@@ -0,0 +1,21 @@
1
+ module God
2
+ module Behaviors
3
+
4
+ class CleanPidFile < Behavior
5
+ def valid?
6
+ valid = true
7
+ valid &= complain("Attribute 'pid_file' must be specified", self) if self.watch.pid_file.nil?
8
+ valid
9
+ end
10
+
11
+ def before_start
12
+ File.delete(self.watch.pid_file)
13
+
14
+ "deleted pid file"
15
+ rescue
16
+ "no pid file to delete"
17
+ end
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module God
2
+ module Behaviors
3
+
4
+ class CleanUnixSocket < Behavior
5
+ def valid?
6
+ valid = true
7
+ valid &= complain("Attribute 'unix_socket' must be specified", self) if self.watch.unix_socket.nil?
8
+ valid
9
+ end
10
+
11
+ def before_start
12
+ File.delete(self.watch.unix_socket)
13
+
14
+ "deleted unix socket"
15
+ rescue
16
+ "no unix socket to delete"
17
+ end
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,51 @@
1
+ module God
2
+ module Behaviors
3
+
4
+ class NotifyWhenFlapping < Behavior
5
+ attr_accessor :failures # number of failures
6
+ attr_accessor :seconds # number of seconds
7
+ attr_accessor :notifier # class to notify with
8
+
9
+ def initialize
10
+ super
11
+ @startup_times = []
12
+ end
13
+
14
+ def valid?
15
+ valid = true
16
+ valid &= complain("Attribute 'failures' must be specified", self) unless self.failures
17
+ valid &= complain("Attribute 'seconds' must be specified", self) unless self.seconds
18
+ valid &= complain("Attribute 'notifier' must be specified", self) unless self.notifier
19
+
20
+ # Must take one arg or variable args
21
+ unless self.notifier.respond_to?(:notify) and [1,-1].include?(self.notifier.method(:notify).arity)
22
+ valid &= complain("The 'notifier' must have a method 'notify' which takes 1 or variable args", self)
23
+ end
24
+
25
+ valid
26
+ end
27
+
28
+ def before_start
29
+ now = Time.now.to_i
30
+ @startup_times << now
31
+ check_for_flapping(now)
32
+ end
33
+
34
+ def before_restart
35
+ now = Time.now.to_i
36
+ @startup_times << now
37
+ check_for_flapping(now)
38
+ end
39
+
40
+ private
41
+
42
+ def check_for_flapping(now)
43
+ @startup_times.select! {|time| time >= now - self.seconds }
44
+ if @startup_times.length >= self.failures
45
+ self.notifier.notify("#{self.watch.name} has called start/restart #{@startup_times.length} times in #{self.seconds} seconds")
46
+ end
47
+ end
48
+ end
49
+
50
+ end
51
+ end