resurrected_god 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
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