From 08b0ddfc7b4128fc2466b50356d245f0b4969fa3 Mon Sep 17 00:00:00 2001
From: "Gun.io Whitespace Robot"
Date: Sat, 17 Dec 2011 06:25:38 -0500
Subject: [PATCH] Remove whitespace [Gun.io WhitespaceBot]
---
Announce.txt | 12 +-
History.txt | 2 +-
README.txt | 12 +-
examples/events.god | 16 +-
examples/gravatar.god | 12 +-
examples/single.god | 14 +-
ext/god/extconf.rb | 6 +-
ext/god/kqueue_handler.c | 36 +--
ext/god/netlink_handler.c | 54 ++---
ideas/execve/execve.c | 8 +-
ideas/future.god | 14 +-
init/god | 4 +-
lib/god.rb | 162 ++++++-------
lib/god/behavior.rb | 26 +-
lib/god/behaviors/clean_pid_file.rb | 8 +-
lib/god/behaviors/clean_unix_socket.rb | 18 +-
lib/god/behaviors/notify_when_flapping.rb | 22 +-
lib/god/cli/command.rb | 70 +++---
lib/god/cli/run.rb | 68 +++---
lib/god/cli/version.rb | 10 +-
lib/god/condition.rb | 40 +--
lib/god/conditions/always.rb | 8 +-
lib/god/conditions/complex.rb | 34 +--
lib/god/conditions/cpu_usage.rb | 26 +-
lib/god/conditions/degrading_lambda.rb | 14 +-
lib/god/conditions/disk_usage.rb | 10 +-
lib/god/conditions/flapping.rb | 44 ++--
lib/god/conditions/http_response_code.rb | 34 +--
lib/god/conditions/lambda.rb | 2 +-
lib/god/conditions/memory_usage.rb | 24 +-
lib/god/conditions/process_exits.rb | 22 +-
lib/god/conditions/process_running.rb | 18 +-
lib/god/conditions/tries.rb | 18 +-
lib/god/configurable.rb | 20 +-
lib/god/contact.rb | 34 +--
lib/god/contacts/email.rb | 20 +-
lib/god/contacts/jabber.rb | 16 +-
lib/god/dependency_graph.rb | 14 +-
lib/god/diagnostics.rb | 8 +-
lib/god/driver.rb | 36 +--
lib/god/errors.rb | 16 +-
lib/god/event_handler.rb | 38 +--
lib/god/event_handlers/dummy_handler.rb | 4 +-
lib/god/event_handlers/kqueue_handler.rb | 4 +-
lib/god/event_handlers/netlink_handler.rb | 2 +-
lib/god/logger.rb | 36 +--
lib/god/metric.rb | 22 +-
lib/god/process.rb | 90 +++----
lib/god/registry.rb | 12 +-
lib/god/simple_logger.rb | 24 +-
lib/god/socket.rb | 22 +-
lib/god/sugar.rb | 28 +--
lib/god/system/portable_poller.rb | 14 +-
lib/god/system/process.rb | 16 +-
lib/god/system/slash_proc_poller.rb | 22 +-
lib/god/task.rb | 184 +++++++-------
lib/god/timeline.rb | 8 +-
lib/god/trigger.rb | 20 +-
lib/god/watch.rb | 72 +++---
site/index.html | 90 +++----
test/configs/child_events/child_events.god | 8 +-
test/configs/child_polls/child_polls.god | 8 +-
test/configs/complex/complex.god | 12 +-
test/configs/contact/contact.god | 8 +-
test/configs/daemon_events/daemon_events.god | 8 +-
test/configs/daemon_polls/daemon_polls.god | 4 +-
.../degrading_lambda/degrading_lambda.god | 4 +-
test/configs/matias/matias.god | 10 +-
test/configs/real.rb | 12 +-
test/configs/running_load/running_load.god | 2 +-
test/configs/stress/stress.god | 2 +-
test/configs/task/task.god | 8 +-
test/configs/test.rb | 12 +-
test/helper.rb | 14 +-
test/test_behavior.rb | 4 +-
test/test_condition.rb | 20 +-
test/test_conditions_disk_usage.rb | 26 +-
test/test_conditions_http_response_code.rb | 28 +--
test/test_conditions_process_running.rb | 16 +-
test/test_conditions_tries.rb | 20 +-
test/test_contact.rb | 36 +--
test/test_dependency_graph.rb | 26 +-
test/test_driver.rb | 4 +-
test/test_email.rb | 6 +-
test/test_event_handler.rb | 22 +-
test/test_god.rb | 228 +++++++++---------
test/test_handlers_kqueue_handler.rb | 6 +-
test/test_logger.rb | 32 +--
test/test_metric.rb | 30 +--
test/test_process.rb | 86 +++----
test/test_registry.rb | 2 +-
test/test_socket.rb | 6 +-
test/test_sugar.rb | 14 +-
test/test_system_portable_poller.rb | 2 +-
test/test_system_process.rb | 10 +-
test/test_task.rb | 116 ++++-----
test/test_timeline.rb | 16 +-
test/test_trigger.rb | 30 +--
test/test_watch.rb | 122 +++++-----
99 files changed, 1380 insertions(+), 1380 deletions(-)
diff --git a/Announce.txt b/Announce.txt
index 3a9a2d11..f72f62da 100644
--- a/Announce.txt
+++ b/Announce.txt
@@ -52,7 +52,7 @@ EXAMPLE
The easiest way to understand how god will make your life better is by looking at a sample config file. The following configuration file is what I use at gravatar.com to keep the mongrels running:
# run with: god -c /path/to/gravatar.god
-#
+#
# This is the actual config file used to keep the mongrels of
# gravatar.com running.
@@ -61,7 +61,7 @@ RAILS_ROOT = "/Users/tom/dev/gravatar2"
%w{8200 8201 8202}.each do |port|
God.watch do |w|
w.name = "gravatar2-mongrel-#{port}"
- w.interval = 30.seconds # default
+ w.interval = 30.seconds # default
w.start = "mongrel_rails start -c #{RAILS_ROOT} -p #{port} \
-P #{RAILS_ROOT}/log/mongrel.#{port}.pid -d"
w.stop = "mongrel_rails stop -P #{RAILS_ROOT}/log/mongrel.#{port}.pid"
@@ -69,7 +69,7 @@ RAILS_ROOT = "/Users/tom/dev/gravatar2"
w.start_grace = 10.seconds
w.restart_grace = 10.seconds
w.pid_file = File.join(RAILS_ROOT, "log/mongrel.#{port}.pid")
-
+
w.behavior(:clean_pid_file)
w.start_if do |start|
@@ -78,19 +78,19 @@ RAILS_ROOT = "/Users/tom/dev/gravatar2"
c.running = false
end
end
-
+
w.restart_if do |restart|
restart.condition(:memory_usage) do |c|
c.above = 150.megabytes
c.times = [3, 5] # 3 out of 5 intervals
end
-
+
restart.condition(:cpu_usage) do |c|
c.above = 50.percent
c.times = 5
end
end
-
+
# lifecycle
w.lifecycle do |on|
on.condition(:flapping) do |c|
diff --git a/History.txt b/History.txt
index f69d1c98..c8525c0d 100644
--- a/History.txt
+++ b/History.txt
@@ -142,7 +142,7 @@
* Minor Enhancement
* Allow extra args to pass through to config file
-
+
== 0.5.1 / 2007-10-08
* Bug Fixes
diff --git a/README.txt b/README.txt
index 7aabb9e4..b63912f0 100644
--- a/README.txt
+++ b/README.txt
@@ -1,16 +1,16 @@
god
by Tom Preston-Werner
Kevin Clark (kqueue/netlink support)
-
+
http://god.rubyforge.org
== DESCRIPTION:
-
-God is an easy to configure, easy to extend monitoring framework written
+
+God is an easy to configure, easy to extend monitoring framework written
in Ruby.
-Keeping your server processes and tasks running should be a simple part of
-your deployment process. God aims to be the simplest, most powerful
+Keeping your server processes and tasks running should be a simple part of
+your deployment process. God aims to be the simplest, most powerful
monitoring application available.
== DOCUMENTATION:
@@ -24,7 +24,7 @@ Sign up for the god mailing list at http://groups.google.com/group/god-rb
== INSTALL:
$ sudo gem install god
-
+
== CONTRIBUTE:
Latest code is available at http://github.com/mojombo/god
diff --git a/examples/events.god b/examples/events.god
index 34a1aa22..d38d82c5 100644
--- a/examples/events.god
+++ b/examples/events.god
@@ -14,23 +14,23 @@ RAILS_ROOT = ENV['GOD_TEST_RAILS_ROOT']
w.stop = "mongrel_rails stop -P #{RAILS_ROOT}/log/mongrel.#{port}.pid -c #{RAILS_ROOT}"
w.pid_file = File.join(RAILS_ROOT, "log/mongrel.#{port}.pid")
w.log = File.join(RAILS_ROOT, "log/commands.#{port}.log")
-
+
# clean pid files before start if necessary
w.behavior(:clean_pid_file)
-
+
# determine the state on startup
w.transition(:init, { true => :up, false => :start }) do |on|
on.condition(:process_running) do |c|
c.running = true
end
end
-
+
# determine when process has finished starting
w.transition([:start, :restart], :up) do |on|
on.condition(:process_running) do |c|
c.running = true
end
-
+
# failsafe
on.condition(:tries) do |c|
c.times = 8
@@ -43,7 +43,7 @@ RAILS_ROOT = ENV['GOD_TEST_RAILS_ROOT']
w.transition(:up, :start) do |on|
on.condition(:process_exits)
end
-
+
# restart if memory or cpu is too high
w.transition(:up, :restart) do |on|
on.condition(:memory_usage) do |c|
@@ -51,13 +51,13 @@ RAILS_ROOT = ENV['GOD_TEST_RAILS_ROOT']
c.above = 50.megabytes
c.times = [3, 5]
end
-
+
on.condition(:cpu_usage) do |c|
c.interval = 10
c.above = 10.percent
c.times = 5
end
-
+
on.condition(:http_response_code) do |c|
c.host = 'localhost'
c.port = port
@@ -67,7 +67,7 @@ RAILS_ROOT = ENV['GOD_TEST_RAILS_ROOT']
c.times = [3, 5]
end
end
-
+
# lifecycle
w.lifecycle do |on|
on.condition(:flapping) do |c|
diff --git a/examples/gravatar.god b/examples/gravatar.god
index a676ddc9..a7b61040 100644
--- a/examples/gravatar.god
+++ b/examples/gravatar.god
@@ -1,5 +1,5 @@
# run with: god -c /path/to/gravatar.god
-#
+#
# This is the actual config file used to keep the mongrels of
# gravatar.com running.
@@ -8,7 +8,7 @@ RAILS_ROOT = "/Users/tom/dev/gravatar2"
%w{8200 8201 8202}.each do |port|
God.watch do |w|
w.name = "gravatar2-mongrel-#{port}"
- w.interval = 30.seconds # default
+ w.interval = 30.seconds # default
w.start = "mongrel_rails start -c #{RAILS_ROOT} -p #{port} \
-P #{RAILS_ROOT}/log/mongrel.#{port}.pid -d"
w.stop = "mongrel_rails stop -P #{RAILS_ROOT}/log/mongrel.#{port}.pid"
@@ -16,7 +16,7 @@ RAILS_ROOT = "/Users/tom/dev/gravatar2"
w.start_grace = 10.seconds
w.restart_grace = 10.seconds
w.pid_file = File.join(RAILS_ROOT, "log/mongrel.#{port}.pid")
-
+
w.behavior(:clean_pid_file)
w.start_if do |start|
@@ -25,19 +25,19 @@ RAILS_ROOT = "/Users/tom/dev/gravatar2"
c.running = false
end
end
-
+
w.restart_if do |restart|
restart.condition(:memory_usage) do |c|
c.above = 150.megabytes
c.times = [3, 5] # 3 out of 5 intervals
end
-
+
restart.condition(:cpu_usage) do |c|
c.above = 50.percent
c.times = 5
end
end
-
+
# lifecycle
w.lifecycle do |on|
on.condition(:flapping) do |c|
diff --git a/examples/single.god b/examples/single.god
index c55372fc..229d331c 100644
--- a/examples/single.god
+++ b/examples/single.god
@@ -7,23 +7,23 @@ God.watch do |w|
w.stop = "mongrel_rails stop -P #{RAILS_ROOT}/log/mongrel.pid"
w.restart = "mongrel_rails restart -P #{RAILS_ROOT}/log/mongrel.pid"
w.pid_file = File.join(RAILS_ROOT, "log/mongrel.pid")
-
+
# clean pid files before start if necessary
w.behavior(:clean_pid_file)
-
+
# determine the state on startup
w.transition(:init, { true => :up, false => :start }) do |on|
on.condition(:process_running) do |c|
c.running = true
end
end
-
+
# determine when process has finished starting
w.transition([:start, :restart], :up) do |on|
on.condition(:process_running) do |c|
c.running = true
end
-
+
# failsafe
on.condition(:tries) do |c|
c.times = 5
@@ -35,7 +35,7 @@ God.watch do |w|
w.transition(:up, :start) do |on|
on.condition(:process_exits)
end
-
+
# restart if memory or cpu is too high
w.transition(:up, :restart) do |on|
on.condition(:memory_usage) do |c|
@@ -43,14 +43,14 @@ God.watch do |w|
c.above = 50.megabytes
c.times = [3, 5]
end
-
+
on.condition(:cpu_usage) do |c|
c.interval = 10
c.above = 10.percent
c.times = [3, 5]
end
end
-
+
# lifecycle
w.lifecycle do |on|
on.condition(:flapping) do |c|
diff --git a/ext/god/extconf.rb b/ext/god/extconf.rb
index 46835750..41ee9467 100644
--- a/ext/god/extconf.rb
+++ b/ext/god/extconf.rb
@@ -16,7 +16,7 @@ def create_dummy_makefile
puts "Missing 'sys/event.h' header"
fail = true
end
-
+
if fail
puts
puts "Events handler could not be compiled (see above error). Your god installation will not support event conditions."
@@ -31,7 +31,7 @@ def create_dummy_makefile
puts "You may need to install a header package for your system"
fail = true
end
-
+
unless have_header('linux/connector.h') && have_header('linux/cn_proc.h')
puts
puts "Missing 'linux/connector.h', or 'linux/cn_proc.h' header(s)"
@@ -39,7 +39,7 @@ def create_dummy_makefile
puts "You may need to install a header package for your system"
fail = true
end
-
+
if fail
puts
puts "Events handler could not be compiled (see above error). Your god installation will not support event conditions."
diff --git a/ext/god/kqueue_handler.c b/ext/god/kqueue_handler.c
index 7936993d..da7b03cf 100644
--- a/ext/god/kqueue_handler.c
+++ b/ext/god/kqueue_handler.c
@@ -31,28 +31,28 @@ kqh_event_mask(VALUE klass, VALUE sym)
} else {
rb_raise(rb_eNotImpError, "Event `%s` not implemented", rb_id2name(id));
}
-
+
return Qnil;
}
-
+
VALUE
kqh_monitor_process(VALUE klass, VALUE pid, VALUE mask)
{
struct kevent new_event;
ID event;
-
+
u_int fflags = NUM2UINT(mask);
-
+
EV_SET(&new_event, FIX2UINT(pid), EVFILT_PROC,
EV_ADD | EV_ENABLE, fflags, 0, 0);
-
+
if (-1 == kevent(kq, &new_event, 1, NULL, 0, NULL)) {
rb_raise(rb_eStandardError, strerror(errno));
}
-
+
num_events = NUM_EVENTS;
-
+
return Qnil;
}
@@ -62,23 +62,23 @@ kqh_handle_events()
int nevents, i, num_to_fetch;
struct kevent *events;
fd_set read_set;
-
+
FD_ZERO(&read_set);
FD_SET(kq, &read_set);
-
+
// Don't actually run this method until we've got an event
- rb_thread_select(kq + 1, &read_set, NULL, NULL, NULL);
-
+ rb_thread_select(kq + 1, &read_set, NULL, NULL, NULL);
+
// Grabbing num_events once for thread safety
num_to_fetch = num_events;
events = (struct kevent*)malloc(num_to_fetch * sizeof(struct kevent));
-
+
if (NULL == events) {
rb_raise(rb_eStandardError, strerror(errno));
}
-
+
nevents = kevent(kq, NULL, 0, events, num_to_fetch, NULL);
-
+
if (-1 == nevents) {
free(events);
rb_raise(rb_eStandardError, strerror(errno));
@@ -91,7 +91,7 @@ kqh_handle_events()
}
}
}
-
+
free(events);
return INT2FIX(nevents);
@@ -101,17 +101,17 @@ void
Init_kqueue_handler_ext()
{
kq = kqueue();
-
+
if (kq == -1) {
rb_raise(rb_eStandardError, "kqueue initilization failed");
}
-
+
proc_exit = rb_intern("proc_exit");
proc_fork = rb_intern("proc_fork");
m_call = rb_intern("call");
m_size = rb_intern("size");
m_deregister = rb_intern("deregister");
-
+
mGod = rb_const_get(rb_cObject, rb_intern("God"));
cEventHandler = rb_const_get(mGod, rb_intern("EventHandler"));
cKQueueHandler = rb_define_class_under(mGod, "KQueueHandler", rb_cObject);
diff --git a/ext/god/netlink_handler.c b/ext/god/netlink_handler.c
index 32c53d7a..b467c441 100644
--- a/ext/god/netlink_handler.c
+++ b/ext/god/netlink_handler.c
@@ -27,42 +27,42 @@ nlh_handle_events()
char buff[CONNECTOR_MAX_MSG_SIZE];
struct nlmsghdr *hdr;
struct proc_event *event;
-
+
VALUE extra_data;
-
+
fd_set fds;
-
+
FD_ZERO(&fds);
FD_SET(nl_sock, &fds);
-
+
if (0 > rb_thread_select(nl_sock + 1, &fds, NULL, NULL, NULL)) {
rb_raise(rb_eStandardError, strerror(errno));
}
-
+
/* If there were no events detected, return */
if (! FD_ISSET(nl_sock, &fds)) {
return INT2FIX(0);
}
-
- /* if there are events, make calls */
+
+ /* if there are events, make calls */
if (-1 == recv(nl_sock, buff, sizeof(buff), 0)) {
rb_raise(rb_eStandardError, strerror(errno));
}
-
+
hdr = (struct nlmsghdr *)buff;
-
+
if (NLMSG_ERROR == hdr->nlmsg_type) {
rb_raise(rb_eStandardError, strerror(errno));
- } else if (NLMSG_DONE == hdr->nlmsg_type) {
-
+ } else if (NLMSG_DONE == hdr->nlmsg_type) {
+
event = (struct proc_event *)((struct cn_msg *)NLMSG_DATA(hdr))->data;
-
+
switch(event->what) {
case PROC_EVENT_EXIT:
if (Qnil == rb_funcall(cEventHandler, m_watching_pid, 1, INT2FIX(event->event_data.exit.process_pid))) {
return INT2FIX(0);
}
-
+
extra_data = rb_hash_new();
rb_hash_aset(extra_data, ID2SYM(rb_intern("pid")), INT2FIX(event->event_data.exit.process_pid));
rb_hash_aset(extra_data, ID2SYM(rb_intern("exit_code")), INT2FIX(event->event_data.exit.exit_code));
@@ -71,18 +71,18 @@ nlh_handle_events()
rb_funcall(cEventHandler, m_call, 3, INT2FIX(event->event_data.exit.process_pid), ID2SYM(proc_exit), extra_data);
return INT2FIX(1);
-
+
case PROC_EVENT_FORK:
if (Qnil == rb_funcall(cEventHandler, m_watching_pid, 1, INT2FIX(event->event_data.fork.parent_pid))) {
return INT2FIX(0);
}
-
+
extra_data = rb_hash_new();
rb_hash_aset(extra_data, rb_intern("parent_pid"), INT2FIX(event->event_data.fork.parent_pid));
rb_hash_aset(extra_data, rb_intern("parent_thread_group_id"), INT2FIX(event->event_data.fork.parent_tgid));
rb_hash_aset(extra_data, rb_intern("child_pid"), INT2FIX(event->event_data.fork.child_pid));
rb_hash_aset(extra_data, rb_intern("child_thread_group_id"), INT2FIX(event->event_data.fork.child_tgid));
-
+
rb_funcall(cEventHandler, m_call, 3, INT2FIX(event->event_data.fork.parent_pid), ID2SYM(proc_fork), extra_data);
return INT2FIX(1);
@@ -93,7 +93,7 @@ nlh_handle_events()
break;
}
}
-
+
return Qnil;
}
@@ -108,23 +108,23 @@ connect_to_netlink()
char buff[NL_MESSAGE_SIZE];
struct nlmsghdr *hdr; /* for telling netlink what we want */
struct cn_msg *msg; /* the actual connector message */
-
+
/* connect to netlink socket */
nl_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
-
+
if (-1 == nl_sock) {
rb_raise(rb_eStandardError, strerror(errno));
}
-
+
bzero(&sa_nl, sizeof(sa_nl));
sa_nl.nl_family = AF_NETLINK;
sa_nl.nl_groups = CN_IDX_PROC;
sa_nl.nl_pid = getpid();
-
+
if (-1 == bind(nl_sock, (struct sockaddr *)&sa_nl, sizeof(sa_nl))) {
rb_raise(rb_eStandardError, strerror(errno));
}
-
+
/* Fill header */
hdr = (struct nlmsghdr *)buff;
hdr->nlmsg_len = NL_MESSAGE_SIZE;
@@ -132,7 +132,7 @@ connect_to_netlink()
hdr->nlmsg_flags = 0;
hdr->nlmsg_seq = 0;
hdr->nlmsg_pid = getpid();
-
+
/* Fill message */
msg = (struct cn_msg *)NLMSG_DATA(hdr);
msg->id.idx = CN_IDX_PROC; /* Connecting to process information */
@@ -142,7 +142,7 @@ connect_to_netlink()
msg->flags = 0;
msg->len = sizeof(int);
*(int*)msg->data = PROC_CN_MCAST_LISTEN;
-
+
if (-1 == send(nl_sock, hdr, hdr->nlmsg_len, 0)) {
rb_raise(rb_eStandardError, strerror(errno));
}
@@ -150,17 +150,17 @@ connect_to_netlink()
void
Init_netlink_handler_ext()
-{
+{
proc_exit = rb_intern("proc_exit");
proc_fork = rb_intern("proc_fork");
m_call = rb_intern("call");
m_watching_pid = rb_intern("watching_pid?");
-
+
mGod = rb_const_get(rb_cObject, rb_intern("God"));
cEventHandler = rb_const_get(mGod, rb_intern("EventHandler"));
cNetlinkHandler = rb_define_class_under(mGod, "NetlinkHandler", rb_cObject);
rb_define_singleton_method(cNetlinkHandler, "handle_events", nlh_handle_events, 0);
-
+
connect_to_netlink();
}
diff --git a/ideas/execve/execve.c b/ideas/execve/execve.c
index 4439807f..37d07b2e 100644
--- a/ideas/execve/execve.c
+++ b/ideas/execve/execve.c
@@ -12,18 +12,18 @@ void Init_execve() {
VALUE method_execve(VALUE self, VALUE r_cmd, VALUE r_env) {
char *shell = (char *)dln_find_exe("sh", 0);
char *arg[] = { "sh", "-c", StringValuePtr(r_cmd), (char *)0 };
-
+
struct RArray *env_array;
env_array = RARRAY(r_env);
char *env[env_array->len + 1];
-
+
int i;
for(i = 0; i < env_array->len; i++) {
env[i] = StringValuePtr(env_array->ptr[i]);
}
-
+
env[env_array->len] = (char *)0;
-
+
execve(shell, arg, env);
return Qnil;
}
\ No newline at end of file
diff --git a/ideas/future.god b/ideas/future.god
index 6723030e..9a28eb5f 100644
--- a/ideas/future.god
+++ b/ideas/future.god
@@ -22,17 +22,17 @@ God.watch do |w|
w.start = "mongrel_rails start -P ./log/mongrel.pid -c #{RAILS_ROOT} -d"
w.stop = "mongrel_rails stop -P ./log/mongrel.pid -c #{RAILS_ROOT}"
w.pid_file = File.join(RAILS_ROOT, "log/mongrel.pid")
-
+
# clean pid files before start if necessary
w.behavior(:clean_pid_file)
-
+
# determine the state on startup
w.transition(:init, { true => :up, false => :start }) do |on|
on.condition(:process_running) do |c|
c.running = true
end
end
-
+
# determine when process has finished starting
w.transition([:start, :restart], :up) do |on|
on.condition(:process_running) do |c|
@@ -44,7 +44,7 @@ God.watch do |w|
w.transition(:up, :start) do |on|
on.condition(:process_exits)
end
-
+
# restart if memory or cpu is too high
w.transition(:up, :restart) do |on|
on.condition(:memory_usage) do |c|
@@ -52,14 +52,14 @@ God.watch do |w|
c.above = 50.megabytes
c.times = [3, 5]
end
-
+
on.condition(:cpu_usage) do |c|
c.interval = 10
c.above = 10.percent
c.times = [3, 5]
end
end
-
+
# lifecycle
w.lifecycle do |on|
on.condition(:flapping) do |c|
@@ -71,7 +71,7 @@ God.watch do |w|
c.giveup_tries = 5
c.notify = 'tom'
end
-
+
on.condition(:memory_usage) do |c|
c.interval = 20
c.above = 40.megabytes
diff --git a/init/god b/init/god
index 2c7d7336..bda4cfe3 100755
--- a/init/god
+++ b/init/god
@@ -5,7 +5,7 @@
# chkconfig: - 85 15
# description: God is an easy to configure, easy to extend monitoring \
# framework written in Ruby.
-#
+#
CONF_DIR=/etc/god
@@ -37,6 +37,6 @@ case "$1" in
echo "Usage: god {start|stop|restart|status}"
exit 1
;;
-esac
+esac
exit $RETVAL
diff --git a/lib/god.rb b/lib/god.rb
index fa56ce7b..0804c436 100644
--- a/lib/god.rb
+++ b/lib/god.rb
@@ -99,15 +99,15 @@ def root_binding
module Kernel
alias_method :abort_orig, :abort
-
+
def abort(text = nil)
$run = false
applog(nil, :error, text) if text
exit(1)
end
-
+
alias_method :exit_orig, :exit
-
+
def exit(code = 0)
$run = false
exit_orig(code)
@@ -121,15 +121,15 @@ def safe_attr_accessor(*args)
if !self.running && self.inited
abort "God.#{arg} must be set before any Tasks are defined"
end
-
+
if self.running && self.inited
applog(nil, :warn, "God.#{arg} can't be set while god is running")
return
end
-
+
instance_variable_set(('@' + arg.to_s).intern, other)
end
-
+
define_method(arg) do
instance_variable_get(('@' + arg.to_s).intern)
end
@@ -139,13 +139,13 @@ def safe_attr_accessor(*args)
module God
VERSION = '0.7.9'
-
+
LOG_BUFFER_SIZE_DEFAULT = 100
PID_FILE_DIRECTORY_DEFAULTS = ['/var/run/god', '~/.god/pids']
DRB_PORT_DEFAULT = 17165
DRB_ALLOW_DEFAULT = ['127.0.0.1']
LOG_LEVEL_DEFAULT = :info
-
+
class << self
# user configurable
safe_attr_accessor :pid,
@@ -157,7 +157,7 @@ class << self
:log_file,
:log_level,
:use_events
-
+
# internal
attr_accessor :inited,
:running,
@@ -170,7 +170,7 @@ class << self
:contact_groups,
:main
end
-
+
# initialize class instance variables
self.pid = nil
self.host = nil
@@ -179,14 +179,14 @@ class << self
self.log_buffer_size = nil
self.pid_file_directory = nil
self.log_level = nil
-
+
# Initialize internal data.
#
# Returns nothing
def self.internal_init
# only do this once
return if self.inited
-
+
# variable init
self.watches = {}
self.groups = {}
@@ -194,16 +194,16 @@ def self.internal_init
self.pending_watch_states = {}
self.contacts = {}
self.contact_groups = {}
-
+
# set defaults
self.log_buffer_size ||= LOG_BUFFER_SIZE_DEFAULT
self.port ||= DRB_PORT_DEFAULT
self.allow ||= DRB_ALLOW_DEFAULT
self.log_level ||= LOG_LEVEL_DEFAULT
-
+
# additional setup
self.setup
-
+
# log level
log_level_map = {:debug => Logger::DEBUG,
:info => Logger::INFO,
@@ -211,14 +211,14 @@ def self.internal_init
:error => Logger::ERROR,
:fatal => Logger::FATAL}
LOG.level = log_level_map[self.log_level]
-
+
# init has been executed
self.inited = true
-
+
# not yet running
self.running = false
end
-
+
# Instantiate a new, empty Watch object and pass it to the mandatory
# block. The attributes of the watch will be set by the configuration
# file.
@@ -231,7 +231,7 @@ def self.internal_init
def self.watch(&block)
self.task(Watch, &block)
end
-
+
# Instantiate a new, empty Task object and yield it to the mandatory
# block. The attributes of the task will be set by the configuration
# file.
@@ -243,13 +243,13 @@ def self.watch(&block)
# Returns nothing
def self.task(klass = Task)
self.internal_init
-
+
t = klass.new
yield(t)
-
+
# do the post-configuration
t.prepare
-
+
# if running, completely remove the watch (if necessary) to
# prepare for the reload
existing_watch = self.watches[t.name]
@@ -257,35 +257,35 @@ def self.task(klass = Task)
self.pending_watch_states[existing_watch.name] = existing_watch.state
self.unwatch(existing_watch)
end
-
+
# ensure the new watch has a unique name
if self.watches[t.name] || self.groups[t.name]
abort "Task name '#{t.name}' already used for a Task or Group"
end
-
+
# ensure watch is internally valid
t.valid? || abort("Task '#{t.name}' is not valid (see above)")
-
+
# add to list of watches
self.watches[t.name] = t
-
+
# add to pending watches
self.pending_watches << t
-
+
# add to group if specified
if t.group
# ensure group name hasn't been used for a watch already
if self.watches[t.group]
abort "Group name '#{t.group}' already used for a Task"
end
-
+
self.groups[t.group] ||= []
self.groups[t.group] << t
end
-
+
# register watch
t.register!
-
+
# log
if self.running && existing_watch
applog(t, :info, "#{t.name} Reloaded config")
@@ -293,7 +293,7 @@ def self.task(klass = Task)
applog(t, :info, "#{t.name} Loaded config")
end
end
-
+
# Unmonitor and remove the given watch from god.
# +watch+ is the Watch to remove
#
@@ -301,21 +301,21 @@ def self.task(klass = Task)
def self.unwatch(watch)
# unmonitor
watch.unmonitor unless watch.state == :unmonitored
-
+
# unregister
watch.unregister!
-
+
# remove from watches
self.watches.delete(watch.name)
-
+
# remove from groups
if watch.group
self.groups[watch.group].delete(watch)
end
-
+
applog(watch, :info, "#{watch.name} unwatched")
end
-
+
# Instantiate a new Contact of the given kind and send it to the block.
# Then prepare, validate, and record the Contact.
# +kind+ is the contact class specifier
@@ -328,53 +328,53 @@ def self.unwatch(watch)
# Returns nothing
def self.contact(kind)
self.internal_init
-
+
# create the contact
begin
c = Contact.generate(kind)
rescue NoSuchContactError => e
abort e.message
end
-
+
# send to block so config can set attributes
yield(c) if block_given?
-
+
# call prepare on the contact
c.prepare
-
+
# remove existing contacts of same name
existing_contact = self.contacts[c.name]
if self.running && existing_contact
self.uncontact(existing_contact)
end
-
+
# warn and noop if the contact has been defined before
if self.contacts[c.name] || self.contact_groups[c.name]
applog(nil, :warn, "Contact name '#{c.name}' already used for a Contact or Contact Group")
return
end
-
+
# abort if the Contact is invalid, the Contact will have printed
# out its own error messages by now
unless Contact.valid?(c) && c.valid?
abort "Exiting on invalid contact"
end
-
+
# add to list of contacts
self.contacts[c.name] = c
-
+
# add to contact group if specified
if c.group
# ensure group name hasn't been used for a contact already
if self.contacts[c.group]
abort "Contact Group name '#{c.group}' already used for a Contact"
end
-
+
self.contact_groups[c.group] ||= []
self.contact_groups[c.group] << c
end
end
-
+
# Remove the given contact from god.
# +contact+ is the Contact to remove
#
@@ -385,7 +385,7 @@ def self.uncontact(contact)
self.contact_groups[contact.group].delete(contact)
end
end
-
+
# Control the lifecycle of the given task(s).
# +name+ is the name of a task/group (String)
# +command+ is the command to run (String)
@@ -400,9 +400,9 @@ def self.uncontact(contact)
def self.control(name, command)
# get the list of items
items = Array(self.watches[name] || self.groups[name]).dup
-
+
jobs = []
-
+
# do the command
case command
when "start", "monitor"
@@ -418,12 +418,12 @@ def self.control(name, command)
else
raise InvalidCommandError.new
end
-
+
jobs.each { |j| j.join }
-
+
items.map { |x| x.name }
end
-
+
# Unmonitor and stop all tasks.
#
# Returns true on success
@@ -435,15 +435,15 @@ def self.stop_all
w.action(:stop) if w.alive?
end
end
-
+
10.times do
return true unless self.watches.map { |name, w| w.alive? }.any?
sleep 1
end
-
+
return false
end
-
+
# Force the termination of god.
# * Clean up pid file if one exists
# * Stop DRb service
@@ -455,7 +455,7 @@ def self.terminate
self.server.stop if self.server
exit!(0)
end
-
+
# Gather the status of each task.
#
# Examples
@@ -470,7 +470,7 @@ def self.status
end
info
end
-
+
# Log lines for the given task since the specified time.
# +watch_name+ is the name of the task (may be abbreviated)
# +since+ is the Time since which to report log lines
@@ -480,14 +480,14 @@ def self.status
# Returns String:joined_log_lines
def self.running_log(watch_name, since)
matches = pattern_match(watch_name, self.watches.keys)
-
+
unless matches.first
raise NoSuchWatchError.new
end
-
+
LOG.watch_log_since(matches.first, since)
end
-
+
# Load a config file into a running god instance. Rescues any exceptions
# that the config may raise and reports these back to the caller.
# +code+ is a String containing the config file
@@ -497,10 +497,10 @@ def self.running_log(watch_name, since)
def self.running_load(code, filename)
errors = ""
watches = []
-
+
begin
LOG.start_capture
-
+
Gem.clear_paths
eval(code, root_binding, filename)
self.pending_watches.each do |w|
@@ -516,17 +516,17 @@ def self.running_load(code, filename)
rescue Exception => e
# don't ever let running_load take down god
errors << LOG.finish_capture
-
+
unless e.instance_of?(SystemExit)
errors << e.message << "\n"
errors << e.backtrace.join("\n")
end
end
-
+
names = watches.map { |x| x.name }
[names, errors]
end
-
+
# Load the given file(s) according to the given glob.
# +glob+ is the glob-enabled path to load
#
@@ -536,7 +536,7 @@ def self.load(glob)
Kernel.load f
end
end
-
+
def self.setup
if self.pid_file_directory
# pid file dir was specified, ensure it is created and writable
@@ -547,7 +547,7 @@ def self.setup
abort "Failed to create pid file directory: #{e.message}"
end
end
-
+
unless File.writable?(self.pid_file_directory)
abort "The pid file directory (#{self.pid_file_directory}) is not writable by #{Etc.getlogin}"
end
@@ -564,54 +564,54 @@ def self.setup
rescue Errno::EACCES => e
end
end
-
+
unless self.pid_file_directory
dirs = PID_FILE_DIRECTORY_DEFAULTS.map { |x| File.expand_path(x) }
abort "No pid file directory exists, could be created, or is writable at any of #{dirs.join(', ')}"
end
end
-
+
applog(nil, :info, "Using pid file directory: #{self.pid_file_directory}")
end
-
+
# Initialize and startup the machinery that makes god work.
#
# Returns nothing
def self.start
self.internal_init
-
+
# instantiate server
self.server = Socket.new(self.port)
-
+
# start monitoring any watches set to autostart
self.watches.values.each { |w| w.monitor if w.autostart? }
-
+
# clear pending watches
self.pending_watches.clear
-
+
# mark as running
self.running = true
-
+
# don't exit
- self.main =
+ self.main =
Thread.new do
loop do
sleep 60
end
end
-
+
self.main.join
end
-
+
# To be called on program exit to start god
#
# Returns nothing
def self.at_exit
self.start
end
-
+
# private
-
+
# Match a shortened pattern against a list of String candidates.
# The pattern is expanded into a regular expression by
# inserting .* between each character.
@@ -628,7 +628,7 @@ def self.at_exit
# Returns String[]:matched_elements
def self.pattern_match(pattern, list)
regex = pattern.split('').join('.*')
-
+
list.select do |item|
item =~ Regexp.new(regex)
end
diff --git a/lib/god/behavior.rb b/lib/god/behavior.rb
index 478e6ef2..a2721b84 100644
--- a/lib/god/behavior.rb
+++ b/lib/god/behavior.rb
@@ -1,10 +1,10 @@
module God
-
+
class Behavior
include Configurable
-
+
attr_accessor :watch
-
+
# Generate a Behavior of the given kind. The proper class is found by camel casing the
# kind (which is given as an underscored symbol).
# +kind+ is the underscored symbol representing the class (e.g. foo_bar for God::Behaviors::FooBar)
@@ -16,31 +16,31 @@ def self.generate(kind, watch)
rescue NameError
raise NoSuchBehaviorError.new("No Behavior found with the class name God::Behaviors::#{sym}")
end
-
+
def valid?
true
end
-
+
#######
-
+
def before_start
end
-
+
def after_start
end
-
+
def before_restart
end
-
+
def after_restart
end
-
+
def before_stop
end
-
+
def after_stop
end
-
+
# Construct the friendly name of this Behavior, looks like:
#
# Behavior FooBar on Watch 'baz'
@@ -48,5 +48,5 @@ def friendly_name
"Behavior " + super + " on Watch '#{self.watch.name}'"
end
end
-
+
end
\ No newline at end of file
diff --git a/lib/god/behaviors/clean_pid_file.rb b/lib/god/behaviors/clean_pid_file.rb
index df404fa8..11839b48 100644
--- a/lib/god/behaviors/clean_pid_file.rb
+++ b/lib/god/behaviors/clean_pid_file.rb
@@ -1,21 +1,21 @@
module God
module Behaviors
-
+
class CleanPidFile < Behavior
def valid?
valid = true
valid &= complain("Attribute 'pid_file' must be specified", self) if self.watch.pid_file.nil?
valid
end
-
+
def before_start
File.delete(self.watch.pid_file)
-
+
"deleted pid file"
rescue
"no pid file to delete"
end
end
-
+
end
end
\ No newline at end of file
diff --git a/lib/god/behaviors/clean_unix_socket.rb b/lib/god/behaviors/clean_unix_socket.rb
index 6b505311..da93d0c3 100644
--- a/lib/god/behaviors/clean_unix_socket.rb
+++ b/lib/god/behaviors/clean_unix_socket.rb
@@ -1,21 +1,21 @@
module God
module Behaviors
-
+
class CleanUnixSocket < Behavior
def valid?
valid = true
valid &= complain("Attribute 'unix_socket' must be specified", self) if self.watch.unix_socket.nil?
valid
- end
-
- def before_start
+ end
+
+ def before_start
File.delete(self.watch.unix_socket)
-
- "deleted unix socket"
- rescue
- "no unix socket to delete"
+
+ "deleted unix socket"
+ rescue
+ "no unix socket to delete"
end
end
-
+
end
end
\ No newline at end of file
diff --git a/lib/god/behaviors/notify_when_flapping.rb b/lib/god/behaviors/notify_when_flapping.rb
index 6ede3a4a..a7c20c8e 100644
--- a/lib/god/behaviors/notify_when_flapping.rb
+++ b/lib/god/behaviors/notify_when_flapping.rb
@@ -1,44 +1,44 @@
module God
module Behaviors
-
+
class NotifyWhenFlapping < Behavior
- attr_accessor :failures # number of failures
+ attr_accessor :failures # number of failures
attr_accessor :seconds # number of seconds
attr_accessor :notifier # class to notify with
-
+
def initialize
super
@startup_times = []
end
-
+
def valid?
valid = true
valid &= complain("Attribute 'failures' must be specified", self) unless self.failures
valid &= complain("Attribute 'seconds' must be specified", self) unless self.seconds
valid &= complain("Attribute 'notifier' must be specified", self) unless self.notifier
-
+
# Must take one arg or variable args
unless self.notifier.respond_to?(:notify) and [1,-1].include?(self.notifier.method(:notify).arity)
valid &= complain("The 'notifier' must have a method 'notify' which takes 1 or variable args", self)
end
-
+
valid
end
-
+
def before_start
now = Time.now.to_i
@startup_times << now
check_for_flapping(now)
end
-
+
def before_restart
now = Time.now.to_i
@startup_times << now
check_for_flapping(now)
end
-
+
private
-
+
def check_for_flapping(now)
@startup_times.select! {|time| time >= now - self.seconds }
if @startup_times.length >= self.failures
@@ -46,6 +46,6 @@ def check_for_flapping(now)
end
end
end
-
+
end
end
\ No newline at end of file
diff --git a/lib/god/cli/command.rb b/lib/god/cli/command.rb
index 9da357f7..8c4dbf86 100644
--- a/lib/god/cli/command.rb
+++ b/lib/god/cli/command.rb
@@ -1,20 +1,20 @@
module God
module CLI
-
+
class Command
def initialize(command, options, args)
@command = command
@options = options
@args = args
-
+
dispatch
end
-
+
def setup
# connect to drb unix socket
DRb.start_service("druby://127.0.0.1:0")
@server = DRbObject.new(nil, God::Socket.socket(@options[:port]))
-
+
# ping server to ensure that it is responsive
begin
@server.ping
@@ -23,7 +23,7 @@ def setup
abort
end
end
-
+
def dispatch
if %w{load status log quit terminate}.include?(@command)
setup
@@ -38,19 +38,19 @@ def dispatch
abort
end
end
-
+
def load_command
file = @args[1]
-
+
puts "Sending '#{@command}' command"
puts
-
+
unless File.exist?(file)
abort "File not found: #{file}"
end
-
+
names, errors = *@server.running_load(File.read(file), File.expand_path(file))
-
+
# output response
unless names.empty?
puts 'The following tasks were affected:'
@@ -58,13 +58,13 @@ def load_command
puts ' ' + w
end
end
-
+
unless errors.empty?
puts errors
exit(1)
end
end
-
+
def status_command
watches = {}
@server.status.each do |name, status|
@@ -83,17 +83,17 @@ def status_command
end
end
end
-
+
def log_command
begin
Signal.trap('INT') { exit }
name = @args[1]
-
+
unless name
puts "You must specify a Task or Group name"
exit!
end
-
+
t = Time.at(0)
loop do
print @server.running_log(name, t)
@@ -106,7 +106,7 @@ def log_command
puts "The server went away"
end
end
-
+
def quit_command
begin
@server.terminate
@@ -115,7 +115,7 @@ def quit_command
puts 'Stopped god'
end
end
-
+
def terminate_command
t = Thread.new { loop { STDOUT.print('.'); STDOUT.flush; sleep(1) } }
if @server.stop_all
@@ -125,7 +125,7 @@ def terminate_command
t.kill; STDOUT.puts
puts 'Could not stop all watches within 10 seconds'
end
-
+
begin
@server.terminate
abort 'Could not stop god'
@@ -133,13 +133,13 @@ def terminate_command
puts 'Stopped god'
end
end
-
+
def check_command
Thread.new do
begin
event_system = God::EventHandler.event_system
puts "using event system: #{event_system}"
-
+
if God::EventHandler.loaded?
puts "starting event handler"
God::EventHandler.start
@@ -147,48 +147,48 @@ def check_command
puts "[fail] event system did not load"
exit(1)
end
-
+
puts 'forking off new process'
-
+
pid = fork do
loop { sleep(1) }
end
-
+
puts "forked process with pid = #{pid}"
-
+
God::EventHandler.register(pid, :proc_exit) do
puts "[ok] process exit event received"
exit!(0)
end
-
+
sleep(1)
-
+
puts "killing process"
-
+
::Process.kill('KILL', pid)
rescue => e
puts e.message
puts e.backtrace.join("\n")
end
end
-
+
sleep(2)
-
+
puts "[fail] never received process exit event"
exit(1)
end
-
+
def lifecycle_command
# get the name of the watch/group
name = @args[1]
-
+
puts "Sending '#{@command}' command"
-
+
t = Thread.new { loop { sleep(1); STDOUT.print('.'); STDOUT.flush; sleep(1) } }
-
+
# send @command
watches = @server.control(name, @command)
-
+
# output response
t.kill; STDOUT.puts
unless watches.empty?
@@ -201,6 +201,6 @@ def lifecycle_command
end
end
end # Command
-
+
end
end
diff --git a/lib/god/cli/run.rb b/lib/god/cli/run.rb
index 80161fde..69db91ea 100644
--- a/lib/god/cli/run.rb
+++ b/lib/god/cli/run.rb
@@ -1,6 +1,6 @@
module God
module CLI
-
+
class Run
def initialize(options)
@options = options
@@ -8,14 +8,14 @@ def initialize(options)
unless @options[:syslog]
Logger.syslog = false
end
-
+
dispatch
end
-
+
def dispatch
# have at_exit start god
$run = true
-
+
# run
if @options[:daemonize]
run_daemonized
@@ -23,7 +23,7 @@ def dispatch
run_in_front
end
end
-
+
def attach
process = System::Process.new(@options[:attach])
Thread.new do
@@ -36,54 +36,54 @@ def attach
end
end
end
-
+
def default_run
# start attached pid watcher if necessary
if @options[:attach]
self.attach
end
-
+
if @options[:port]
God.port = @options[:port]
end
-
+
if @options[:events]
God::EventHandler.load
end
-
+
# set log level, defaults to WARN
if @options[:log_level]
God.log_level = @options[:log_level]
else
God.log_level = @options[:daemonize] ? :warn : :info
end
-
+
if @options[:config]
unless File.exist?(@options[:config])
abort "File not found: #{@options[:config]}"
end
-
+
# start the event handler
God::EventHandler.start if God::EventHandler.loaded?
-
+
load_config @options[:config]
end
end
-
+
def run_in_front
require 'god'
-
+
if @options[:bleakhouse]
BleakHouseDiagnostic.install
end
-
+
default_run
-
+
log_file = God.log_file
- log_file = File.expand_path(@options[:log]) if @options[:log]
+ log_file = File.expand_path(@options[:log]) if @options[:log]
if log_file
puts "Sending output to log file: #{log_file}"
-
+
# reset file descriptors
STDIN.reopen "/dev/null"
STDOUT.reopen(log_file, "a")
@@ -91,30 +91,30 @@ def run_in_front
STDOUT.sync = true
end
end
-
+
def run_daemonized
# trap and ignore SIGHUP
Signal.trap('HUP') {}
-
+
pid = fork do
begin
require 'god'
-
+
log_file = @options[:log] || God.log_file || "/dev/null"
-
+
# reset file descriptors
STDIN.reopen "/dev/null"
STDOUT.reopen(log_file, "a")
STDERR.reopen STDOUT
STDOUT.sync = true
-
+
# set pid if requested
if @options[:pid] # and as deamon
- God.pid = @options[:pid]
+ God.pid = @options[:pid]
end
-
+
default_run
-
+
unless God::EventHandler.loaded?
puts
puts "***********************************************************************"
@@ -125,23 +125,23 @@ def run_daemonized
puts "***********************************************************************"
puts
end
-
+
rescue => e
puts e.message
puts e.backtrace.join("\n")
abort "There was a fatal system error while starting god (see above)"
end
end
-
+
if @options[:pid]
File.open(@options[:pid], 'w') { |f| f.write pid }
end
-
+
::Process.detach pid
-
+
exit
end
-
+
def load_config(config)
if File.directory? config
files_loaded = false
@@ -157,7 +157,7 @@ def load_config(config)
end
end
end
-
+
def load_god_file(god_file)
load File.expand_path(god_file)
rescue Exception => e
@@ -170,8 +170,8 @@ def load_god_file(god_file)
return false
end
end
-
+
end # Run
-
+
end
end
diff --git a/lib/god/cli/version.rb b/lib/god/cli/version.rb
index fa1f6d85..57b87f1e 100644
--- a/lib/god/cli/version.rb
+++ b/lib/god/cli/version.rb
@@ -1,23 +1,23 @@
module God
module CLI
-
+
class Version
def self.version
require 'god'
-
+
# print version
puts "Version #{God::VERSION}"
exit
end
-
+
def self.version_extended
puts "Version: #{God::VERSION}"
puts "Polls: enabled"
puts "Events: " + God::EventHandler.event_system
-
+
exit
end
end
-
+
end
end
\ No newline at end of file
diff --git a/lib/god/condition.rb b/lib/god/condition.rb
index 7eb11ea7..3ede8ece 100644
--- a/lib/god/condition.rb
+++ b/lib/god/condition.rb
@@ -1,29 +1,29 @@
module God
-
+
class Condition < Behavior
attr_accessor :transition, :notify, :info, :phase
-
+
# Generate a Condition of the given kind. The proper class if found by camel casing the
# kind (which is given as an underscored symbol).
# +kind+ is the underscored symbol representing the class (e.g. :foo_bar for God::Conditions::FooBar)
def self.generate(kind, watch)
sym = kind.to_s.capitalize.gsub(/_(.)/){$1.upcase}.intern
c = God::Conditions.const_get(sym).new
-
+
unless c.kind_of?(PollCondition) || c.kind_of?(EventCondition) || c.kind_of?(TriggerCondition)
- abort "Condition '#{c.class.name}' must subclass God::PollCondition, God::EventCondition, or God::TriggerCondition"
+ abort "Condition '#{c.class.name}' must subclass God::PollCondition, God::EventCondition, or God::TriggerCondition"
end
-
+
if !EventHandler.loaded? && c.kind_of?(EventCondition)
abort "Condition '#{c.class.name}' requires an event system but none has been loaded"
end
-
+
c.watch = watch
c
rescue NameError
raise NoSuchConditionError.new("No Condition found with the class name God::Conditions::#{sym}")
end
-
+
def self.valid?(condition)
valid = true
if condition.notify
@@ -35,7 +35,7 @@ def self.valid?(condition)
end
valid
end
-
+
# Construct the friendly name of this Condition, looks like:
#
# Condition FooBar on Watch 'baz'
@@ -43,15 +43,15 @@ def friendly_name
"Condition #{self.class.name.split('::').last} on Watch '#{self.watch.name}'"
end
end
-
+
class PollCondition < Condition
- # all poll conditions can specify a poll interval
+ # all poll conditions can specify a poll interval
attr_accessor :interval
-
+
# Override this method in your Conditions (optional)
def before
end
-
+
# Override this method in your Conditions (mandatory)
#
# Return true if the test passes (everything is ok)
@@ -59,38 +59,38 @@ def before
def test
raise AbstractMethodNotOverriddenError.new("PollCondition#test must be overridden in subclasses")
end
-
+
# Override this method in your Conditions (optional)
def after
end
end
-
+
class EventCondition < Condition
def register
raise AbstractMethodNotOverriddenError.new("EventCondition#register must be overridden in subclasses")
end
-
+
def deregister
raise AbstractMethodNotOverriddenError.new("EventCondition#deregister must be overridden in subclasses")
end
end
-
+
class TriggerCondition < Condition
def process(event, payload)
raise AbstractMethodNotOverriddenError.new("TriggerCondition#process must be overridden in subclasses")
end
-
+
def trigger
self.watch.trigger(self)
end
-
+
def register
Trigger.register(self)
end
-
+
def deregister
Trigger.deregister(self)
end
end
-
+
end
\ No newline at end of file
diff --git a/lib/god/conditions/always.rb b/lib/god/conditions/always.rb
index f651863a..d817bd00 100644
--- a/lib/god/conditions/always.rb
+++ b/lib/god/conditions/always.rb
@@ -3,21 +3,21 @@ module Conditions
class Always < PollCondition
attr_accessor :what
-
+
def initialize
self.info = "always"
end
-
+
def valid?
valid = true
valid &= complain("Attribute 'what' must be specified", self) if self.what.nil?
valid
end
-
+
def test
@what
end
end
-
+
end
end
\ No newline at end of file
diff --git a/lib/god/conditions/complex.rb b/lib/god/conditions/complex.rb
index 50dd8ed4..42b39810 100644
--- a/lib/god/conditions/complex.rb
+++ b/lib/god/conditions/complex.rb
@@ -1,60 +1,60 @@
module God
module Conditions
-
+
class Complex < PollCondition
- AND = 0x1
+ AND = 0x1
OR = 0x2
NOT = 0x4
-
+
def initialize()
super
-
+
@oper_stack = []
@op_stack = []
-
+
@this = nil
end
-
+
def valid?
@oper_stack.inject(true) { |acc, oper| acc & oper.valid? }
end
-
+
def prepare
@oper_stack.each { |oper| oper.prepare }
end
-
+
def new_oper(kind, op)
oper = Condition.generate(kind, self.watch)
@oper_stack.push(oper)
@op_stack.push(op)
oper
end
-
+
def this(kind)
@this = Condition.generate(kind, self.watch)
yield @this if block_given?
end
-
+
def and(kind)
oper = new_oper(kind, 0x1)
yield oper if block_given?
end
-
+
def and_not(kind)
oper = new_oper(kind, 0x5)
yield oper if block_given?
end
-
+
def or(kind)
oper = new_oper(kind, 0x2)
yield oper if block_given?
end
-
+
def or_not(kind)
oper = new_oper(kind, 0x6)
yield oper if block_given?
end
-
+
def test
if @this.nil?
# Although this() makes sense semantically and therefore
@@ -71,16 +71,16 @@ def test
else
res = @this.test
end
-
+
@op_stack.each do |op|
cond = @oper_stack.shift
eval "res " + ((0 < op & AND) ? "&&" : "||") + "= " + ((0 < op & NOT) ? "!" : "") + "cond.test"
@oper_stack.push cond
end
-
+
res
end
end
-
+
end
end
\ No newline at end of file
diff --git a/lib/god/conditions/cpu_usage.rb b/lib/god/conditions/cpu_usage.rb
index c52007fc..886b2be1 100644
--- a/lib/god/conditions/cpu_usage.rb
+++ b/lib/god/conditions/cpu_usage.rb
@@ -1,9 +1,9 @@
module God
module Conditions
-
+
# Condition Symbol :cpu_usage
# Type: Poll
- #
+ #
# Trigger when the percent of CPU use of a process is above a specified limit.
# On multi-core systems, this number could conceivably be above 100.
#
@@ -11,7 +11,7 @@ module Conditions
# Required
# +pid_file+ is the pid file of the process in question. Automatically
# populated for Watches.
- # +above+ is the percent CPU above which to trigger the condition. You
+ # +above+ is the percent CPU above which to trigger the condition. You
# may use #percent to clarify this amount (see examples).
#
# Examples
@@ -30,42 +30,42 @@ module Conditions
# end
class CpuUsage < PollCondition
attr_accessor :above, :times, :pid_file
-
+
def initialize
super
self.above = nil
self.times = [1, 1]
end
-
+
def prepare
if self.times.kind_of?(Integer)
self.times = [self.times, self.times]
end
-
+
@timeline = Timeline.new(self.times[1])
end
-
+
def reset
@timeline.clear
end
-
+
def pid
self.pid_file ? File.read(self.pid_file).strip.to_i : self.watch.pid
end
-
+
def valid?
valid = true
valid &= complain("Attribute 'pid_file' must be specified", self) if self.pid_file.nil? && self.watch.pid_file.nil?
valid &= complain("Attribute 'above' must be specified", self) if self.above.nil?
valid
end
-
+
def test
process = System::Process.new(self.pid)
@timeline.push(process.percent_cpu)
-
+
history = "[" + @timeline.map { |x| "#{x > self.above ? '*' : ''}#{x}%%" }.join(", ") + "]"
-
+
if @timeline.select { |x| x > self.above }.size >= self.times.first
self.info = "cpu out of bounds #{history}"
return true
@@ -75,6 +75,6 @@ def test
end
end
end
-
+
end
end
\ No newline at end of file
diff --git a/lib/god/conditions/degrading_lambda.rb b/lib/god/conditions/degrading_lambda.rb
index 5bb97dd0..7616318b 100644
--- a/lib/god/conditions/degrading_lambda.rb
+++ b/lib/god/conditions/degrading_lambda.rb
@@ -1,21 +1,21 @@
module God
module Conditions
-
+
# This condition degrades its interval by a factor of two for 3 tries before failing
class DegradingLambda < PollCondition
attr_accessor :lambda
-
+
def initialize
super
@tries = 0
end
-
+
def valid?
valid = true
valid &= complain("Attribute 'lambda' must be specified", self) if self.lambda.nil?
valid
end
-
+
def test
puts "Calling test. Interval at #{self.interval}"
@original_interval ||= self.interval
@@ -30,13 +30,13 @@ def test
@tries = 0
self.interval = @original_interval
end
-
+
self.info = "lambda condition was not satisfied"
false
end
-
+
private
-
+
def pass?
begin
Timeout::timeout(@interval) {
diff --git a/lib/god/conditions/disk_usage.rb b/lib/god/conditions/disk_usage.rb
index 140b57b2..a9fff710 100644
--- a/lib/god/conditions/disk_usage.rb
+++ b/lib/god/conditions/disk_usage.rb
@@ -1,27 +1,27 @@
module God
module Conditions
-
+
class DiskUsage < PollCondition
attr_accessor :above, :mount_point
-
+
def initialize
super
self.above = nil
self.mount_point = nil
end
-
+
def valid?
valid = true
valid &= complain("Attribute 'mount_point' must be specified", self) if self.mount_point.nil?
valid &= complain("Attribute 'above' must be specified", self) if self.above.nil?
valid
end
-
+
def test
usage = `df | grep -i " #{self.mount_point}$" | awk '{print $5}' | sed 's/%//'`
usage.to_i > self.above
end
end
-
+
end
end
diff --git a/lib/god/conditions/flapping.rb b/lib/god/conditions/flapping.rb
index 78bf3293..bc63a817 100644
--- a/lib/god/conditions/flapping.rb
+++ b/lib/god/conditions/flapping.rb
@@ -1,11 +1,11 @@
module God
module Conditions
-
+
# Condition Symbol :flapping
# Type: Trigger
- #
+ #
# Trigger when a Task transitions to or from a state or states a given number
- # of times within a given period.
+ # of times within a given period.
#
# Paramaters
# Required
@@ -24,7 +24,7 @@ module Conditions
# it has been disabled by the condition.
# +retry_times+ is the number of times after which to permanently unmonitor
# the Task.
- # +retry_within+ is the number of seconds within which
+ # +retry_within+ is the number of seconds within which
#
# Examples
#
@@ -37,16 +37,16 @@ class Flapping < TriggerCondition
:retry_in,
:retry_times,
:retry_within
-
+
def initialize
self.info = "process is flapping"
end
-
+
def prepare
@timeline = Timeline.new(self.times)
@retry_timeline = Timeline.new(self.retry_times)
end
-
+
def valid?
valid = true
valid &= complain("Attribute 'times' must be specified", self) if self.times.nil?
@@ -54,21 +54,21 @@ def valid?
valid &= complain("Attributes 'from_state', 'to_state', or both must be specified", self) if self.from_state.nil? && self.to_state.nil?
valid
end
-
+
def process(event, payload)
begin
if event == :state_change
event_from_state, event_to_state = *payload
-
+
from_state_match = !self.from_state || self.from_state && Array(self.from_state).include?(event_from_state)
to_state_match = !self.to_state || self.to_state && Array(self.to_state).include?(event_to_state)
-
+
if from_state_match && to_state_match
@timeline << Time.now
-
+
concensus = (@timeline.size == self.times)
duration = (@timeline.last - @timeline.first) < self.within
-
+
if concensus && duration
@timeline.clear
trigger
@@ -81,21 +81,21 @@ def process(event, payload)
puts e.backtrace.join("\n")
end
end
-
+
private
-
+
def retry_mechanism
if self.retry_in
@retry_timeline << Time.now
-
+
concensus = (@retry_timeline.size == self.retry_times)
duration = (@retry_timeline.last - @retry_timeline.first) < self.retry_within
-
+
if concensus && duration
# give up
Thread.new do
sleep 1
-
+
# log
msg = "#{self.watch.name} giving up"
applog(self.watch, :info, msg)
@@ -104,17 +104,17 @@ def retry_mechanism
# try again later
Thread.new do
sleep 1
-
+
# log
msg = "#{self.watch.name} auto-reenable monitoring in #{self.retry_in} seconds"
applog(self.watch, :info, msg)
-
+
sleep self.retry_in
-
+
# log
msg = "#{self.watch.name} auto-reenabling monitoring"
applog(self.watch, :info, msg)
-
+
if self.watch.state == :unmonitored
self.watch.monitor
end
@@ -123,6 +123,6 @@ def retry_mechanism
end
end
end
-
+
end
end
\ No newline at end of file
diff --git a/lib/god/conditions/http_response_code.rb b/lib/god/conditions/http_response_code.rb
index a005ef2e..f31489ae 100644
--- a/lib/god/conditions/http_response_code.rb
+++ b/lib/god/conditions/http_response_code.rb
@@ -2,10 +2,10 @@
module God
module Conditions
-
+
# Condition Symbol :http_response_code
# Type: Poll
- #
+ #
# Trigger based on the response from an HTTP request.
#
# Paramaters
@@ -71,7 +71,7 @@ class HttpResponseCode < PollCondition
:timeout, # e.g. 60.seconds
:path, # e.g. '/'
:headers # e.g. {'Host' => 'myvirtual.mydomain.com'}
-
+
def initialize
super
self.port = 80
@@ -80,24 +80,24 @@ def initialize
self.times = [1, 1]
self.timeout = 60.seconds
end
-
+
def prepare
self.code_is = Array(self.code_is).map { |x| x.to_i } if self.code_is
self.code_is_not = Array(self.code_is_not).map { |x| x.to_i } if self.code_is_not
-
+
if self.times.kind_of?(Integer)
self.times = [self.times, self.times]
end
-
+
@timeline = Timeline.new(self.times[1])
@history = Timeline.new(self.times[1])
end
-
+
def reset
@timeline.clear
@history.clear
end
-
+
def valid?
valid = true
valid &= complain("Attribute 'host' must be specified", self) if self.host.nil?
@@ -105,15 +105,15 @@ def valid?
(self.code_is.nil? && self.code_is_not.nil?) || (self.code_is && self.code_is_not)
valid
end
-
+
def test
response = nil
-
+
Net::HTTP.start(self.host, self.port) do |http|
http.read_timeout = self.timeout
response = http.get(self.path, self.headers)
end
-
+
actual_response_code = response.code.to_i
if self.code_is && self.code_is.include?(actual_response_code)
pass(actual_response_code)
@@ -135,9 +135,9 @@ def test
rescue Exception => failure
self.code_is ? fail(failure.class.name) : pass(failure.class.name)
end
-
+
private
-
+
def pass(code)
@timeline << true
if @timeline.select { |x| x }.size >= self.times.first
@@ -148,21 +148,21 @@ def pass(code)
false
end
end
-
+
def fail(code)
@timeline << false
self.info = "http response nominal #{history(code, false)}"
false
end
-
+
def history(code, passed)
entry = code.to_s.dup
entry = '*' + entry if passed
@history << entry
'[' + @history.join(", ") + ']'
end
-
+
end
-
+
end
end
\ No newline at end of file
diff --git a/lib/god/conditions/lambda.rb b/lib/god/conditions/lambda.rb
index 0eb72c26..5d8a1aa5 100644
--- a/lib/god/conditions/lambda.rb
+++ b/lib/god/conditions/lambda.rb
@@ -1,6 +1,6 @@
module God
module Conditions
-
+
class Lambda < PollCondition
attr_accessor :lambda
diff --git a/lib/god/conditions/memory_usage.rb b/lib/god/conditions/memory_usage.rb
index dc573c88..a5d95e10 100644
--- a/lib/god/conditions/memory_usage.rb
+++ b/lib/god/conditions/memory_usage.rb
@@ -1,9 +1,9 @@
module God
module Conditions
-
+
# Condition Symbol :memory_usage
# Type: Poll
- #
+ #
# Trigger when the resident memory of a process is above a specified limit.
#
# Paramaters
@@ -32,42 +32,42 @@ module Conditions
# end
class MemoryUsage < PollCondition
attr_accessor :above, :times, :pid_file
-
+
def initialize
super
self.above = nil
self.times = [1, 1]
end
-
+
def prepare
if self.times.kind_of?(Integer)
self.times = [self.times, self.times]
end
-
+
@timeline = Timeline.new(self.times[1])
end
-
+
def reset
@timeline.clear
end
-
+
def pid
self.pid_file ? File.read(self.pid_file).strip.to_i : self.watch.pid
end
-
+
def valid?
valid = true
valid &= complain("Attribute 'pid_file' must be specified", self) if self.pid_file.nil? && self.watch.pid_file.nil?
valid &= complain("Attribute 'above' must be specified", self) if self.above.nil?
valid
end
-
+
def test
process = System::Process.new(self.pid)
@timeline.push(process.memory)
-
+
history = "[" + @timeline.map { |x| "#{x > self.above ? '*' : ''}#{x}kb" }.join(", ") + "]"
-
+
if @timeline.select { |x| x > self.above }.size >= self.times.first
self.info = "memory out of bounds #{history}"
return true
@@ -77,6 +77,6 @@ def test
end
end
end
-
+
end
end
\ No newline at end of file
diff --git a/lib/god/conditions/process_exits.rb b/lib/god/conditions/process_exits.rb
index 54a82b92..4566a65a 100644
--- a/lib/god/conditions/process_exits.rb
+++ b/lib/god/conditions/process_exits.rb
@@ -1,9 +1,9 @@
module God
module Conditions
-
+
# Condition Symbol :process_exits
# Type: Event
- #
+ #
# Trigger when a process exits.
#
# Paramaters
@@ -24,41 +24,41 @@ module Conditions
# end
class ProcessExits < EventCondition
attr_accessor :pid_file
-
+
def initialize
self.info = "process exited"
end
-
+
def valid?
true
end
-
+
def pid
self.pid_file ? File.read(self.pid_file).strip.to_i : self.watch.pid
end
-
+
def register
pid = self.pid
-
+
begin
EventHandler.register(pid, :proc_exit) do |extra|
formatted_extra = extra.size > 0 ? " #{extra.inspect}" : ""
self.info = "process #{pid} exited#{formatted_extra}"
self.watch.trigger(self)
end
-
+
msg = "#{self.watch.name} registered 'proc_exit' event for pid #{pid}"
applog(self.watch, :info, msg)
rescue StandardError
raise EventRegistrationFailedError.new
end
end
-
+
def deregister
pid = self.pid
if pid
EventHandler.deregister(pid, :proc_exit)
-
+
msg = "#{self.watch.name} deregistered 'proc_exit' event for pid #{pid}"
applog(self.watch, :info, msg)
else
@@ -67,6 +67,6 @@ def deregister
end
end
end
-
+
end
end
\ No newline at end of file
diff --git a/lib/god/conditions/process_running.rb b/lib/god/conditions/process_running.rb
index 2877f364..0720a473 100644
--- a/lib/god/conditions/process_running.rb
+++ b/lib/god/conditions/process_running.rb
@@ -1,16 +1,16 @@
module God
module Conditions
-
+
# Condition Symbol :process_running
# Type: Poll
- #
+ #
# Trigger when a process is running or not running depending on attributes.
#
# Paramaters
# Required
# +pid_file+ is the pid file of the process in question. Automatically
# populated for Watches.
- # +running" specifies whether you want to trigger if the process is
+ # +running" specifies whether you want to trigger if the process is
# running (true) or whether it is not running (false)
#
# Examples
@@ -35,24 +35,24 @@ module Conditions
# end
class ProcessRunning < PollCondition
attr_accessor :running, :pid_file
-
+
def pid
self.pid_file ? File.read(self.pid_file).strip.to_i : self.watch.pid
end
-
+
def valid?
valid = true
valid &= complain("Attribute 'pid_file' must be specified", self) if self.pid_file.nil? && self.watch.pid_file.nil?
valid &= complain("Attribute 'running' must be specified", self) if self.running.nil?
valid
end
-
+
def test
self.info = []
-
+
pid = self.pid
active = pid && System::Process.new(pid).exists?
-
+
if (self.running && active)
self.info.concat(["process is running"])
true
@@ -69,6 +69,6 @@ def test
end
end
end
-
+
end
end
\ No newline at end of file
diff --git a/lib/god/conditions/tries.rb b/lib/god/conditions/tries.rb
index fdc03add..d666485c 100644
--- a/lib/god/conditions/tries.rb
+++ b/lib/god/conditions/tries.rb
@@ -1,35 +1,35 @@
module God
module Conditions
-
+
class Tries < PollCondition
attr_accessor :times, :within
-
+
def prepare
@timeline = Timeline.new(self.times)
end
-
+
def reset
@timeline.clear
end
-
+
def valid?
valid = true
valid &= complain("Attribute 'times' must be specified", self) if self.times.nil?
valid
end
-
+
def test
@timeline << Time.now
-
+
concensus = (@timeline.size == self.times)
duration = self.within.nil? || (@timeline.last - @timeline.first) < self.within
-
+
if within
history = "[#{@timeline.size}/#{self.times} within #{(@timeline.last - @timeline.first).to_i}s]"
else
history = "[#{@timeline.size}/#{self.times}]"
end
-
+
if concensus && duration
self.info = "tries exceeded #{history}"
return true
@@ -39,6 +39,6 @@ def test
end
end
end
-
+
end
end
\ No newline at end of file
diff --git a/lib/god/configurable.rb b/lib/god/configurable.rb
index ae6f0f02..c2cc2496 100644
--- a/lib/god/configurable.rb
+++ b/lib/god/configurable.rb
@@ -1,18 +1,18 @@
module God
-
+
module Configurable
# Override this method in your Configurable (optional)
#
# Called once after the Configurable has been sent to the block and attributes have been
# set. Do any post-processing on attributes here
def prepare
-
+
end
-
+
def reset
-
+
end
-
+
# Override this method in your Configurable (optional)
#
# Called once during evaluation of the config file. Return true if valid, false otherwise
@@ -29,16 +29,16 @@ def reset
def valid?
true
end
-
+
def base_name
x = 1 # fix for MRI's local scope optimization bug DO NOT REMOVE!
self.class.name.split('::').last
end
-
+
def friendly_name
base_name
end
-
+
def self.complain(text, c = nil)
watch = c.watch rescue nil
msg = ""
@@ -48,10 +48,10 @@ def self.complain(text, c = nil)
applog(watch, :error, msg)
false
end
-
+
def complain(text, c = nil)
Configurable.complain(text, c)
end
end
-
+
end
\ No newline at end of file
diff --git a/lib/god/contact.rb b/lib/god/contact.rb
index 5de3181d..7b782dc5 100644
--- a/lib/god/contact.rb
+++ b/lib/god/contact.rb
@@ -1,29 +1,29 @@
module God
-
+
class Contact
include Configurable
-
+
attr_accessor :name, :group, :info
-
+
def self.generate(kind)
sym = kind.to_s.capitalize.gsub(/_(.)/){$1.upcase}.intern
c = God::Contacts.const_get(sym).new
-
+
unless c.kind_of?(Contact)
- abort "Contact '#{c.class.name}' must subclass God::Contact"
+ abort "Contact '#{c.class.name}' must subclass God::Contact"
end
-
+
c
rescue NameError
raise NoSuchContactError.new("No Contact found with the class name God::Contacts::#{sym}")
end
-
+
def self.valid?(contact)
valid = true
valid &= Configurable.complain("Attribute 'name' must be specified", contact) if contact.name.nil?
valid
end
-
+
# Normalize the given notify specification into canonical form.
# +spec+ is the notify spec as a String, Array of Strings, or Hash
#
@@ -32,7 +32,7 @@ def self.valid?(contact)
# Where :contacts will be present and point to an Array of Strings. Both
# :priority and :category may not be present but if they are, they will each
# contain a single String.
- #
+ #
# Returns normalized notify spec
# Raises ArgumentError on invalid spec (message contains details)
def self.normalize(spec)
@@ -46,7 +46,7 @@ def self.normalize(spec)
{:contacts => spec}
when Hash
copy = spec.dup
-
+
# check :contacts
if contacts = copy.delete(:contacts)
case contacts
@@ -63,27 +63,27 @@ def self.normalize(spec)
else
raise ArgumentError.new("must have a :contacts key")
end
-
+
# remove priority and category
copy.delete(:priority)
copy.delete(:category)
-
+
# check for invalid keys
unless copy.empty?
raise ArgumentError.new("contains extra elements: #{copy.inspect}")
end
-
+
# normalize
spec[:contacts] &&= Array(spec[:contacts])
spec[:priority] &&= spec[:priority].to_s
spec[:category] &&= spec[:category].to_s
-
+
spec
else
raise ArgumentError.new("must be a String (contact name), Array (of contact names), or Hash (contact specification)")
end
end
-
+
# Abstract
# Send the message to the external source
# +message+ is the message body returned from the condition
@@ -94,7 +94,7 @@ def self.normalize(spec)
def notify(message, time, priority, category, host)
raise AbstractMethodNotOverriddenError.new("Contact#notify must be overridden in subclasses")
end
-
+
# Construct the friendly name of this Contact, looks like:
#
# Contact FooBar
@@ -102,5 +102,5 @@ def friendly_name
super + " Contact '#{self.name}'"
end
end
-
+
end
\ No newline at end of file
diff --git a/lib/god/contacts/email.rb b/lib/god/contacts/email.rb
index 36b59eae..e56785ff 100644
--- a/lib/god/contacts/email.rb
+++ b/lib/god/contacts/email.rb
@@ -3,16 +3,16 @@
module God
module Contacts
-
+
class Email < Contact
class << self
attr_accessor :message_settings, :delivery_method, :server_settings, :sendmail_settings, :format
end
-
+
self.message_settings = {:from => 'god@example.com'}
-
+
self.delivery_method = :smtp # or :sendmail
-
+
self.server_settings = {:address => 'localhost',
:port => 25}
# :domain
@@ -23,7 +23,7 @@ class << self
self.sendmail_settings = {:location => '/usr/sbin/sendmail',
:arguments => '-i -t'
}
-
+
self.format = lambda do |name, email, message, time, priority, category, host|
<<-EOF
From: god <#{self.message_settings[:from]}>
@@ -38,15 +38,15 @@ class << self
Category: #{category}
EOF
end
-
+
attr_accessor :email
-
+
def valid?
valid = true
valid &= complain("Attribute 'email' must be specified", self) if self.email.nil?
valid
end
-
+
def notify(message, time, priority, category, host)
begin
body = Email.format.call(self.name, self.email, message, time, priority, category, host)
@@ -59,7 +59,7 @@ def notify(message, time, priority, category, host)
else
raise "unknown delivery method: #{Email.delivery_method}"
end
-
+
self.info = "sent email to #{self.email}"
rescue => e
applog(nil, :info, "failed to send email to #{self.email}: #{e.message}")
@@ -75,7 +75,7 @@ def notify_smtp(mail)
args << Email.server_settings[:domain]
args << Email.server_settings[:user_name]
args << Email.server_settings[:password]
- args << Email.server_settings[:authentication]
+ args << Email.server_settings[:authentication]
end
Net::SMTP.start(*args) do |smtp|
diff --git a/lib/god/contacts/jabber.rb b/lib/god/contacts/jabber.rb
index a52f8617..d1469534 100644
--- a/lib/god/contacts/jabber.rb
+++ b/lib/god/contacts/jabber.rb
@@ -17,11 +17,11 @@ module XMPP4R
module God
module Contacts
- class Jabber < Contact
+ class Jabber < Contact
class << self
attr_accessor :settings, :format
end
-
+
self.format = lambda do |message, priority, category, host|
text = "Message: #{message}\n"
text += "Host: #{host}\n" if host
@@ -29,13 +29,13 @@ class << self
text += "Category: #{category}\n" if category
return text
end
-
+
attr_accessor :jabber_id
-
+
def valid?
valid = true
end
-
+
def notify(message, time, priority, category, host)
begin
jabber_id = XMPP4R::JID::new "#{Jabber.settings[:jabber_id]}/God"
@@ -44,7 +44,7 @@ def notify(message, time, priority, category, host)
jabber_client.auth Jabber.settings[:password]
body = Jabber.format.call message, priority, category, host
-
+
message = XMPP4R::Message::new self.jabber_id, body
message.set_type :normal
message.set_id '1'
@@ -55,11 +55,11 @@ def notify(message, time, priority, category, host)
rescue => e
puts e.message
puts e.backtrace.join("\n")
-
+
self.info = "failed to send jabber message to #{self.jabber_id}: #{e.message}"
end
end
end
-
+
end
end
\ No newline at end of file
diff --git a/lib/god/dependency_graph.rb b/lib/god/dependency_graph.rb
index 7a863427..13713671 100644
--- a/lib/god/dependency_graph.rb
+++ b/lib/god/dependency_graph.rb
@@ -1,17 +1,17 @@
module God
class DependencyGraph
attr_accessor :nodes
-
+
def initialize
self.nodes = {}
end
-
+
def add(a, b)
node_a = self.nodes[a] || Node.new(a)
node_b = self.nodes[b] || Node.new(b)
-
+
node_a.add(node_b)
-
+
self.nodes[a] ||= node_a
self.nodes[b] ||= node_b
end
@@ -23,16 +23,16 @@ class DependencyGraph
class Node
attr_accessor :name
attr_accessor :dependencies
-
+
def initialize(name)
self.name = name
self.dependencies = []
end
-
+
def add(node)
self.dependencies << node unless self.dependencies.include?(node)
end
-
+
def has_node?(node)
(self == node) || self.dependencies.any { |x| x.has_node?(node) }
end
diff --git a/lib/god/diagnostics.rb b/lib/god/diagnostics.rb
index d9be6e4a..2ce69094 100644
--- a/lib/god/diagnostics.rb
+++ b/lib/god/diagnostics.rb
@@ -11,21 +11,21 @@ def start_dike
class BleakHouseDiagnostic
LOG_FILE = File.join(File.dirname(__FILE__), *%w[.. .. logs bleak.log])
-
+
class << self
attr_accessor :logger
end
-
+
def self.install
require 'bleak_house'
self.logger = BleakHouse::Logger.new
File.delete(LOG_FILE) rescue nil
end
-
+
def self.snapshot(name)
self.logger.snapshot(LOG_FILE, name, false) if self.logger
end
-
+
def self.spin(delay = 1)
Thread.new do
loop do
diff --git a/lib/god/driver.rb b/lib/god/driver.rb
index 8188faf3..bd536a0b 100644
--- a/lib/god/driver.rb
+++ b/lib/god/driver.rb
@@ -3,7 +3,7 @@ class TimedEvent
include Comparable
attr_accessor :at
-
+
# Instantiate a new TimedEvent that will be triggered after the specified delay
# +delay+ is the number of seconds from now at which to trigger
#
@@ -23,13 +23,13 @@ def <=>(other)
class DriverEvent < TimedEvent
attr_accessor :condition, :task
-
+
def initialize(delay, task, condition)
super delay
self.task = task
self.condition = condition
end
-
+
def handle_event
@task.handle_poll(@condition)
end
@@ -44,7 +44,7 @@ def initialize(task, name, args)
self.name = name
self.args = args
end
-
+
# Handle the next queued operation that was issued asynchronously
#
# Returns nothing
@@ -52,8 +52,8 @@ def handle_event
@task.send(@name, *@args)
end
end
-
- class DriverEventQueue
+
+ class DriverEventQueue
def initialize
@shutdown = false
@waiting = []
@@ -63,9 +63,9 @@ def initialize
self.taint
end
- #
+ #
# Wake any sleeping threads after setting the sentinel
- #
+ #
def shutdown
@shutdown = true
begin
@@ -103,8 +103,8 @@ def pop
alias shift pop
alias deq pop
- #
- # Add an event to the queue, wake any waiters if what we added needs to
+ #
+ # Add an event to the queue, wake any waiters if what we added needs to
# happen sooner than the next pending event
#
def push(event)
@@ -150,7 +150,7 @@ def num_waiting
class Driver
attr_reader :thread
-
+
# Instantiate a new Driver and start the scheduler loop to handle events
# +task+ is the Task this Driver belongs to
#
@@ -158,7 +158,7 @@ class Driver
def initialize(task)
@task = task
@events = God::DriverEventQueue.new
-
+
@thread = Thread.new do
loop do
begin
@@ -174,14 +174,14 @@ def initialize(task)
end
end
end
-
+
# Clear all events for this Driver
- #
+ #
# Returns nothing
def clear_events
@events.clear
end
-
+
# Queue an asynchronous message
# +name+ is the Symbol name of the operation
# +args+ is an optional Array of arguments
@@ -190,7 +190,7 @@ def clear_events
def message(name, args = [])
@events.push(DriverOperation.new(@task, name, args))
end
-
+
# Create and schedule a new DriverEvent
# +condition+ is the Condition
# +delay+ is the number of seconds to delay (default: interval defined in condition)
@@ -198,9 +198,9 @@ def message(name, args = [])
# Returns nothing
def schedule(condition, delay = condition.interval)
applog(nil, :debug, "driver schedule #{condition} in #{delay} seconds")
-
+
@events.push(DriverEvent.new(delay, @task, condition))
end
end # Driver
-
+
end # God
diff --git a/lib/god/errors.rb b/lib/god/errors.rb
index 6ba50c16..5b4814d9 100644
--- a/lib/god/errors.rb
+++ b/lib/god/errors.rb
@@ -1,24 +1,24 @@
module God
-
+
class AbstractMethodNotOverriddenError < StandardError
end
-
+
class NoSuchWatchError < StandardError
end
-
+
class NoSuchConditionError < StandardError
end
-
+
class NoSuchBehaviorError < StandardError
end
-
+
class NoSuchContactError < StandardError
end
-
+
class InvalidCommandError < StandardError
end
-
+
class EventRegistrationFailedError < StandardError
end
-
+
end
\ No newline at end of file
diff --git a/lib/god/event_handler.rb b/lib/god/event_handler.rb
index c46965ef..2bd6b3e9 100644
--- a/lib/god/event_handler.rb
+++ b/lib/god/event_handler.rb
@@ -3,15 +3,15 @@ class EventHandler
@@actions = {}
@@handler = nil
@@loaded = false
-
+
def self.loaded?
@@loaded
end
-
+
def self.event_system
@@handler::EVENT_SYSTEM
end
-
+
def self.load
begin
case RUBY_PLATFORM
@@ -31,13 +31,13 @@ def self.load
@@loaded = false
end
end
-
+
def self.register(pid, event, &block)
@@actions[pid] ||= {}
@@actions[pid][event] = block
@@handler.register_process(pid, @@actions[pid].keys)
end
-
+
def self.deregister(pid, event=nil)
if watching_pid? pid
running = ::Process.kill(0, pid.to_i) rescue false
@@ -50,15 +50,15 @@ def self.deregister(pid, event=nil)
end
end
end
-
+
def self.call(pid, event, extra_data = {})
@@actions[pid][event].call(extra_data) if watching_pid?(pid) && @@actions[pid][event]
end
-
+
def self.watching_pid?(pid)
@@actions[pid]
end
-
+
def self.start
Thread.new do
loop do
@@ -71,41 +71,41 @@ def self.start
end
end
end
-
+
# do a real test to make sure events are working properly
@@loaded = self.operational?
end
-
+
def self.operational?
com = [false]
-
+
Thread.new do
begin
event_system = God::EventHandler.event_system
-
+
pid = fork do
loop { sleep(1) }
end
-
+
self.register(pid, :proc_exit) do
com[0] = true
end
-
+
::Process.kill('KILL', pid)
-
+
sleep(0.1)
-
+
self.deregister(pid, :proc_exit) rescue nil
rescue => e
puts e.message
puts e.backtrace.join("\n")
end
end.join
-
+
sleep(0.1)
-
+
com.first
end
-
+
end
end
\ No newline at end of file
diff --git a/lib/god/event_handlers/dummy_handler.rb b/lib/god/event_handlers/dummy_handler.rb
index e453dbbd..2e700d4b 100644
--- a/lib/god/event_handlers/dummy_handler.rb
+++ b/lib/god/event_handlers/dummy_handler.rb
@@ -1,11 +1,11 @@
module God
class DummyHandler
EVENT_SYSTEM = "none"
-
+
def self.register_process
raise NotImplementedError
end
-
+
def self.handle_events
raise NotImplementedError
end
diff --git a/lib/god/event_handlers/kqueue_handler.rb b/lib/god/event_handlers/kqueue_handler.rb
index 1068bed4..7d01e1a9 100644
--- a/lib/god/event_handlers/kqueue_handler.rb
+++ b/lib/god/event_handlers/kqueue_handler.rb
@@ -3,11 +3,11 @@
module God
class KQueueHandler
EVENT_SYSTEM = "kqueue"
-
+
def self.register_process(pid, events)
monitor_process(pid, events_mask(events))
end
-
+
def self.events_mask(events)
events.inject(0) do |mask, event|
mask |= event_mask(event)
diff --git a/lib/god/event_handlers/netlink_handler.rb b/lib/god/event_handlers/netlink_handler.rb
index eb7e1573..6d775850 100644
--- a/lib/god/event_handlers/netlink_handler.rb
+++ b/lib/god/event_handlers/netlink_handler.rb
@@ -3,7 +3,7 @@
module God
class NetlinkHandler
EVENT_SYSTEM = "netlink"
-
+
def self.register_process(pid, events)
# netlink doesn't need to do this
# it just reads from the eventhandler actions to see if the pid
diff --git a/lib/god/logger.rb b/lib/god/logger.rb
index 5215c6b0..bb59707b 100644
--- a/lib/god/logger.rb
+++ b/lib/god/logger.rb
@@ -1,20 +1,20 @@
module God
-
+
class Logger < SimpleLogger
SYSLOG_EQUIVALENTS = {:fatal => :crit,
:error => :err,
:warn => :debug,
:info => :debug,
:debug => :debug}
-
+
attr_accessor :logs
-
+
class << self
attr_accessor :syslog
end
-
+
self.syslog ||= true
-
+
# Instantiate a new Logger object
def initialize
super($stdout)
@@ -26,17 +26,17 @@ def initialize
@templog.level = Logger::INFO
load_syslog
end
-
+
# If Logger.syslog is true then attempt to load the syslog bindings. If syslog
# cannot be loaded, then set Logger.syslog to false and continue.
#
# Returns nothing
def load_syslog
return unless Logger.syslog
-
+
begin
require 'syslog'
-
+
# Ensure that Syslog is open
begin
Syslog.open('god')
@@ -47,7 +47,7 @@ def load_syslog
Logger.syslog = false
end
end
-
+
# Log a message
# +watch+ is the String name of the Watch (may be nil if not Watch is applicable)
# +level+ is the log level [:debug|:info|:warn|:error|:fatal]
@@ -57,7 +57,7 @@ def load_syslog
def log(watch, level, text)
# initialize watch log if necessary
self.logs[watch.name] ||= Timeline.new(God::LOG_BUFFER_SIZE_DEFAULT) if watch
-
+
# push onto capture and timeline for the given watch
@templogio.truncate(0)
@templogio.rewind
@@ -66,14 +66,14 @@ def log(watch, level, text)
@capture.puts(@templogio.string.dup) if @capture
self.logs[watch.name] << [Time.now, @templogio.string.dup] if watch
end
-
+
# send to regular logger
self.send(level, text % [])
-
+
# send to syslog
Syslog.send(SYSLOG_EQUIVALENTS[level], text) if Logger.syslog
end
-
+
# Get all log output for a given Watch since a certain Time.
# +watch_name+ is the String name of the Watch
# +since+ is the Time since which to fetch log lines
@@ -82,7 +82,7 @@ def log(watch, level, text)
def watch_log_since(watch_name, since)
# initialize watch log if necessary
self.logs[watch_name] ||= Timeline.new(God::LOG_BUFFER_SIZE_DEFAULT)
-
+
# get and join lines since given time
@mutex.synchronize do
self.logs[watch_name].select do |x|
@@ -92,9 +92,9 @@ def watch_log_since(watch_name, since)
end.join
end
end
-
+
# private
-
+
# Enable capturing of log
#
# Returns nothing
@@ -103,7 +103,7 @@ def start_capture
@capture = StringIO.new
end
end
-
+
# Disable capturing of log and return what was captured since
# capturing was enabled with Logger#start_capture
#
@@ -116,5 +116,5 @@ def finish_capture
end
end
end
-
+
end
\ No newline at end of file
diff --git a/lib/god/metric.rb b/lib/god/metric.rb
index 936f2ab6..7a709a82 100644
--- a/lib/god/metric.rb
+++ b/lib/god/metric.rb
@@ -1,14 +1,14 @@
module God
-
+
class Metric
attr_accessor :watch, :destination, :conditions
-
+
def initialize(watch, destination = nil)
self.watch = watch
self.destination = destination
self.conditions = []
end
-
+
# Instantiate a Condition of type +kind+ and pass it into the optional
# block. Attributes of the condition must be set in the config file
def condition(kind)
@@ -18,18 +18,18 @@ def condition(kind)
rescue NoSuchConditionError => e
abort e.message
end
-
+
# send to block so config can set attributes
yield(c) if block_given?
-
+
# call prepare on the condition
c.prepare
-
+
# test generic and specific validity
unless Condition.valid?(c) && c.valid?
abort "Exiting on invalid condition"
end
-
+
# inherit interval from watch if no poll condition specific interval was set
if c.kind_of?(PollCondition) && !c.interval
if self.watch.interval
@@ -38,22 +38,22 @@ def condition(kind)
abort "No interval set for Condition '#{c.class.name}' in Watch '#{self.watch.name}', and no default Watch interval from which to inherit"
end
end
-
+
# remember
self.conditions << c
end
-
+
def enable
self.conditions.each do |c|
self.watch.attach(c)
end
end
-
+
def disable
self.conditions.each do |c|
self.watch.detach(c)
end
end
end
-
+
end
\ No newline at end of file
diff --git a/lib/god/process.rb b/lib/god/process.rb
index 6817416e..fdb16e67 100644
--- a/lib/god/process.rb
+++ b/lib/god/process.rb
@@ -1,19 +1,19 @@
module God
class Process
WRITES_PID = [:start, :restart]
-
+
attr_accessor :name, :uid, :gid, :log, :start, :stop, :restart, :unix_socket, :chroot, :env
-
+
def initialize
self.log = '/dev/null'
-
+
@pid_file = nil
@tracking_pid = true
@user_log = false
@pid = nil
@unix_socket = nil
end
-
+
def alive?
if self.pid
System::Process.new(self.pid).exists?
@@ -21,7 +21,7 @@ def alive?
false
end
end
-
+
def file_writable?(file)
pid = fork do
uid_num = Etc.getpwnam(self.uid).uid if self.uid
@@ -34,29 +34,29 @@ def file_writable?(file)
File.writable?(file_in_chroot(file)) ? exit(0) : exit(1)
end
-
+
wpid, status = ::Process.waitpid2(pid)
status.exitstatus == 0 ? true : false
end
-
+
def valid?
# determine if we're tracking pid or not
self.pid_file
-
+
valid = true
-
+
# a start command must be specified
if self.start.nil?
valid = false
applog(self, :error, "No start command was specified")
end
-
+
# self-daemonizing processes must specify a stop command
if !@tracking_pid && self.stop.nil?
valid = false
applog(self, :error, "No stop command was specified")
end
-
+
# uid must exist if specified
if self.uid
begin
@@ -66,7 +66,7 @@ def valid?
applog(self, :error, "UID for '#{self.uid}' does not exist")
end
end
-
+
# gid must exist if specified
if self.gid
begin
@@ -76,25 +76,25 @@ def valid?
applog(self, :error, "GID for '#{self.gid}' does not exist")
end
end
-
+
# pid dir must exist if specified
if !@tracking_pid && !File.exist?(File.dirname(self.pid_file))
valid = false
applog(self, :error, "PID file directory '#{File.dirname(self.pid_file)}' does not exist")
end
-
+
# pid dir must be writable if specified
if !@tracking_pid && File.exist?(File.dirname(self.pid_file)) && !file_writable?(File.dirname(self.pid_file))
valid = false
applog(self, :error, "PID file directory '#{File.dirname(self.pid_file)}' is not writable by #{self.uid || Etc.getlogin}")
end
-
+
# log dir must exist
if !File.exist?(File.dirname(self.log))
valid = false
applog(self, :error, "Log directory '#{File.dirname(self.log)}' does not exist")
end
-
+
# log file or dir must be writable
if File.exist?(self.log)
unless file_writable?(self.log)
@@ -120,10 +120,10 @@ def valid?
LOG.log(self, :error, "CHROOT directory '#{self.chroot}' does not contain '/dev/null'")
end
end
-
+
valid
end
-
+
# DON'T USE THIS INTERNALLY. Use the instance variable. -- Kev
# No really, trust me. Use the instance variable.
def pid_file=(value)
@@ -133,14 +133,14 @@ def pid_file=(value)
else
@tracking_pid = true
end
-
+
@pid_file = value
end
-
+
def pid_file
@pid_file ||= default_pid_file
end
-
+
# Fetch the PID from pid_file. If the pid_file does not
# exist, then use the PID from the last time it was read.
# If it has never been read, then return nil.
@@ -149,7 +149,7 @@ def pid_file
def pid
contents = File.read(self.pid_file).strip rescue ''
real_pid = contents =~ /^\d+$/ ? contents.to_i : nil
-
+
if real_pid
@pid = real_pid
real_pid
@@ -157,35 +157,35 @@ def pid
@pid
end
end
-
+
def start!
call_action(:start)
end
-
+
def stop!
call_action(:stop)
end
-
+
def restart!
call_action(:restart)
end
-
+
def default_pid_file
File.join(God.pid_file_directory, "#{self.name}.pid")
end
-
+
def call_action(action)
command = send(action)
-
+
if action == :stop && command.nil?
pid = self.pid
name = self.name
command = lambda do
applog(self, :info, "#{self.name} stop: default lambda killer")
-
+
::Process.kill('TERM', pid) rescue nil
applog(self, :info, "#{self.name} sent SIGTERM")
-
+
# Poll to see if it's dead
5.times do
begin
@@ -195,18 +195,18 @@ def call_action(action)
applog(self, :info, "#{self.name} process stopped")
return
end
-
+
sleep 1
end
-
+
::Process.kill('KILL', pid) rescue nil
applog(self, :info, "#{self.name} still alive; sent SIGKILL")
end
end
-
+
if command.kind_of?(String)
pid = nil
-
+
if @tracking_pid
# double fork god-daemonized processes
# we don't want to wait for them to finish
@@ -218,7 +218,7 @@ def call_action(action)
pid = self.spawn(command)
puts pid.to_s # send pid back to forker
end
-
+
::Process.waitpid(opid, 0)
w.close
pid = r.gets.chomp
@@ -233,19 +233,19 @@ def call_action(action)
pid = self.spawn(command)
status = ::Process.waitpid2(pid, 0)
exit_code = status[1] >> 8
-
+
if exit_code != 0
applog(self, :warn, "#{self.name} #{action} command exited with non-zero code = #{exit_code}")
end
-
+
ensure_stop if action == :stop
end
-
+
if @tracking_pid or (@pid_file.nil? and WRITES_PID.include?(action))
File.open(default_pid_file, 'w') do |f|
f.write pid
end
-
+
@tracking_pid = true
@pid_file = default_pid_file
end
@@ -256,7 +256,7 @@ def call_action(action)
raise NotImplementedError
end
end
-
+
# Fork/exec the given command, returns immediately
# +command+ is the String containing the shell command
#
@@ -276,7 +276,7 @@ def spawn(command)
STDIN.reopen "/dev/null"
STDOUT.reopen file_in_chroot(self.log), "a"
STDERR.reopen STDOUT
-
+
# close any other file descriptors
3.upto(256){|fd| IO::new(fd).close rescue nil}
@@ -289,7 +289,7 @@ def spawn(command)
exec command unless command.empty?
end
end
-
+
# Ensure that a stop command actually stops the process. Force kill
# if necessary.
#
@@ -299,7 +299,7 @@ def ensure_stop
applog(self, :warn, "#{self.name} stop called but pid is uknown")
return
end
-
+
# Poll to see if it's dead
10.times do
begin
@@ -308,10 +308,10 @@ def ensure_stop
# It died. Good.
return
end
-
+
sleep 1
end
-
+
# last resort
::Process.kill('KILL', self.pid) rescue nil
applog(self, :warn, "#{self.name} process still running 10 seconds after stop command returned. Force killing.")
diff --git a/lib/god/registry.rb b/lib/god/registry.rb
index 2a5e71d9..d0f7542e 100644
--- a/lib/god/registry.rb
+++ b/lib/god/registry.rb
@@ -2,29 +2,29 @@ module God
def self.registry
@registry ||= Registry.new
end
-
+
class Registry
def initialize
@storage = {}
end
-
+
def add(item)
# raise TypeError unless item.is_a? God::Process
@storage[item.name] = item
end
-
+
def remove(item)
@storage.delete(item.name)
end
-
+
def size
@storage.size
end
-
+
def [](name)
@storage[name]
end
-
+
def reset
@storage.clear
end
diff --git a/lib/god/simple_logger.rb b/lib/god/simple_logger.rb
index 97677095..afd15117 100644
--- a/lib/god/simple_logger.rb
+++ b/lib/god/simple_logger.rb
@@ -1,53 +1,53 @@
module God
-
+
class SimpleLogger
DEBUG = 2
INFO = 4
WARN = 8
ERROR = 16
FATAL = 32
-
+
SEV_LABEL = {DEBUG => 'DEBUG',
INFO => 'INFO',
WARN => 'WARN',
ERROR => 'ERROR',
FATAL => 'FATAL'}
-
+
attr_accessor :datetime_format, :level
-
+
def initialize(io)
@io = io
@level = INFO
@datetime_format = "%Y-%m-%d %H:%M:%S"
end
-
+
def output(level, msg)
return if level < self.level
-
+
time = Time.now.strftime(self.datetime_format)
label = SEV_LABEL[level]
@io.print("#{label[0..0]} [#{time}] #{label.rjust(5)}: #{msg}\n")
end
-
+
def fatal(msg)
self.output(FATAL, msg)
end
-
+
def error(msg)
self.output(ERROR, msg)
end
-
+
def warn(msg)
self.output(WARN, msg)
end
-
+
def info(msg)
self.output(INFO, msg)
end
-
+
def debug(msg)
self.output(DEBUG, msg)
end
end
-
+
end
\ No newline at end of file
diff --git a/lib/god/socket.rb b/lib/god/socket.rb
index 72914032..0b178f8f 100644
--- a/lib/god/socket.rb
+++ b/lib/god/socket.rb
@@ -5,7 +5,7 @@ module God
# The God::Server oversees the DRb server which dishes out info on this God daemon.
class Socket
attr_reader :port
-
+
# The location of the socket for a given port
# +port+ is the port number
#
@@ -13,7 +13,7 @@ class Socket
def self.socket_file(port)
"/tmp/god.#{port}.sock"
end
-
+
# The address of the socket for a given port
# +port+ is the port number
#
@@ -21,40 +21,40 @@ def self.socket_file(port)
def self.socket(port)
"drbunix://#{self.socket_file(port)}"
end
-
+
# The location of the socket for this Server
#
# Returns String (file location)
def socket_file
self.class.socket_file(@port)
end
-
+
# The address of the socket for this Server
#
# Returns String (drb address)
def socket
self.class.socket(@port)
end
-
+
# Create a new Server and star the DRb server
# +port+ is the port on which to start the DRb service (default nil)
def initialize(port = nil)
@port = port
start
end
-
+
# Returns true
def ping
true
end
-
+
# Forward API calls to God
#
# Returns whatever the forwarded call returns
def method_missing(*args, &block)
God.send(*args, &block)
end
-
+
# Stop the DRb server and delete the socket file
#
# Returns nothing
@@ -62,9 +62,9 @@ def stop
DRb.stop_service
FileUtils.rm_f(self.socket_file)
end
-
+
private
-
+
# Start the DRb server. Abort if there is already a running god instance
# on the socket.
#
@@ -77,7 +77,7 @@ def start
applog(nil, :info, "Socket already in use")
DRb.start_service
server = DRbObject.new(nil, self.socket)
-
+
begin
Timeout.timeout(5) do
server.ping
diff --git a/lib/god/sugar.rb b/lib/god/sugar.rb
index 11795572..6b625baf 100644
--- a/lib/god/sugar.rb
+++ b/lib/god/sugar.rb
@@ -2,45 +2,45 @@ class Numeric
def seconds
self
end
-
+
alias :second :seconds
-
+
def minutes
self * 60
end
-
+
alias :minute :minutes
-
+
def hours
self * 3600
end
-
+
alias :hour :hours
-
+
def days
self * 86400
end
-
+
alias :day :days
-
+
def kilobytes
self
end
-
+
alias :kilobyte :kilobytes
-
+
def megabytes
self * 1024
end
-
+
alias :megabyte :megabytes
-
+
def gigabytes
self * (1024 ** 2)
end
-
+
alias :gigabyte :gigabytes
-
+
def percent
self
end
diff --git a/lib/god/system/portable_poller.rb b/lib/god/system/portable_poller.rb
index 95eb0e5a..d9a28759 100644
--- a/lib/god/system/portable_poller.rb
+++ b/lib/god/system/portable_poller.rb
@@ -8,31 +8,31 @@ def initialize(pid)
def memory
ps_int('rss')
end
-
+
# Percentage memory usage
def percent_memory
ps_float('%mem')
end
-
+
# Percentage CPU usage
def percent_cpu
ps_float('%cpu')
end
-
+
private
-
+
def ps_int(keyword)
`ps -o #{keyword}= -p #{@pid}`.to_i
end
-
+
def ps_float(keyword)
`ps -o #{keyword}= -p #{@pid}`.to_f
end
-
+
def ps_string(keyword)
`ps -o #{keyword}= -p #{@pid}`.strip
end
-
+
def time_string_to_seconds(text)
_, minutes, seconds, useconds = *text.match(/(\d+):(\d{2}).(\d{2})/)
(minutes.to_i * 60) + seconds.to_i
diff --git a/lib/god/system/process.rb b/lib/god/system/process.rb
index e2741bf0..0ce0051b 100644
--- a/lib/god/system/process.rb
+++ b/lib/god/system/process.rb
@@ -1,34 +1,34 @@
module God
module System
-
+
class Process
def initialize(pid)
@pid = pid.to_i
@poller = fetch_system_poller.new(@pid)
end
-
+
# Return true if this process is running, false otherwise
def exists?
!!::Process.kill(0, @pid) rescue false
end
-
+
# Memory usage in kilobytes (resident set size)
def memory
@poller.memory
end
-
+
# Percentage memory usage
def percent_memory
@poller.percent_memory
end
-
+
# Percentage CPU usage
def percent_cpu
@poller.percent_cpu
end
-
+
private
-
+
def fetch_system_poller
if SlashProcPoller.usable?
SlashProcPoller
@@ -37,6 +37,6 @@ def fetch_system_poller
end
end
end
-
+
end
end
\ No newline at end of file
diff --git a/lib/god/system/slash_proc_poller.rb b/lib/god/system/slash_proc_poller.rb
index 31879c8c..2c256edb 100644
--- a/lib/god/system/slash_proc_poller.rb
+++ b/lib/god/system/slash_proc_poller.rb
@@ -4,12 +4,12 @@ class SlashProcPoller < PortablePoller
@@kb_per_page = 4 # TODO: Need to make this portable
@@hertz = 100
@@total_mem = nil
-
+
MeminfoPath = '/proc/meminfo'
UptimePath = '/proc/uptime'
-
+
RequiredPaths = [MeminfoPath, UptimePath]
-
+
# FreeBSD has /proc by default, but nothing mounted there!
# So we should check for the actual required paths!
# Returns true if +RequiredPaths+ are readable.
@@ -18,29 +18,29 @@ def self.usable?
test(?r, path)
end
end
-
+
def initialize(pid)
super(pid)
-
+
unless @@total_mem # in K
File.open(MeminfoPath) do |f|
@@total_mem = f.gets.split[1]
end
end
end
-
+
def memory
stat[:rss].to_i * @@kb_per_page
rescue # This shouldn't fail is there's an error (or proc doesn't exist)
0
end
-
+
def percent_memory
(memory / @@total_mem.to_f) * 100
rescue # This shouldn't fail is there's an error (or proc doesn't exist)
0
end
-
+
# TODO: Change this to calculate the wma instead
def percent_cpu
stats = stat
@@ -54,14 +54,14 @@ def percent_cpu
rescue # This shouldn't fail is there's an error (or proc doesn't exist)
0
end
-
+
private
-
+
# in seconds
def uptime
File.read(UptimePath).split[0].to_f
end
-
+
def stat
stats = {}
stats[:pid], stats[:comm], stats[:state], stats[:ppid], stats[:pgrp],
diff --git a/lib/god/task.rb b/lib/god/task.rb
index 7c88da79..bd0ff185 100644
--- a/lib/god/task.rb
+++ b/lib/god/task.rb
@@ -1,87 +1,87 @@
module God
-
+
class Task
attr_accessor :name, :interval, :group, :valid_states, :initial_state, :driver
-
+
attr_writer :autostart
def autostart?; @autostart; end
-
+
# api
attr_accessor :state, :behaviors, :metrics, :directory
-
+
def initialize
@autostart ||= true
-
+
# initial state is unmonitored
self.state = :unmonitored
-
+
# the list of behaviors
self.behaviors = []
-
+
# the list of conditions for each action
self.metrics = {nil => [], :unmonitored => [], :stop => []}
-
+
# the condition -> metric lookup
self.directory = {}
-
+
# driver
self.driver = Driver.new(self)
end
-
+
def prepare
self.valid_states.each do |state|
self.metrics[state] ||= []
end
end
-
+
def valid?
valid = true
-
+
# a name must be specified
if self.name.nil?
valid = false
applog(self, :error, "No name was specified")
end
-
+
# valid_states must be specified
if self.valid_states.nil?
valid = false
applog(self, :error, "No valid_states array was specified")
end
-
+
# valid_states must be specified
if self.initial_state.nil?
valid = false
applog(self, :error, "No initial_state was specified")
end
-
+
valid
end
-
+
###########################################################################
#
# Advanced mode
#
###########################################################################
-
+
def canonical_hash_form(to)
to.instance_of?(Symbol) ? {true => to} : to
end
-
+
# Define a transition handler which consists of a set of conditions
def transition(start_states, end_states)
# convert end_states into canonical hash form
canonical_end_states = canonical_hash_form(end_states)
-
+
Array(start_states).each do |start_state|
# validate start state
unless self.valid_states.include?(start_state)
abort "Invalid state :#{start_state}. Must be one of the symbols #{self.valid_states.map{|x| ":#{x}"}.join(', ')}"
end
-
+
# create a new metric to hold the watch, end states, and conditions
m = Metric.new(self, canonical_end_states)
-
+
if block_given?
# let the config file define some conditions on the metric
yield(m)
@@ -91,54 +91,54 @@ def transition(start_states, end_states)
c.what = true
end
end
-
+
# populate the condition -> metric directory
m.conditions.each do |c|
self.directory[c] = m
end
-
+
# record the metric
self.metrics[start_state] ||= []
self.metrics[start_state] << m
end
end
-
+
def lifecycle
# create a new metric to hold the watch and conditions
m = Metric.new(self)
-
+
# let the config file define some conditions on the metric
yield(m)
-
+
# populate the condition -> metric directory
m.conditions.each do |c|
self.directory[c] = m
end
-
+
# record the metric
self.metrics[nil] << m
end
-
+
###########################################################################
#
# Lifecycle
#
###########################################################################
-
+
# Enable monitoring
#
# Returns nothing
def monitor
self.move(self.initial_state)
end
-
+
# Disable monitoring
#
# Returns nothing
def unmonitor
self.move(:unmonitored)
end
-
+
# Move to the givent state
# +to_state+ is the Symbol representing the state to move to
#
@@ -146,85 +146,85 @@ def unmonitor
def move(to_state)
if Thread.current != self.driver.thread
# called from outside Driver
-
+
# send an async message to Driver
self.driver.message(:move, [to_state])
else
# called from within Driver
-
+
# record original info
orig_to_state = to_state
from_state = self.state
-
+
# log
msg = "#{self.name} move '#{from_state}' to '#{to_state}'"
applog(self, :info, msg)
-
+
# cleanup from current state
self.driver.clear_events
self.metrics[from_state].each { |m| m.disable }
if to_state == :unmonitored
self.metrics[nil].each { |m| m.disable }
end
-
+
# perform action
self.action(to_state)
-
+
# enable simple mode
if [:start, :restart].include?(to_state) && self.metrics[to_state].empty?
to_state = :up
end
-
+
# move to new state
self.metrics[to_state].each { |m| m.enable }
-
+
# if no from state, enable lifecycle metric
if from_state == :unmonitored
self.metrics[nil].each { |m| m.enable }
end
-
+
# set state
self.state = to_state
-
+
# broadcast to interested TriggerConditions
Trigger.broadcast(self, :state_change, [from_state, orig_to_state])
-
+
# log
msg = "#{self.name} moved '#{from_state}' to '#{to_state}'"
applog(self, :info, msg)
end
-
+
self
end
-
+
# Notify the Driver that an EventCondition has triggered
#
# Returns nothing
def trigger(condition)
self.driver.message(:handle_event, [condition])
end
-
+
###########################################################################
#
# Actions
#
###########################################################################
-
+
def method_missing(sym, *args)
unless (sym.to_s =~ /=$/)
super
end
-
+
base = sym.to_s.chop.intern
-
+
unless self.valid_states.include?(base)
super
end
-
+
self.class.send(:attr_accessor, base)
self.send(sym, *args)
end
-
+
# Perform the given action
# +a+ is the action Symbol
# +c+ is the Condition
@@ -233,25 +233,25 @@ def method_missing(sym, *args)
def action(a, c = nil)
if Thread.current != self.driver.thread
# called from outside Driver
-
+
# send an async message to Driver
self.driver.message(:action, [a, c])
else
# called from within Driver
-
+
if self.respond_to?(a)
command = self.send(a)
-
+
case command
when String
msg = "#{self.name} #{a}: #{command}"
applog(self, :info, msg)
-
+
system(command)
when Proc
msg = "#{self.name} #{a}: lambda"
applog(self, :info, msg)
-
+
command.call
else
raise NotImplementedError
@@ -259,13 +259,13 @@ def action(a, c = nil)
end
end
end
-
+
###########################################################################
#
# Events
#
###########################################################################
-
+
def attach(condition)
case condition
when PollCondition
@@ -274,7 +274,7 @@ def attach(condition)
condition.register
end
end
-
+
def detach(condition)
case condition
when PollCondition
@@ -283,27 +283,27 @@ def detach(condition)
condition.deregister
end
end
-
+
###########################################################################
#
# Registration
#
###########################################################################
-
+
def register!
# override if necessary
end
-
+
def unregister!
# override if necessary
end
-
+
###########################################################################
#
# Handlers
#
###########################################################################
-
+
# Evaluate and handle the given poll condition. Handles logging
# notifications, and moving to the new state if necessary
# +condition+ is the Condition to handle
@@ -312,23 +312,23 @@ def unregister!
def handle_poll(condition)
# lookup metric
metric = self.directory[condition]
-
+
# run the test
result = condition.test
-
+
# log
messages = self.log_line(self, metric, condition, result)
-
+
# notify
if condition.notify && self.trigger?(metric, result)
self.notify(condition, messages.last)
end
-
+
# after-condition
condition.after
-
+
# get the destination
- dest =
+ dest =
if result && condition.transition
# condition override
condition.transition
@@ -336,7 +336,7 @@ def handle_poll(condition)
# regular
metric.destination && metric.destination[result]
end
-
+
# transition or reschedule
if dest
# transition
@@ -345,7 +345,7 @@ def handle_poll(condition)
rescue EventRegistrationFailedError
msg = self.name + ' Event registration failed, moving back to previous state'
applog(self, :info, msg)
-
+
dest = self.state
retry
end
@@ -354,7 +354,7 @@ def handle_poll(condition)
self.driver.schedule(condition)
end
end
-
+
# Asynchronously evaluate and handle the given event condition. Handles logging
# notifications, and moving to the new state if necessary
# +condition+ is the Condition to handle
@@ -363,17 +363,17 @@ def handle_poll(condition)
def handle_event(condition)
# lookup metric
metric = self.directory[condition]
-
+
# log
messages = self.log_line(self, metric, condition, true)
-
+
# notify
if condition.notify && self.trigger?(metric, true)
self.notify(condition, messages.last)
end
-
+
# get the destination
- dest =
+ dest =
if condition.transition
# condition override
condition.transition
@@ -381,12 +381,12 @@ def handle_event(condition)
# regular
metric.destination && metric.destination[true]
end
-
+
if dest
self.move(dest)
end
end
-
+
# Determine whether a trigger happened
# +metric+ is the Metric
# +result+ is the result from the condition's test
@@ -395,7 +395,7 @@ def handle_event(condition)
def trigger?(metric, result)
metric.destination && metric.destination[result]
end
-
+
# Log info about the condition and return the list of messages logged
# +watch+ is the Watch
# +metric+ is the Metric
@@ -404,15 +404,15 @@ def trigger?(metric, result)
#
# Returns String[]
def log_line(watch, metric, condition, result)
- status =
+ status =
if self.trigger?(metric, result)
"[trigger]"
else
"[ok]"
end
-
+
messages = []
-
+
# log info if available
if condition.info
Array(condition.info).each do |condition_info|
@@ -423,14 +423,14 @@ def log_line(watch, metric, condition, result)
messages << "#{watch.name} #{status} (#{condition.base_name})"
status == '[trigger]' ? applog(watch, :warn, messages.last) : applog(watch, :info, messages.last)
end
-
+
# log
debug_message = watch.name + ' ' + condition.base_name + " [#{result}] " + self.dest_desc(metric, condition)
applog(watch, :debug, debug_message)
-
+
messages
end
-
+
# Format the destination specification for use in debug logging
# +metric+ is the Metric
# +condition+ is the Condition
@@ -447,7 +447,7 @@ def dest_desc(metric, condition)
end
end
end
-
+
# Notify all recipeients of the given condition with the specified message
# +condition+ is the Condition
# +message+ is the String message to send
@@ -456,7 +456,7 @@ def dest_desc(metric, condition)
def notify(condition, message)
spec = Contact.normalize(condition.notify)
unmatched = []
-
+
# resolve contacts
resolved_contacts =
spec[:contacts].inject([]) do |acc, contact_name_or_group|
@@ -465,23 +465,23 @@ def notify(condition, message)
acc += cons
acc
end
-
+
# warn about unmatched contacts
unless unmatched.empty?
msg = "#{condition.watch.name} no matching contacts for '#{unmatched.join(", ")}'"
applog(condition.watch, :warn, msg)
end
-
+
# notify each contact
resolved_contacts.each do |c|
host = `hostname`.chomp rescue 'none'
c.notify(message, Time.now, spec[:priority], spec[:category], host)
-
+
msg = "#{condition.watch.name} #{c.info ? c.info : "notification sent for contact: #{c.name}"} (#{c.base_name})"
-
+
applog(condition.watch, :info, msg % [])
end
end
end
-
+
end
diff --git a/lib/god/timeline.rb b/lib/god/timeline.rb
index 4d021bd4..61f2f59e 100644
--- a/lib/god/timeline.rb
+++ b/lib/god/timeline.rb
@@ -1,5 +1,5 @@
module God
-
+
class Timeline < Array
# Instantiate a new Timeline
# +max_size+ is the maximum size to which the timeline should grow
@@ -9,7 +9,7 @@ def initialize(max_size)
super()
@max_size = max_size
end
-
+
# Push a value onto the Timeline
# +val+ is the value to push
#
@@ -18,8 +18,8 @@ def push(val)
self.concat([val])
shift if size > @max_size
end
-
+
alias_method :<<, :push
end
-
+
end
\ No newline at end of file
diff --git a/lib/god/trigger.rb b/lib/god/trigger.rb
index 0f022840..f753dc2b 100644
--- a/lib/god/trigger.rb
+++ b/lib/god/trigger.rb
@@ -1,43 +1,43 @@
module God
-
+
class Trigger
-
+
class << self
attr_accessor :triggers # {task.name => condition}
end
-
+
# init
self.triggers = {}
@mutex = Mutex.new
-
+
def self.register(condition)
@mutex.synchronize do
self.triggers[condition.watch.name] ||= []
self.triggers[condition.watch.name] << condition
end
end
-
+
def self.deregister(condition)
@mutex.synchronize do
self.triggers[condition.watch.name].delete(condition)
self.triggers.delete(condition.watch.name) if self.triggers[condition.watch.name].empty?
end
end
-
+
def self.broadcast(task, message, payload)
return unless self.triggers[task.name]
-
+
@mutex.synchronize do
self.triggers[task.name].each do |t|
t.process(message, payload)
end
end
end
-
+
def self.reset
self.triggers.clear
end
-
+
end
-
+
end
\ No newline at end of file
diff --git a/lib/god/watch.rb b/lib/god/watch.rb
index 34589cf4..ececbdd8 100644
--- a/lib/god/watch.rb
+++ b/lib/god/watch.rb
@@ -2,43 +2,43 @@
require 'forwardable'
module God
-
+
class Watch < Task
VALID_STATES = [:init, :up, :start, :restart]
INITIAL_STATE = :init
-
+
# config
attr_accessor :grace, :start_grace, :stop_grace, :restart_grace
-
+
extend Forwardable
def_delegators :@process, :name, :uid, :gid, :start, :stop, :restart,
:name=, :uid=, :gid=, :start=, :stop=, :restart=,
:pid_file, :pid_file=, :log, :log=, :alive?, :pid,
:unix_socket, :unix_socket=, :chroot, :chroot=, :env, :env=
- #
+ #
def initialize
super
-
+
@process = God::Process.new
-
+
# valid states
self.valid_states = VALID_STATES
self.initial_state = INITIAL_STATE
-
+
# no grace period by default
self.grace = self.start_grace = self.stop_grace = self.restart_grace = 0
end
-
+
def valid?
super && @process.valid?
end
-
+
###########################################################################
#
# Behavior
#
###########################################################################
-
+
def behavior(kind)
# create the behavior
begin
@@ -46,47 +46,47 @@ def behavior(kind)
rescue NoSuchBehaviorError => e
abort e.message
end
-
+
# send to block so config can set attributes
yield(b) if block_given?
-
+
# abort if the Behavior is invalid, the Behavior will have printed
# out its own error messages by now
abort unless b.valid?
-
+
self.behaviors << b
end
-
+
###########################################################################
#
# Simple mode
#
###########################################################################
-
+
def start_if
self.transition(:up, :start) do |on|
yield(on)
end
end
-
+
def restart_if
self.transition(:up, :restart) do |on|
yield(on)
end
end
-
- def stop_if
- self.transition(:up, :stop) do |on|
- yield(on)
- end
+
+ def stop_if
+ self.transition(:up, :stop) do |on|
+ yield(on)
+ end
end
-
+
###########################################################################
#
# Lifecycle
#
###########################################################################
-
+
# Enable monitoring
def monitor
# start monitoring at the first available of the init or up states
@@ -96,22 +96,22 @@ def monitor
self.move(:up)
end
end
-
+
###########################################################################
#
# Actions
#
###########################################################################
-
+
def action(a, c = nil)
if Thread.current != self.driver.thread
# called from outside Driver
-
+
# send an async message to Driver
self.driver.message(:action, [a, c])
else
# called from within Driver
-
+
case a
when :start
call_action(c, :start)
@@ -129,10 +129,10 @@ def action(a, c = nil)
sleep(self.stop_grace + self.grace)
end
end
-
+
self
end
-
+
def call_action(condition, action)
# before
before_items = self.behaviors
@@ -144,15 +144,15 @@ def call_action(condition, action)
applog(self, :info, msg)
end
end
-
+
# log
if self.send(action)
msg = "#{self.name} #{action}: #{self.send(action).to_s}"
applog(self, :info, msg)
end
-
+
@process.call_action(action)
-
+
# after
after_items = self.behaviors
after_items += [condition] if condition
@@ -164,20 +164,20 @@ def call_action(condition, action)
end
end
end
-
+
###########################################################################
#
# Registration
#
###########################################################################
-
+
def register!
God.registry.add(@process)
end
-
+
def unregister!
God.registry.remove(@process)
end
end
-
+
end
diff --git a/site/index.html b/site/index.html
index 7f991fd6..4f4657c1 100644
--- a/site/index.html
+++ b/site/index.html
@@ -46,18 +46,18 @@ Features
Easily control non-daemonizing scripts
-
+
Installation (v 0.7.3)
The best way to get god is via rubygems:
$ sudo gem install god
You can also peruse or clone the code from git://github.com/mojombo/god.git
-
+
Requirements
-
+
God currently only works on Linux (kernel 2.6.15+), BSD, and Darwin systems. No support for Windows is planned. Event based conditions on Linux systems require the cn (connector) kernel module loaded or compiled in to the kernel and god must be run as root.
-
+
The following systems have been tested. Help us test it on others!
-
+
- Darwin 10.4.10
- RedHat Fedora Core 6
@@ -68,9 +68,9 @@ Requirements
Finally, a Config File that Makes Sense
The easiest way to understand how god will make your life better is by looking at a sample config file. The following configuration file is what I use at gravatar.com to keep the mongrels running:
-
+
# run with: god -c /path/to/gravatar.god
-#
+#
# This is the actual config file used to keep the mongrels of
# gravatar.com running.
@@ -79,7 +79,7 @@ Finally, a Config File that Makes Sense
%w{8200 8201 8202}.each do |port|
God.watch do |w|
w.name = "gravatar2-mongrel-#{port}"
- w.interval = 30.seconds # default
+ w.interval = 30.seconds # default
w.start = "mongrel_rails start -c #{RAILS_ROOT} -p #{port} \
-P #{RAILS_ROOT}/log/mongrel.#{port}.pid -d"
w.stop = "mongrel_rails stop -P #{RAILS_ROOT}/log/mongrel.#{port}.pid"
@@ -87,7 +87,7 @@ Finally, a Config File that Makes Sense
w.start_grace = 10.seconds
w.restart_grace = 10.seconds
w.pid_file = File.join(RAILS_ROOT, "log/mongrel.#{port}.pid")
-
+
w.behavior(:clean_pid_file)
w.start_if do |start|
@@ -96,19 +96,19 @@ Finally, a Config File that Makes Sense
c.running = false
end
end
-
+
w.restart_if do |restart|
restart.condition(:memory_usage) do |c|
c.above = 150.megabytes
c.times = [3, 5] # 3 out of 5 intervals
end
-
+
restart.condition(:cpu_usage) do |c|
c.above = 50.percent
c.times = 5
end
end
-
+
# lifecycle
w.lifecycle do |on|
on.condition(:flapping) do |c|
@@ -138,7 +138,7 @@ Finally, a Config File that Makes Sense
God.watch do |w|
w.name = "gravatar2-mongrel-#{port}"
- w.interval = 30.seconds # default
+ w.interval = 30.seconds # default
w.start = "mongrel_rails start -c #{RAILS_ROOT} -p #{port} \
-P #{RAILS_ROOT}/log/mongrel.#{port}.pid -d"
w.stop = "mongrel_rails stop -P #{RAILS_ROOT}/log/mongrel.#{port}.pid"
@@ -146,14 +146,14 @@ Finally, a Config File that Makes Sense
w.start_grace = 10.seconds
w.restart_grace = 10.seconds
w.pid_file = File.join(RAILS_ROOT, "log/mongrel.#{port}.pid")
-
+
...
end
A watch represents a single process that has concrete start, stop, and/or restart operations. You can define as many watches as you like. In the example above, I've got some Rails instances running in Mongrels that I need to keep alive. Every watch must have a unique name so that it can be identified later on. The interval option sets the default poll interval (this can be overridden in each condition). The start and stop attributes specify the commands to start and stop the process. If no restart attribute is set, restart will be represented by a call to stop followed by a call to start. The optional grace attribute sets the amount of time following a start/stop/restart command to wait before resuming normal monitoring operations. To be more specific, I can set just start_grace, stop_grace, and/or restart_grace. If the process you're watching runs as a daemon (as mine does), you'll need to set the pid_file attribute.
w.behavior(:clean_pid_file)
-
+
Behaviors allow you to execute additional commands around start/stop/restart commands. In our case, if the process dies it will leave a PID file behind. The next time a start command is issued, it will fail, complaining about the leftover PID file. We'd like the PID file cleaned up before a start command is issued. The built-in behavior clean_pid_file will do just that.
w.start_if do |start|
@@ -162,8 +162,8 @@ Finally, a Config File that Makes Sense
c.running = false
end
end
-
-Watches contain conditions grouped by the action to execute should they return true. I start with a start_if block that contains a single condition. Conditions are specified by calling condition with an identifier, in this case
+
+
Watches contain conditions grouped by the action to execute should they return true. I start with a start_if block that contains a single condition. Conditions are specified by calling condition with an identifier, in this case
:process_running. Each condition can specify a poll interval that will override the default watch interval. In this case, I want to check that the process is still running every 5 seconds instead of the 30 second interval that other conditions will inherit. The ability to set condition specific poll intervals makes it possible to run critical tests (such as :process_running) more often than less critical tests (such as :memory_usage and :cpu_usage).
w.restart_if do |restart|
@@ -171,7 +171,7 @@ Finally, a Config File that Makes Sense
c.above = 150.megabytes
c.times = [3, 5] # 3 out of 5 intervals
end
-
+
...
end
@@ -179,13 +179,13 @@ Finally, a Config File that Makes Sense
w.restart_if do |restart|
...
-
+
restart.condition(:cpu_usage) do |c|
c.above = 50.percent
c.times = 5
end
end
-
+
To keep an eye on CPU usage, I've employed the cpu_usage condition. When CPU usage for a Mongrel process is over 50% for 5 consecutive intervals, it will be restarted.
w.lifecycle do |on|
@@ -199,9 +199,9 @@ Finally, a Config File that Makes Sense
c.retry_within = 2.hours
end
end
-
-Conditions inside a lifecycle section are active as long as the process is being monitored (they live across state changes).
-
+
+
Conditions inside a lifecycle section are active as long as the process is being monitored (they live across state changes).
+
The :flapping condition guards against the edge case wherein god rapidly starts or restarts your application. Things like server configuration changes or the unavailability of external services could make it impossible for my process to start. In that case, god will try to start my process over and over to no avail. The :flapping condition provides two levels of giving up on flapping processes. If I were to translate the options of the code above, it would be something like: If this watch is started or restarted five times withing 5 minutes, then unmonitor it...then after ten minutes, monitor it again to see if it was just a temporary problem; if the process is seen to be flapping five times within two hours, then give up completely.
That's it! Simple, huh?
@@ -214,13 +214,13 @@ Changing UID/GID for processes
God.watch do |w|
...
-
+
w.uid = 'tom'
w.gid = 'devs'
-
+
...
end
-
+
This only works for commands specified as a string. Lambda commands are unaffected.
@@ -232,9 +232,9 @@ Lambda commands
God.watch do |w|
...
-
+
w.start = lambda { ENV['APACHE'] ? `apachectl -k graceful` : `lighttpd restart` }
-
+
...
end
@@ -262,12 +262,12 @@ Grouping Watches
God.watch do |w|
...
-
+
w.group = 'mongrels'
-
+
...
end
-
+
The above configuration now allows you to control the watch (and any others that are in the group) with a single command:
$ sudo god stop mongrels
@@ -289,23 +289,23 @@ Advanced Configuration with Transitions and Events
w.stop = "mongrel_rails stop -P #{RAILS_ROOT}/log/mongrel.pid"
w.restart = "mongrel_rails restart -P #{RAILS_ROOT}/log/mongrel.pid"
w.pid_file = File.join(RAILS_ROOT, "log/mongrel.pid")
-
+
# clean pid files before start if necessary
w.behavior(:clean_pid_file)
-
+
# determine the state on startup
w.transition(:init, { true => :up, false => :start }) do |on|
on.condition(:process_running) do |c|
c.running = true
end
end
-
+
# determine when process has finished starting
w.transition([:start, :restart], :up) do |on|
on.condition(:process_running) do |c|
c.running = true
end
-
+
# failsafe
on.condition(:tries) do |c|
c.times = 5
@@ -317,7 +317,7 @@ Advanced Configuration with Transitions and Events
w.transition(:up, :start) do |on|
on.condition(:process_exits)
end
-
+
# restart if memory or cpu is too high
w.transition(:up, :restart) do |on|
on.condition(:memory_usage) do |c|
@@ -325,14 +325,14 @@ Advanced Configuration with Transitions and Events
c.above = 50.megabytes
c.times = [3, 5]
end
-
+
on.condition(:cpu_usage) do |c|
c.interval = 10
c.above = 10.percent
c.times = [3, 5]
end
end
-
+
# lifecycle
w.lifecycle do |on|
on.condition(:flapping) do |c|
@@ -351,7 +351,7 @@ Advanced Configuration with Transitions and Events
A bit longer, I know, but very straighforward once you understand how the transition calls work. The name, interval, start, stop, and pid_file attributes should be familiar. We also specify the clean_pid_file behavior.
Before jumping into the code, it's important to understand the different states that a Watch can have, and how that state changes over time. At any given time, a Watch will be in one of the init, up, start, or restart states. As different conditions are satisfied, the Watch will progress from state to state, enabling and disabling conditions along the way.
-
+
When god first starts, each Watch is placed in the init state.
You'll use the transition method to tell god how to transition between states. It takes two arguments. The first argument may be either a symbol or an array of symbols representing the state or states during which the specified conditions should be enabled. The second argument may be either a symbol or a hash. If it is a symbol, then that is the state that will be transitioned to if any of the conditions return true. If it is a hash, then that hash must have both true and false keys, each of which point to a symbol that represents the state to transition to given the corresponding return from the single condition that must be specified.
@@ -370,7 +370,7 @@ Advanced Configuration with Transitions and Events
on.condition(:process_running) do |c|
c.running = true
end
-
+
...
end
@@ -379,7 +379,7 @@ Advanced Configuration with Transitions and Events
# determine when process has finished starting
w.transition([:start, :restart], :up) do |on|
...
-
+
# failsafe
on.condition(:tries) do |c|
c.times = 5
@@ -403,7 +403,7 @@ Advanced Configuration with Transitions and Events
c.above = 50.megabytes
c.times = [3, 5]
end
-
+
on.condition(:cpu_usage) do |c|
c.interval = 10
c.above = 10.percent
@@ -516,15 +516,15 @@ Notifications
c.notify = 'tom'
end
end
-
+
There are two ways to specify that a notification should be sent. The first, easier way is shown above. Every condition can take an optional notify attribute that specifies which contacts should be notified when the condition is triggered. The value can be a contact name or contact group *or* an array of contact names and/or contact groups.
-
+
w.transition(:up, :start) do |on|
on.condition(:process_exits) do |c|
c.notify = {:contacts => ['tom', 'developers'], :priority => 1, :category => 'product'}
end
end
-
+
The second way allows you to specify the priority and category in addition to the contacts. The extra attributes can be arbitrary integers or strings and will be passed as-is to the notification subsystem.
The above notification will arrive as an email similar to the following.
diff --git a/test/configs/child_events/child_events.god b/test/configs/child_events/child_events.god
index d946affa..3d3d9627 100644
--- a/test/configs/child_events/child_events.god
+++ b/test/configs/child_events/child_events.god
@@ -3,20 +3,20 @@ God.watch do |w|
w.interval = 5.seconds
w.start = File.join(GOD_ROOT, *%w[test configs child_events simple_server.rb])
# w.log = File.join(GOD_ROOT, *%w[test configs child_events god.log])
-
+
# determine the state on startup
w.transition(:init, { true => :up, false => :start }) do |on|
on.condition(:process_running) do |c|
c.running = true
end
end
-
+
# determine when process has finished starting
w.transition([:start, :restart], :up) do |on|
on.condition(:process_running) do |c|
c.running = true
end
-
+
# failsafe
on.condition(:tries) do |c|
c.times = 2
@@ -28,7 +28,7 @@ God.watch do |w|
w.transition(:up, :start) do |on|
on.condition(:process_exits)
end
-
+
# lifecycle
w.lifecycle do |on|
on.condition(:flapping) do |c|
diff --git a/test/configs/child_polls/child_polls.god b/test/configs/child_polls/child_polls.god
index c563ad4b..5b032c49 100644
--- a/test/configs/child_polls/child_polls.god
+++ b/test/configs/child_polls/child_polls.god
@@ -3,25 +3,25 @@ God.watch do |w|
w.start = File.join(GOD_ROOT, *%w[test configs child_polls simple_server.rb])
w.interval = 5
w.grace = 2
-
+
w.start_if do |start|
start.condition(:process_running) do |c|
c.running = false
end
end
-
+
w.restart_if do |restart|
restart.condition(:cpu_usage) do |c|
c.above = 30.percent
c.times = [3, 5]
end
-
+
restart.condition(:memory_usage) do |c|
c.above = 10.megabytes
c.times = [3, 5]
end
end
-
+
# lifecycle
w.lifecycle do |on|
on.condition(:flapping) do |c|
diff --git a/test/configs/complex/complex.god b/test/configs/complex/complex.god
index d03d6358..f20ac7bc 100644
--- a/test/configs/complex/complex.god
+++ b/test/configs/complex/complex.god
@@ -3,20 +3,20 @@ God.watch do |w|
w.interval = 5.seconds
w.start = File.join(GOD_ROOT, *%w[test configs complex simple_server.rb])
# w.log = File.join(GOD_ROOT, *%w[test configs child_events god.log])
-
+
# determine the state on startup
w.transition(:init, { true => :up, false => :start }) do |on|
on.condition(:process_running) do |c|
c.running = true
end
end
-
+
# determine when process has finished starting
w.transition([:start, :restart], :up) do |on|
on.condition(:process_running) do |c|
c.running = true
end
-
+
# failsafe
on.condition(:tries) do |c|
c.times = 2
@@ -28,7 +28,7 @@ God.watch do |w|
w.transition(:up, :start) do |on|
on.condition(:process_exits)
end
-
+
# restart if process is misbehaving
w.transition(:up, :restart) do |on|
on.condition(:complex) do |cc|
@@ -36,14 +36,14 @@ God.watch do |w|
c.above = 0.percent
c.times = 1
end
-
+
cc.and(:memory_usage) do |c|
c.above = 0.megabytes
c.times = 3
end
end
end
-
+
# lifecycle
w.lifecycle do |on|
on.condition(:flapping) do |c|
diff --git a/test/configs/contact/contact.god b/test/configs/contact/contact.god
index da76deec..df5c5891 100644
--- a/test/configs/contact/contact.god
+++ b/test/configs/contact/contact.god
@@ -31,20 +31,20 @@ God.watch do |w|
w.uid = 'tom'
w.gid = 'tom'
w.log = "/Users/tom/contact.log"
-
+
# determine the state on startup
w.transition(:init, { true => :up, false => :start }) do |on|
on.condition(:process_running) do |c|
c.running = true
end
end
-
+
# determine when process has finished starting
w.transition([:start, :restart], :up) do |on|
on.condition(:process_running) do |c|
c.running = true
end
-
+
# failsafe
on.condition(:tries) do |c|
c.times = 2
@@ -58,7 +58,7 @@ God.watch do |w|
c.notify = {:contacts => ['tom', 'foobar'], :priority => 1, :category => 'product'}
end
end
-
+
# lifecycle
w.lifecycle do |on|
on.condition(:flapping) do |c|
diff --git a/test/configs/daemon_events/daemon_events.god b/test/configs/daemon_events/daemon_events.god
index 3a91f980..7d34698b 100644
--- a/test/configs/daemon_events/daemon_events.god
+++ b/test/configs/daemon_events/daemon_events.god
@@ -7,22 +7,22 @@ God.watch do |w|
w.log = File.join(File.dirname(__FILE__), 'daemon_events.log')
w.uid = 'tom'
w.gid = 'tom'
-
+
w.behavior(:clean_pid_file)
-
+
# determine the state on startup
w.transition(:init, { true => :up, false => :start }) do |on|
on.condition(:process_running) do |c|
c.running = true
end
end
-
+
# determine when process has finished starting
w.transition([:start, :restart], :up) do |on|
on.condition(:process_running) do |c|
c.running = true
end
-
+
# failsafe
on.condition(:tries) do |c|
c.times = 2
diff --git a/test/configs/daemon_polls/daemon_polls.god b/test/configs/daemon_polls/daemon_polls.god
index c770042a..af1daccf 100644
--- a/test/configs/daemon_polls/daemon_polls.god
+++ b/test/configs/daemon_polls/daemon_polls.god
@@ -6,9 +6,9 @@ God.watch do |w|
w.pid_file = '/var/run/daemon-polls.pid'
w.start_grace = 2.seconds
w.log = File.join(File.dirname(__FILE__), *%w[out.log])
-
+
w.behavior(:clean_pid_file)
-
+
w.start_if do |start|
start.condition(:process_running) do |c|
c.running = false
diff --git a/test/configs/degrading_lambda/degrading_lambda.god b/test/configs/degrading_lambda/degrading_lambda.god
index 87dd2a37..33e37951 100644
--- a/test/configs/degrading_lambda/degrading_lambda.god
+++ b/test/configs/degrading_lambda/degrading_lambda.god
@@ -4,13 +4,13 @@ God.watch do |w|
w.interval = 5
w.grace = 2
w.group = 'test'
-
+
w.start_if do |start|
start.condition(:process_running) do |c|
c.running = false
end
end
-
+
w.restart_if do |restart|
restart.condition(:degrading_lambda) do |c|
require 'socket'
diff --git a/test/configs/matias/matias.god b/test/configs/matias/matias.god
index fd0ba0dd..737cc85c 100644
--- a/test/configs/matias/matias.god
+++ b/test/configs/matias/matias.god
@@ -5,7 +5,7 @@ God.task do |w|
w.interval = 5.seconds
w.valid_states = [:init, :up, :down]
w.initial_state = :init
-
+
# determine the state on startup
w.transition(:init, { true => :up, false => :down }) do |on|
on.condition(:process_running) do |c|
@@ -13,7 +13,7 @@ God.task do |w|
c.pid_file = $pid_file
end
end
-
+
# when process is up
w.transition(:up, :down) do |on|
# transition to 'start' if process goes down
@@ -21,7 +21,7 @@ God.task do |w|
c.running = false
c.pid_file = $pid_file
end
-
+
# send up info
on.condition(:lambda) do |c|
c.lambda = lambda do
@@ -30,7 +30,7 @@ God.task do |w|
end
end
end
-
+
# when process is down
w.transition(:down, :up) do |on|
# transition to 'up' if process comes up
@@ -38,7 +38,7 @@ God.task do |w|
c.running = true
c.pid_file = $pid_file
end
-
+
# send down info
on.condition(:lambda) do |c|
c.lambda = lambda do
diff --git a/test/configs/real.rb b/test/configs/real.rb
index 1beaad70..457d5758 100644
--- a/test/configs/real.rb
+++ b/test/configs/real.rb
@@ -10,14 +10,14 @@
w.start = "mongrel_rails start -P ./log/mongrel.pid -c #{RAILS_ROOT} -d"
w.stop = "mongrel_rails stop -P ./log/mongrel.pid -c #{RAILS_ROOT}"
w.grace = 5
-
+
pid_file = File.join(RAILS_ROOT, "log/mongrel.pid")
-
+
# clean pid files before start if necessary
w.behavior(:clean_pid_file) do |b|
b.pid_file = pid_file
end
-
+
# start if process is not running
w.start_if do |start|
start.condition(:process_running) do |c|
@@ -25,7 +25,7 @@
c.pid_file = pid_file
end
end
-
+
# restart if memory or cpu is too high
w.restart_if do |restart|
restart.condition(:memory_usage) do |c|
@@ -34,7 +34,7 @@
c.above = (50 * 1024) # 50mb
c.times = [3, 5]
end
-
+
restart.condition(:cpu_usage) do |c|
c.interval = 10
c.pid_file = pid_file
@@ -52,7 +52,7 @@
# File.mtime(f) < Time.now - (7 * 24 * 60 * 60)
# end.each { |f| File.delete(f) }
# end
-#
+#
# w.start_if do |start|
# start.condition(:always)
# end
diff --git a/test/configs/running_load/running_load.god b/test/configs/running_load/running_load.god
index 6bc70fb9..e62b9bfd 100644
--- a/test/configs/running_load/running_load.god
+++ b/test/configs/running_load/running_load.god
@@ -7,7 +7,7 @@ God.watch do |w|
w.uid = 'tom'
w.gid = 'tom'
w.group = 'test'
-
+
w.start_if do |start|
start.condition(:process_running) do |c|
c.running = false
diff --git a/test/configs/stress/stress.god b/test/configs/stress/stress.god
index f140053f..e55564b9 100644
--- a/test/configs/stress/stress.god
+++ b/test/configs/stress/stress.god
@@ -5,7 +5,7 @@
w.interval = 0
w.grace = 2
w.group = 'test'
-
+
w.start_if do |start|
start.condition(:process_running) do |c|
c.running = false
diff --git a/test/configs/task/task.god b/test/configs/task/task.god
index eb81eaa3..fbf6cc19 100644
--- a/test/configs/task/task.god
+++ b/test/configs/task/task.god
@@ -5,17 +5,17 @@ God.task do |t|
t.valid_states = [:ok, :clean]
t.initial_state = :ok
t.interval = 5
-
+
# t.clean = lambda do
# Dir[File.join(LOG_DIR, '*.log')].each do |f|
# File.delete(f)
# end
# end
-
+
t.clean = "rm #{File.join(LOG_DIR, '*.log')}"
-
+
t.transition(:clean, :ok)
-
+
t.transition(:ok, :clean) do |on|
on.condition(:lambda) do |c|
c.lambda = lambda do
diff --git a/test/configs/test.rb b/test/configs/test.rb
index 00cdcb27..1b786181 100644
--- a/test/configs/test.rb
+++ b/test/configs/test.rb
@@ -12,17 +12,17 @@
w.stop = "mongrel_rails stop -P ./log/mongrel.pid -c #{RAILS_ROOT}"
w.group = 'mongrels'
w.pid_file = File.join(RAILS_ROOT, "log/mongrel.pid")
-
+
# clean pid files before start if necessary
w.behavior(:clean_pid_file)
-
+
# determine the state on startup
w.transition(:init, { true => :up, false => :start }) do |on|
on.condition(:process_running) do |c|
c.running = true
end
end
-
+
# determine when process has finished starting
w.transition([:start, :restart], :up) do |on|
on.condition(:process_running) do |c|
@@ -34,7 +34,7 @@
w.transition(:up, :start) do |on|
on.condition(:process_exits)
end
-
+
# restart if memory or cpu is too high
w.transition(:up, :restart) do |on|
on.condition(:memory_usage) do |c|
@@ -42,13 +42,13 @@
c.above = 50.megabytes
c.times = [3, 5]
end
-
+
on.condition(:cpu_usage) do |c|
c.interval = 1
c.above = 10.percent
c.times = [3, 5]
end
-
+
on.condition(:http_response_code) do |c|
c.host = 'localhost'
c.port = port
diff --git a/test/helper.rb b/test/helper.rb
index 078669f0..9a8cd676 100644
--- a/test/helper.rb
+++ b/test/helper.rb
@@ -37,13 +37,13 @@ def test
true
end
end
-
+
class FakePollCondition < PollCondition
def test
true
end
end
-
+
class FakeEventCondition < EventCondition
def register
end
@@ -51,7 +51,7 @@ def deregister
end
end
end
-
+
module Behaviors
class FakeBehavior < Behavior
def before_start
@@ -62,15 +62,15 @@ def after_start
end
end
end
-
+
module Contacts
class FakeContact < Contact
end
-
+
class InvalidContact
end
end
-
+
def self.reset
self.watches = nil
self.groups = nil
@@ -139,7 +139,7 @@ class Bypass
def initialize(ref)
@ref = ref
end
-
+
def method_missing(sym, *args)
@ref.__send__(sym, *args)
end
diff --git a/test/test_behavior.rb b/test/test_behavior.rb
index 50de69c6..3210a46f 100644
--- a/test/test_behavior.rb
+++ b/test/test_behavior.rb
@@ -4,13 +4,13 @@ class TestBehavior < Test::Unit::TestCase
def test_generate_should_return_an_object_corresponding_to_the_given_type
assert_equal Behaviors::FakeBehavior, Behavior.generate(:fake_behavior, nil).class
end
-
+
def test_generate_should_raise_on_invalid_type
assert_raise NoSuchBehaviorError do
Behavior.generate(:foo, nil)
end
end
-
+
def test_complain
Syslog.expects(:err).with('foo')
# Kernel.expects(:puts).with('foo')
diff --git a/test/test_condition.rb b/test/test_condition.rb
index 712a7c33..e0ff9c6a 100644
--- a/test/test_condition.rb
+++ b/test/test_condition.rb
@@ -4,19 +4,19 @@ class BadlyImplementedCondition < PollCondition
end
class TestCondition < Test::Unit::TestCase
-
+
# generate
-
+
def test_generate_should_return_an_object_corresponding_to_the_given_type
assert_equal Conditions::ProcessRunning, Condition.generate(:process_running, nil).class
end
-
+
def test_generate_should_raise_on_invalid_type
assert_raise NoSuchConditionError do
Condition.generate(:foo, nil)
end
end
-
+
def test_generate_should_abort_on_event_condition_without_loaded_event_system
God::EventHandler.stubs(:operational?).returns(false)
assert_abort do
@@ -24,25 +24,25 @@ def test_generate_should_abort_on_event_condition_without_loaded_event_system
Condition.generate(:process_exits, nil).class
end
end
-
+
def test_generate_should_return_a_good_error_message_for_invalid_types
emsg = "No Condition found with the class name God::Conditions::FooBar"
rmsg = nil
-
+
begin
Condition.generate(:foo_bar, nil)
rescue => e
rmsg = e.message
end
-
+
assert_equal emsg, rmsg
end
-
+
# test
-
+
def test_test_should_raise_if_not_defined_in_subclass
c = BadlyImplementedCondition.new
-
+
assert_raise AbstractMethodNotOverriddenError do
c.test
end
diff --git a/test/test_conditions_disk_usage.rb b/test/test_conditions_disk_usage.rb
index 0e43e28e..cece0e65 100644
--- a/test/test_conditions_disk_usage.rb
+++ b/test/test_conditions_disk_usage.rb
@@ -2,55 +2,55 @@
class TestConditionsDiskUsage < Test::Unit::TestCase
# valid?
-
+
def test_valid_should_return_false_if_no_above_given
c = Conditions::DiskUsage.new
c.mount_point = '/'
c.watch = stub(:name => 'foo')
-
+
no_stdout do
assert_equal false, c.valid?
end
end
-
+
def test_valid_should_return_false_if_no_mount_point_given
c = Conditions::DiskUsage.new
c.above = 90
c.watch = stub(:name => 'foo')
-
+
no_stdout do
assert_equal false, c.valid?
end
end
-
+
def test_valid_should_return_true_if_required_options_all_set
c = Conditions::DiskUsage.new
c.above = 90
c.mount_point = '/'
c.watch = stub(:name => 'foo')
-
+
assert_equal true, c.valid?
end
-
+
# test
-
+
def test_test_should_return_true_if_above_limit
c = Conditions::DiskUsage.new
c.above = 90
c.mount_point = '/'
-
+
c.expects(:`).returns('91')
-
+
assert_equal true, c.test
end
-
+
def test_test_should_return_false_if_below_limit
c = Conditions::DiskUsage.new
c.above = 90
c.mount_point = '/'
-
+
c.expects(:`).returns('90')
-
+
assert_equal false, c.test
end
end
\ No newline at end of file
diff --git a/test/test_conditions_http_response_code.rb b/test/test_conditions_http_response_code.rb
index 47eecbad..81a463ce 100644
--- a/test/test_conditions_http_response_code.rb
+++ b/test/test_conditions_http_response_code.rb
@@ -14,36 +14,36 @@ def valid_condition
c.prepare
c
end
-
+
# valid?
-
+
def test_valid_condition_is_valid
c = valid_condition
assert c.valid?
end
-
+
def test_valid_should_return_false_if_both_code_is_and_code_is_not_are_set
c = valid_condition do |cc|
cc.code_is_not = 500
end
no_stdout { assert !c.valid? }
end
-
+
def test_valid_should_return_false_if_no_host_set
c = valid_condition do |cc|
cc.host = nil
end
no_stdout { assert !c.valid? }
end
-
+
# test
-
+
def test_test_should_return_false_if_code_is_is_set_to_200_but_response_is_500
c = valid_condition
Net::HTTP.expects(:start).yields(stub(:read_timeout= => nil, :get => stub(:code => 500)))
assert_equal false, c.test
end
-
+
def test_test_should_return_false_if_code_is_not_is_set_to_200_and_response_is_200
c = valid_condition do |cc|
cc.code_is = nil
@@ -52,13 +52,13 @@ def test_test_should_return_false_if_code_is_not_is_set_to_200_and_response_is_2
Net::HTTP.expects(:start).yields(stub(:read_timeout= => nil, :get => stub(:code => 200)))
assert_equal false, c.test
end
-
+
def test_test_should_return_true_if_code_is_is_set_to_200_and_response_is_200
c = valid_condition
Net::HTTP.expects(:start).yields(stub(:read_timeout= => nil, :get => stub(:code => 200)))
assert_equal true, c.test
end
-
+
def test_test_should_return_false_if_code_is_not_is_set_to_200_but_response_is_500
c = valid_condition do |cc|
cc.code_is = nil
@@ -67,13 +67,13 @@ def test_test_should_return_false_if_code_is_not_is_set_to_200_but_response_is_5
Net::HTTP.expects(:start).yields(stub(:read_timeout= => nil, :get => stub(:code => 500)))
assert_equal true, c.test
end
-
+
def test_test_should_return_false_if_code_is_is_set_to_200_but_response_times_out
c = valid_condition
Net::HTTP.expects(:start).raises(Timeout::Error, '')
assert_equal false, c.test
end
-
+
def test_test_should_return_true_if_code_is_not_is_set_to_200_and_response_times_out
c = valid_condition do |cc|
cc.code_is = nil
@@ -82,13 +82,13 @@ def test_test_should_return_true_if_code_is_not_is_set_to_200_and_response_times
Net::HTTP.expects(:start).raises(Timeout::Error, '')
assert_equal true, c.test
end
-
+
def test_test_should_return_false_if_code_is_is_set_to_200_but_cant_connect
c = valid_condition
Net::HTTP.expects(:start).raises(Errno::ECONNREFUSED, '')
assert_equal false, c.test
end
-
+
def test_test_should_return_true_if_code_is_not_is_set_to_200_and_cant_connect
c = valid_condition do |cc|
cc.code_is = nil
@@ -97,7 +97,7 @@ def test_test_should_return_true_if_code_is_not_is_set_to_200_and_cant_connect
Net::HTTP.expects(:start).raises(Errno::ECONNREFUSED, '')
assert_equal true, c.test
end
-
+
def test_test_should_return_true_if_code_is_is_set_to_200_and_response_is_200_twice_for_times_two_of_two
c = valid_condition do |cc|
cc.times = [2, 2]
diff --git a/test/test_conditions_process_running.rb b/test/test_conditions_process_running.rb
index c0b709d7..c1d5d709 100644
--- a/test/test_conditions_process_running.rb
+++ b/test/test_conditions_process_running.rb
@@ -5,39 +5,39 @@ def test_missing_pid_file_returns_opposite
[true, false].each do |r|
c = Conditions::ProcessRunning.new
c.running = r
-
+
c.stubs(:watch).returns(stub(:pid => 123, :name => 'foo'))
-
+
# no_stdout do
assert_equal !r, c.test
# end
end
end
-
+
def test_not_running_returns_opposite
[true, false].each do |r|
c = Conditions::ProcessRunning.new
c.running = r
-
+
File.stubs(:exist?).returns(true)
c.stubs(:watch).returns(stub(:pid => 123))
File.stubs(:read).returns('5')
System::Process.any_instance.stubs(:exists?).returns(false)
-
+
assert_equal !r, c.test
end
end
-
+
def test_running_returns_same
[true, false].each do |r|
c = Conditions::ProcessRunning.new
c.running = r
-
+
File.stubs(:exist?).returns(true)
c.stubs(:watch).returns(stub(:pid => 123))
File.stubs(:read).returns('5')
System::Process.any_instance.stubs(:exists?).returns(true)
-
+
assert_equal r, c.test
end
end
diff --git a/test/test_conditions_tries.rb b/test/test_conditions_tries.rb
index 0b1fc2c4..15d4287b 100644
--- a/test/test_conditions_tries.rb
+++ b/test/test_conditions_tries.rb
@@ -2,7 +2,7 @@
class TestConditionsTries < Test::Unit::TestCase
# valid?
-
+
def test_valid_should_return_false_if_times_not_set
c = Conditions::Tries.new
c.watch = stub(:name => 'foo')
@@ -17,23 +17,23 @@ def setup
@c.times = 3
@c.prepare
end
-
+
# prepare
-
+
def test_prepare_should_create_timeline
assert 3, @c.instance_variable_get(:@timeline).instance_variable_get(:@max_size)
end
-
+
# test
-
+
def test_test_should_return_true_if_called_three_times_within_one_second
assert !@c.test
assert !@c.test
assert @c.test
end
-
+
# reset
-
+
def test_test_should_return_false_on_fourth_call_if_called_three_times_within_one_second
3.times { @c.test }
@c.reset
@@ -49,15 +49,15 @@ def setup
@c.within = 1.seconds
@c.prepare
end
-
+
# test
-
+
def test_test_should_return_true_if_called_three_times_within_one_second
assert !@c.test
assert !@c.test
assert @c.test
end
-
+
def test_test_should_return_false_if_called_three_times_within_two_seconds
assert !@c.test
assert !@c.test
diff --git a/test/test_contact.rb b/test/test_contact.rb
index 1d4427f2..3a28736a 100644
--- a/test/test_contact.rb
+++ b/test/test_contact.rb
@@ -4,103 +4,103 @@ class TestContact < Test::Unit::TestCase
def test_exists
God::Contact
end
-
+
# generate
-
+
def test_generate_should_raise_on_invalid_kind
assert_raise(NoSuchContactError) do
Contact.generate(:invalid)
end
end
-
+
def test_generate_should_abort_on_invalid_contact
assert_abort do
Contact.generate(:invalid_contact)
end
end
-
+
# normalize
-
+
def test_normalize_should_accept_a_string
input = 'tom'
output = {:contacts => ['tom']}
assert_equal(output, Contact.normalize(input))
end
-
+
def test_normalize_should_accept_an_array_of_strings
input = ['tom', 'kevin']
output = {:contacts => ['tom', 'kevin']}
assert_equal(output, Contact.normalize(input))
end
-
+
def test_normalize_should_accept_a_hash_with_contacts_string
input = {:contacts => 'tom'}
output = {:contacts => ['tom']}
assert_equal(output, Contact.normalize(input))
end
-
+
def test_normalize_should_accept_a_hash_with_contacts_array_of_strings
input = {:contacts => ['tom', 'kevin']}
output = {:contacts => ['tom', 'kevin']}
assert_equal(output, Contact.normalize(input))
end
-
+
def test_normalize_should_stringify_priority
input = {:contacts => 'tom', :priority => 1}
output = {:contacts => ['tom'], :priority => '1'}
assert_equal(output, Contact.normalize(input))
end
-
+
def test_normalize_should_stringify_category
input = {:contacts => 'tom', :category => :product}
output = {:contacts => ['tom'], :category => 'product'}
assert_equal(output, Contact.normalize(input))
end
-
+
def test_normalize_should_raise_on_non_string_array_hash
input = 1
assert_raise ArgumentError do
Contact.normalize(input)
end
end
-
+
def test_normalize_should_raise_on_non_string_array_contacts_key
input = {:contacts => 1}
assert_raise ArgumentError do
Contact.normalize(input)
end
end
-
+
def test_normalize_should_raise_on_non_string_containing_array
input = [1]
assert_raise ArgumentError do
Contact.normalize(input)
end
end
-
+
def test_normalize_should_raise_on_non_string_containing_array_contacts_key
input = {:contacts => [1]}
assert_raise ArgumentError do
Contact.normalize(input)
end
end
-
+
def test_normalize_should_raise_on_absent_contacts_key
input = {}
assert_raise ArgumentError do
Contact.normalize(input)
end
end
-
+
def test_normalize_should_raise_on_extra_keys
input = {:contacts => ['tom'], :priority => 1, :category => 'product', :extra => 'foo'}
assert_raise ArgumentError do
Contact.normalize(input)
end
end
-
+
# notify
-
+
def test_notify_should_be_abstract
assert_raise(AbstractMethodNotOverriddenError) do
Contact.new.notify(:a, :b, :c, :d, :e)
diff --git a/test/test_dependency_graph.rb b/test/test_dependency_graph.rb
index 0f5cab98..8c688f52 100644
--- a/test/test_dependency_graph.rb
+++ b/test/test_dependency_graph.rb
@@ -4,32 +4,32 @@ class TestDependencyGraph < Test::Unit::TestCase
def setup
@dg = DependencyGraph.new
end
-
+
# new
-
+
def test_new_should_accept_zero_arguments
assert @dg.instance_of?(DependencyGraph)
end
-
+
# add
-
+
def test_add_should_create_and_store_two_new_nodes
@dg.add('foo', 'bar')
assert_equal 2, @dg.nodes.size
assert @dg.nodes['foo'].instance_of?(DependencyGraph::Node)
assert @dg.nodes['bar'].instance_of?(DependencyGraph::Node)
end
-
+
def test_add_should_record_dependency
@dg.add('foo', 'bar')
assert_equal 1, @dg.nodes['foo'].dependencies.size
assert_equal @dg.nodes['bar'], @dg.nodes['foo'].dependencies.first
end
-
+
def test_add_should_ignore_dups
@dg.add('foo', 'bar')
@dg.add('foo', 'bar')
- assert_equal 2, @dg.nodes.size
+ assert_equal 2, @dg.nodes.size
assert_equal 1, @dg.nodes['foo'].dependencies.size
end
end
@@ -40,22 +40,22 @@ def setup
@foo = DependencyGraph::Node.new('foo')
@bar = DependencyGraph::Node.new('bar')
end
-
+
# new
-
+
def test_new_should_accept_zero_arguments
assert @foo.instance_of?(DependencyGraph::Node)
end
-
+
# add
-
+
def test_add_should_store_node_as_dependency
@foo.add(@bar)
assert_equal 1, @foo.dependencies.size
end
-
+
# has_node?
-
+
def test_has_node
assert @foo.has_node?(@foo)
end
diff --git a/test/test_driver.rb b/test/test_driver.rb
index 44584b46..f0fbd940 100644
--- a/test/test_driver.rb
+++ b/test/test_driver.rb
@@ -2,10 +2,10 @@
class TestDriver < Test::Unit::TestCase
def setup
-
+
end
def test_
-
+
end
end
diff --git a/test/test_email.rb b/test/test_email.rb
index 7378fb41..87badc37 100644
--- a/test/test_email.rb
+++ b/test/test_email.rb
@@ -11,7 +11,7 @@ def test_unknown_delivery_method_for_notify
God::Contacts::Email.any_instance.expects(:notify_sendmail).never
God::Contacts::Email.delivery_method = :foo_protocol
LOG.expects(:log).times(2)
-
+
g = God::Contacts::Email.new
g.notify(:a, :b, :c, :d, :e)
assert_nil g.info
@@ -29,7 +29,7 @@ def test_smtp_delivery_method_for_notify
assert_equal "sent email to joe@example.com", g.info
end
end
-
+
def test_sendmail_delivery_method_for_notify
assert_nothing_raised do
God::Contacts::Email.any_instance.expects(:notify_smtp).never
@@ -41,5 +41,5 @@ def test_sendmail_delivery_method_for_notify
assert_equal "sent email to joe@example.com", g.info
end
end
-
+
end
diff --git a/test/test_event_handler.rb b/test/test_event_handler.rb
index 50adecc2..c86d3fa9 100644
--- a/test/test_event_handler.rb
+++ b/test/test_event_handler.rb
@@ -2,15 +2,15 @@
module God
class EventHandler
-
+
def self.actions=(value)
@@actions = value
end
-
+
def self.actions
@@actions
end
-
+
def self.handler=(value)
@@handler = value
end
@@ -21,40 +21,40 @@ class TestEventHandler < Test::Unit::TestCase
def setup
@h = God::EventHandler
end
-
+
def test_register_one_event
pid = 4445
event = :proc_exit
block = lambda {
puts "Hi"
}
-
+
mock_handler = mock()
mock_handler.expects(:register_process).with(pid, [event])
@h.handler = mock_handler
-
+
@h.register(pid, event, &block)
assert_equal @h.actions, {pid => {event => block}}
end
-
+
def test_register_multiple_events_per_process
pid = 4445
exit_block = lambda { puts "Hi" }
@h.actions = {pid => {:proc_exit => exit_block}}
-
+
mock_handler = mock()
mock_handler.expects(:register_process).with do |a, b|
a == pid &&
b.to_set == [:proc_exit, :proc_fork].to_set
end
@h.handler = mock_handler
-
+
fork_block = lambda { puts "Forking" }
@h.register(pid, :proc_fork, &fork_block)
assert_equal @h.actions, {pid => {:proc_exit => exit_block,
:proc_fork => fork_block }}
end
-
+
# JIRA PLATFORM-75
def test_call_should_check_for_pid_and_action_before_executing
exit_block = mock()
@@ -64,7 +64,7 @@ def test_call_should_check_for_pid_and_action_before_executing
@h.call(4445, :proc_fork) # shouldn't call, bad event
@h.call(4445, :proc_exit) # should call
end
-
+
def teardown
# Reset handler
@h.actions = {}
diff --git a/test/test_god.rb b/test/test_god.rb
index 1fe669c8..44d3bac4 100644
--- a/test/test_god.rb
+++ b/test/test_god.rb
@@ -9,7 +9,7 @@ def setup
God.reset
God.pid_file_directory = '/var/run/god'
end
-
+
def teardown
God.main && God.main.kill
if God.watches
@@ -18,46 +18,46 @@ def teardown
end
end
end
-
+
# applog
-
+
def test_applog
LOG.expects(:log).with(nil, :debug, 'foo')
applog(nil, :debug, 'foo')
end
-
+
# internal_init
-
+
def test_init_should_initialize_watches_to_empty_array
God.internal_init { }
assert_equal Hash.new, God.watches
end
-
+
# init
-
+
def test_pid_file_directory_should_abort_if_called_after_watch
God.watch { |w| w.name = 'foo'; w.start = 'bar' }
-
+
assert_abort do
God.pid_file_directory = 'foo'
end
end
-
+
# pid_file_directory
-
+
def test_pid_file_directory_should_return_default_if_not_set_explicitly
God.internal_init
assert_equal '/var/run/god', God.pid_file_directory
end
-
+
def test_pid_file_directory_equals_should_set
God.pid_file_directory = '/foo'
God.internal_init
assert_equal '/foo', God.pid_file_directory
end
-
+
# watch
-
+
def test_watch_should_get_stored
watch = nil
God.watch do |w|
@@ -65,13 +65,13 @@ def test_watch_should_get_stored
w.start = 'bar'
watch = w
end
-
+
assert_equal 1, God.watches.size
assert_equal watch, God.watches.values.first
-
+
assert_equal 0, God.groups.size
end
-
+
def test_watch_should_get_stored_in_pending_watches
watch = nil
God.watch do |w|
@@ -79,11 +79,11 @@ def test_watch_should_get_stored_in_pending_watches
w.start = 'bar'
watch = w
end
-
+
assert_equal 1, God.pending_watches.size
assert_equal watch, God.pending_watches.first
end
-
+
def test_watch_should_register_processes
assert_nil God.registry['foo']
God.watch do |w|
@@ -92,86 +92,86 @@ def test_watch_should_register_processes
end
assert_kind_of God::Process, God.registry['foo']
end
-
+
def test_watch_should_get_stored_by_group
a = nil
-
+
God.watch do |w|
a = w
w.name = 'foo'
w.start = 'bar'
w.group = 'test'
end
-
+
assert_equal({'test' => [a]}, God.groups)
end
-
+
def test_watches_should_get_stored_by_group
a = nil
b = nil
-
+
God.watch do |w|
a = w
w.name = 'foo'
w.start = 'bar'
w.group = 'test'
end
-
+
God.watch do |w|
b = w
w.name = 'bar'
w.start = 'baz'
w.group = 'test'
end
-
+
assert_equal({'test' => [a, b]}, God.groups)
end
-
+
def test_watch_should_allow_multiple_watches
God.watch { |w| w.name = 'foo'; w.start = 'bar' }
-
+
assert_nothing_raised do
God.watch { |w| w.name = 'bar'; w.start = 'bar' }
end
end
-
+
def test_watch_should_disallow_duplicate_watch_names
God.watch { |w| w.name = 'foo'; w.start = 'bar' }
-
+
assert_abort do
God.watch { |w| w.name = 'foo'; w.start = 'bar' }
end
end
-
+
def test_watch_should_disallow_identical_watch_and_group_names
God.watch { |w| w.name = 'foo'; w.group = 'bar'; w.start = 'bar' }
-
+
assert_abort do
God.watch { |w| w.name = 'bar'; w.start = 'bar' }
end
end
-
+
def test_watch_should_disallow_identical_watch_and_group_names_other_way
God.watch { |w| w.name = 'bar'; w.start = 'bar' }
-
+
assert_abort do
God.watch { |w| w.name = 'foo'; w.group = 'bar'; w.start = 'bar' }
end
end
-
+
def test_watch_should_unwatch_new_watch_if_running_and_duplicate_watch
God.watch { |w| w.name = 'foo'; w.start = 'bar' }
God.running = true
-
+
assert_nothing_raised do
no_stdout do
God.watch { |w| w.name = 'foo'; w.start = 'bar' }
end
end
end
-
+
# unwatch
-
+
def test_unwatch_should_unmonitor_watch
God.watch { |w| w.name = 'bar'; w.start = 'bar' }
w = God.watches['bar']
@@ -181,7 +181,7 @@ def test_unwatch_should_unmonitor_watch
God.unwatch(w)
end
end
-
+
def test_unwatch_should_unregister_watch
God.watch { |w| w.name = 'bar'; w.start = 'bar' }
w = God.watches['bar']
@@ -190,7 +190,7 @@ def test_unwatch_should_unregister_watch
God.unwatch(w)
end
end
-
+
def test_unwatch_should_remove_same_name_watches
God.watch { |w| w.name = 'bar'; w.start = 'bar' }
w = God.watches['bar']
@@ -199,7 +199,7 @@ def test_unwatch_should_remove_same_name_watches
end
assert_equal 0, God.watches.size
end
-
+
def test_unwatch_should_remove_from_group
God.watch do |w|
w.name = 'bar'
@@ -212,32 +212,32 @@ def test_unwatch_should_remove_from_group
end
assert !God.groups[w.group].include?(w)
end
-
+
# contact
-
+
def test_contact_should_ensure_init_is_called
God.contact(:fake_contact) { |c| c.name = 'tom' }
assert God.inited
end
-
+
def test_contact_should_abort_on_invalid_contact_kind
assert_abort do
God.contact(:foo) { |c| c.name = 'tom' }
end
end
-
+
def test_contact_should_create_and_store_contact
contact = nil
God.contact(:fake_contact) { |c| c.name = 'tom'; contact = c }
assert [contact], God.contacts
end
-
+
def test_contact_should_add_to_group
God.contact(:fake_contact) { |c| c.name = 'tom'; c.group = 'devs' }
God.contact(:fake_contact) { |c| c.name = 'chris'; c.group = 'devs' }
assert 2, God.contact_groups.size
end
-
+
def test_contact_should_abort_on_no_name
no_stdout do
assert_abort do
@@ -245,7 +245,7 @@ def test_contact_should_abort_on_no_name
end
end
end
-
+
def test_contact_should_abort_on_duplicate_contact_name
God.contact(:fake_contact) { |c| c.name = 'tom' }
no_stdout do
@@ -254,7 +254,7 @@ def test_contact_should_abort_on_duplicate_contact_name
end
end
end
-
+
def test_contact_should_abort_on_contact_with_same_name_as_group
God.contact(:fake_contact) { |c| c.name = 'tom'; c.group = 'devs' }
no_stdout do
@@ -263,14 +263,14 @@ def test_contact_should_abort_on_contact_with_same_name_as_group
end
end
end
-
+
def test_contact_should_abort_on_contact_with_same_group_as_name
God.contact(:fake_contact) { |c| c.name = 'tom' }
assert_abort do
God.contact(:fake_contact) { |c| c.name = 'chris'; c.group = 'tom' }
end
end
-
+
def test_contact_should_abort_if_contact_is_invalid
assert_abort do
God.contact(:fake_contact) do |c|
@@ -279,111 +279,111 @@ def test_contact_should_abort_if_contact_is_invalid
end
end
end
-
+
# control
-
+
def test_control_should_monitor_on_start
God.watch { |w| w.name = 'foo'; w.start = 'bar' }
-
+
w = God.watches['foo']
w.expects(:monitor)
God.control('foo', 'start')
end
-
+
def test_control_should_move_to_restart_on_restart
God.watch { |w| w.name = 'foo'; w.start = 'bar' }
-
+
w = God.watches['foo']
w.expects(:move).with(:restart)
God.control('foo', 'restart')
end
-
+
def test_control_should_unmonitor_and_stop_on_stop
God.watch { |w| w.name = 'foo'; w.start = 'bar' }
-
+
w = God.watches['foo']
w.state = :up
w.expects(:unmonitor).returns(w)
w.expects(:action).with(:stop)
God.control('foo', 'stop')
end
-
+
def test_control_should_unmonitor_on_unmonitor
God.watch { |w| w.name = 'foo'; w.start = 'bar' }
-
+
w = God.watches['foo']
w.state = :up
w.expects(:unmonitor).returns(w)
God.control('foo', 'unmonitor')
end
-
+
def test_control_should_unwatch_on_remove
God.watch { |w| w.name = 'foo'; w.start = 'bar' }
-
+
w = God.watches['foo']
w.state = :up
God.expects(:unwatch)
God.control('foo', 'remove')
end
-
+
def test_control_should_raise_on_invalid_command
God.watch { |w| w.name = 'foo'; w.start = 'bar' }
-
+
assert_raise InvalidCommandError do
God.control('foo', 'invalid')
end
end
-
+
def test_control_should_operate_on_each_watch_in_group
God.watch do |w|
w.name = 'foo1'
w.start = 'go'
w.group = 'bar'
end
-
+
God.watch do |w|
w.name = 'foo2'
w.start = 'go'
w.group = 'bar'
end
-
+
God.watches['foo1'].expects(:monitor)
God.watches['foo2'].expects(:monitor)
-
+
God.control('bar', 'start')
end
-
+
# stop_all
-
+
# terminate
-
+
def test_terminate_should_exit
God.pid = nil
FileUtils.expects(:rm_f).never
God.expects(:exit!)
God.terminate
end
-
+
def test_terminate_should_delete_pid
God.pid = '/foo/bar'
FileUtils.expects(:rm_f).with("/foo/bar")
God.expects(:exit!)
God.terminate
end
-
+
# status
-
+
def test_status_should_show_state
God.watch { |w| w.name = 'foo'; w.start = 'bar' }
-
+
w = God.watches['foo']
w.state = :up
assert_equal({'foo' => {:state => :up, :group => nil}}, God.status)
end
-
+
def test_status_should_show_state_with_group
God.watch { |w| w.name = 'foo'; w.start = 'bar'; w.group = 'g' }
-
+
w = God.watches['foo']
w.state = :up
assert_equal({'foo' => {:state => :up, :group => 'g'}}, God.status)
@@ -391,29 +391,29 @@ def test_status_should_show_state_with_group
def test_status_should_show_unmonitored_for_nil_state
God.watch { |w| w.name = 'foo'; w.start = 'bar' }
-
+
w = God.watches['foo']
assert_equal({'foo' => {:state => :unmonitored, :group => nil}}, God.status)
end
-
+
# running_log
-
+
def test_running_log_should_call_watch_log_since_on_main_log
God.watch { |w| w.name = 'foo'; w.start = 'bar' }
t = Time.now
LOG.expects(:watch_log_since).with('foo', t)
God.running_log('foo', t)
end
-
+
def test_running_log_should_raise_on_unknown_watch
God.internal_init
assert_raise(NoSuchWatchError) do
God.running_log('foo', Time.now)
end
end
-
+
# running_load
-
+
def test_running_load_should_eval_code
code = <<-EOF
God.watch do |w|
@@ -421,14 +421,14 @@ def test_running_load_should_eval_code
w.start = 'go'
end
EOF
-
+
no_stdout do
God.running_load(code, '/foo/bar.god')
end
-
+
assert_equal 1, God.watches.size
end
-
+
def test_running_load_should_monitor_new_watches
code = <<-EOF
God.watch do |w|
@@ -436,13 +436,13 @@ def test_running_load_should_monitor_new_watches
w.start = 'go'
end
EOF
-
+
Watch.any_instance.expects(:monitor)
no_stdout do
God.running_load(code, '/foo/bar.god')
end
end
-
+
def test_running_load_should_not_monitor_new_watches_with_autostart_false
code = <<-EOF
God.watch do |w|
@@ -451,13 +451,13 @@ def test_running_load_should_not_monitor_new_watches_with_autostart_false
w.autostart = false
end
EOF
-
+
Watch.any_instance.expects(:monitor).never
no_stdout do
God.running_load(code, '/foo/bar.god')
end
end
-
+
def test_running_load_should_return_array_of_affected_watches
code = <<-EOF
God.watch do |w|
@@ -465,7 +465,7 @@ def test_running_load_should_return_array_of_affected_watches
w.start = 'go'
end
EOF
-
+
w = nil
no_stdout do
w, e = *God.running_load(code, '/foo/bar.god')
@@ -473,7 +473,7 @@ def test_running_load_should_return_array_of_affected_watches
assert_equal 1, w.size
assert_equal 'foo', w.first
end
-
+
def test_running_load_should_clear_pending_watches
code = <<-EOF
God.watch do |w|
@@ -481,69 +481,69 @@ def test_running_load_should_clear_pending_watches
w.start = 'go'
end
EOF
-
+
no_stdout do
God.running_load(code, '/foo/bar.god')
end
assert_equal 0, God.pending_watches.size
end
-
+
# load
-
+
def test_load_should_collect_and_load_globbed_path
Dir.expects(:[]).with('/path/to/*.thing').returns(['a', 'b'])
Kernel.expects(:load).with('a').once
Kernel.expects(:load).with('b').once
God.load('/path/to/*.thing')
end
-
+
# start
-
+
def test_start_should_kick_off_a_server_instance
God::Socket.expects(:new).returns(true)
God.start
end
-
+
def test_start_should_begin_monitoring_autostart_watches
God.watch do |w|
w.name = 'foo'
w.start = 'go'
end
-
+
Watch.any_instance.expects(:monitor).once
God.start
end
-
+
def test_start_should_not_begin_monitoring_non_autostart_watches
God.watch do |w|
w.name = 'foo'
w.start = 'go'
w.autostart = false
end
-
+
Watch.any_instance.expects(:monitor).never
God.start
end
-
+
def test_start_should_get_and_join_timer
God.watch { |w| w.name = 'foo'; w.start = 'bar' }
no_stdout do
God.start
end
end
-
+
# at_exit
-
+
def test_at_exit_should_call_start
God.expects(:start).once
God.at_exit
end
-
+
# pattern_match
-
+
def test_pattern_match
list = %w{ mongrel-3000 mongrel-3001 fuzed fuzed2 apache mysql}
-
+
assert_equal %w{ mongrel-3000 }, God.pattern_match('m3000', list)
assert_equal %w{ mongrel-3001 }, God.pattern_match('m31', list)
assert_equal %w{ fuzed fuzed2 }, God.pattern_match('fu', list)
@@ -558,37 +558,37 @@ def test_pattern_match
# God.internal_init
# God.reset
# end
-#
+#
# def teardown
# God.main && God.main.kill
# end
-#
+#
# # setup
-#
+#
# def test_setup_should_create_pid_file_directory_if_it_doesnt_exist
# God.expects(:test).returns(false)
# FileUtils.expects(:mkdir_p).with(God.pid_file_directory)
# God.setup
# end
-#
+#
# def test_setup_should_raise_if_no_permissions_to_create_pid_file_directory
# God.expects(:test).returns(false)
# FileUtils.expects(:mkdir_p).raises(Errno::EACCES)
-#
+#
# assert_abort do
# God.setup
# end
# end
-#
+#
# # validate
-#
+#
# def test_validate_should_abort_if_pid_file_directory_is_unwriteable
# God.expects(:test).returns(false)
# assert_abort do
# God.validater
# end
# end
-#
+#
# def test_validate_should_not_abort_if_pid_file_directory_is_writeable
# God.expects(:test).returns(true)
# assert_nothing_raised do
diff --git a/test/test_handlers_kqueue_handler.rb b/test/test_handlers_kqueue_handler.rb
index 24dcb82b..68a17611 100644
--- a/test/test_handlers_kqueue_handler.rb
+++ b/test/test_handlers_kqueue_handler.rb
@@ -1,16 +1,16 @@
require File.dirname(__FILE__) + '/helper'
if God::EventHandler.event_system == "kqueue"
-
+
class TestHandlersKqueueHandler < Test::Unit::TestCase
def test_register_process
KQueueHandler.expects(:monitor_process).with(1234, 2147483648)
KQueueHandler.register_process(1234, [:proc_exit])
end
-
+
def test_events_mask
assert_equal 2147483648, KQueueHandler.events_mask([:proc_exit])
end
end
-
+
end
\ No newline at end of file
diff --git a/test/test_logger.rb b/test/test_logger.rb
index 8f9e4e53..d373c560 100644
--- a/test/test_logger.rb
+++ b/test/test_logger.rb
@@ -4,56 +4,56 @@ class TestLogger < Test::Unit::TestCase
def setup
@log = God::Logger.new
end
-
+
# log
-
+
def test_log
@log.expects(:info).with("qux")
-
+
no_stdout do
@log.log(stub(:name => 'foo'), :info, "qux")
end
-
+
assert_equal 1, @log.logs.size
assert_instance_of Time, @log.logs['foo'][0][0]
assert_match(/qux/, @log.logs['foo'][0][1])
end
-
+
def test_log_should_send_to_syslog
Syslog.expects(:crit).with('foo')
-
+
no_stdout do
@log.log(stub(:name => 'foo'), :fatal, "foo")
end
end
-
+
# watch_log_since
-
+
def test_watch_log_since
t1 = Time.now
-
+
no_stdout do
@log.log(stub(:name => 'foo'), :info, "one")
@log.log(stub(:name => 'foo'), :info, "two")
end
-
+
assert_match(/one.*two/m, @log.watch_log_since('foo', t1))
-
+
t2 = Time.now
-
+
no_stdout do
@log.log(stub(:name => 'foo'), :info, "three")
end
-
+
out = @log.watch_log_since('foo', t2)
-
+
assert_no_match(/one/, out)
assert_no_match(/two/, out)
assert_match(/three/, out)
end
-
+
# regular methods
-
+
def test_fatal
no_stdout do
@log.fatal('foo')
diff --git a/test/test_metric.rb b/test/test_metric.rb
index 83ec90f5..1fcd9036 100644
--- a/test/test_metric.rb
+++ b/test/test_metric.rb
@@ -4,66 +4,66 @@ class TestMetric < Test::Unit::TestCase
def setup
@metric = Metric.new(stub(:interval => 10), nil)
end
-
+
# watch
-
+
def test_watch
w = stub()
m = Metric.new(w, nil)
assert_equal w, m.watch
end
-
+
# destination
-
+
def test_destination
d = stub()
m = Metric.new(nil, d)
assert_equal d, m.destination
end
-
+
# condition
-
+
def test_condition_should_be_block_optional
@metric.condition(:fake_poll_condition)
assert_equal 1, @metric.conditions.size
end
-
+
def test_poll_condition_should_inherit_interval_from_watch_if_not_specified
@metric.condition(:fake_poll_condition)
assert_equal 10, @metric.conditions.first.interval
end
-
+
def test_poll_condition_should_abort_if_no_interval_and_no_watch_interval
metric = Metric.new(stub(:name => 'foo', :interval => nil), nil)
-
+
assert_abort do
metric.condition(:fake_poll_condition)
end
end
-
+
def test_condition_should_allow_generation_of_subclasses_of_poll_or_event
metric = Metric.new(stub(:name => 'foo', :interval => 10), nil)
-
+
assert_nothing_raised do
metric.condition(:fake_poll_condition)
metric.condition(:fake_event_condition)
end
end
-
+
def test_condition_should_abort_if_not_subclass_of_poll_or_event
metric = Metric.new(stub(:name => 'foo', :interval => 10), nil)
-
+
assert_abort do
metric.condition(:fake_condition) { |c| }
end
end
-
+
def test_condition_should_abort_on_invalid_condition
assert_abort do
@metric.condition(:fake_poll_condition) { |c| c.stubs(:valid?).returns(false) }
end
end
-
+
def test_condition_should_abort_on_no_such_condition
assert_abort do
@metric.condition(:invalid) { }
diff --git a/test/test_process.rb b/test/test_process.rb
index 8f0aafd8..4138bee2 100644
--- a/test/test_process.rb
+++ b/test/test_process.rb
@@ -5,7 +5,7 @@ class Process
# def fork
# raise "You forgot to stub fork"
# end
-
+
def exec(*args)
raise "You forgot to stub exec"
end
@@ -19,60 +19,60 @@ def setup
@p.name = 'foo'
@p.stubs(:test).returns true # so we don't try to mkdir_p
Process.stubs(:detach) # because we stub fork
-
+
::Process::Sys.stubs(:setuid).returns(true)
::Process::Sys.stubs(:setgid).returns(true)
end
-
+
# valid?
-
+
def test_valid_should_return_true_if_auto_daemonized_and_log
@p.start = 'qux'
@p.log = 'bar'
-
+
assert @p.valid?
end
-
+
def test_valid_should_return_true_if_auto_daemonized_and_no_stop
@p.start = 'qux'
@p.log = 'bar'
-
+
assert @p.valid?
end
-
+
def test_valid_should_return_true_if_uid_exists
@p.start = 'qux'
@p.log = '/tmp/foo.log'
@p.uid = 'root'
-
+
assert @p.valid?
end
-
+
def test_valid_should_return_true_if_uid_does_not_exists
@p.start = 'qux'
@p.log = '/tmp/foo.log'
@p.uid = 'foobarbaz'
-
+
no_stdout do
no_stderr do
assert !@p.valid?
end
end
end
-
+
def test_valid_should_return_true_if_gid_exists
@p.start = 'qux'
@p.log = '/tmp/foo.log'
@p.gid = 'wheel'
-
+
assert @p.valid?
end
-
+
def test_valid_should_return_false_if_gid_does_not_exists
@p.start = 'qux'
@p.log = '/tmp/foo.log'
@p.gid = 'foobarbaz'
-
+
no_stdout do
no_stderr do
assert !@p.valid?
@@ -101,9 +101,9 @@ def test_valid_should_return_true_with_chroot_and_valid_log
assert @p.valid?
end
-
+
# call_action
-
+
def test_call_action_should_write_pid
# Only for start, restart
[:start, :restart].each do |action|
@@ -133,22 +133,22 @@ def setup
@p.stubs(:test).returns true # so we don't try to mkdir_p
Process.stubs(:detach) # because we stub fork
end
-
+
# alive?
-
+
def test_alive_should_call_system_process_exists
File.expects(:read).with('blah.pid').times(2).returns('1234')
System::Process.any_instance.expects(:exists?).returns(false)
assert !@p.alive?
end
-
+
def test_alive_should_return_false_if_no_such_file
File.expects(:read).with('blah.pid').raises(Errno::ENOENT)
assert !@p.alive?
end
-
+
# valid?
-
+
def test_valid_should_return_false_if_no_start
@p.name = 'foo'
@p.stop = 'baz'
@@ -156,87 +156,87 @@ def test_valid_should_return_false_if_no_start
assert !@p.valid?
end
end
-
+
def test_valid_should_return_false_if_self_daemonized_and_no_stop
@p.start = 'bar'
@p.pid_file = 'foo'
-
+
no_stdout do
assert !@p.valid?
end
end
-
+
# pid
-
+
def test_pid_should_return_integer_for_valid_pid_files
File.stubs(:read).returns("123")
assert_equal 123, @p.pid
end
-
+
def test_pid_should_return_nil_for_missing_files
@p.pid_file = ''
assert_equal nil, @p.pid
end
-
+
def test_pid_should_return_nil_for_invalid_pid_files
File.stubs(:read).returns("four score and seven years ago")
assert_equal nil, @p.pid
end
-
+
def test_pid_should_retain_last_pid_value_if_pid_file_is_removed
File.stubs(:read).returns("123")
assert_equal 123, @p.pid
-
+
File.stubs(:read).raises(Errno::ENOENT)
assert_equal 123, @p.pid
-
+
File.stubs(:read).returns("246")
assert_equal 246, @p.pid
end
-
+
# default_pid_file
-
+
def test_default_pid_file
assert_equal File.join(God.pid_file_directory, 'foo.pid'), @p.default_pid_file
end
-
+
# unix socket
-
+
def test_unix_socket_should_return_path_specified
@p.unix_socket = '/path/to-socket'
assert_equal '/path/to-socket', @p.unix_socket
end
-
+
# call_action
# These actually excercise call_action in the back at this point - Kev
-
+
def test_call_action_with_string_should_call_system
@p.start = "do something"
@p.expects(:fork)
Process.expects(:waitpid2).returns([123, 0])
@p.call_action(:start)
end
-
+
def test_call_action_with_lambda_should_call
cmd = lambda { puts "Hi" }
cmd.expects(:call)
@p.start = cmd
@p.call_action(:start)
end
-
+
def test_call_action_with_invalid_command_class_should_raise
@p.start = 5
@p.stop = 'baz'
-
+
assert @p.valid?
-
+
assert_raise NotImplementedError do
@p.call_action(:start)
end
end
-
+
# start!/stop!/restart!
-
+
def test_start_stop_restart_bang
[:start, :stop, :restart].each do |x|
@p.expects(:call_action).with(x)
diff --git a/test/test_registry.rb b/test/test_registry.rb
index 1c15f466..02ac61bc 100644
--- a/test/test_registry.rb
+++ b/test/test_registry.rb
@@ -4,7 +4,7 @@ class TestRegistry < Test::Unit::TestCase
def setup
God.registry.reset
end
-
+
def test_add
foo = God::Process.new
foo.name = 'foo'
diff --git a/test/test_socket.rb b/test/test_socket.rb
index 8ae42198..bf0daabb 100644
--- a/test/test_socket.rb
+++ b/test/test_socket.rb
@@ -2,7 +2,7 @@
class TestSocket < Test::Unit::TestCase
def setup
- silence_warnings do
+ silence_warnings do
Object.const_set(:DRb, stub_everything)
end
end
@@ -29,9 +29,9 @@ def test_should_forward_foreign_method_calls_to_god
God.expects(:send).with(:something_random)
server.something_random
end
-
+
# ping
-
+
def test_ping_should_return_true
server = nil
no_stdout do
diff --git a/test/test_sugar.rb b/test/test_sugar.rb
index 911a77f4..9c2875f6 100644
--- a/test/test_sugar.rb
+++ b/test/test_sugar.rb
@@ -5,37 +5,37 @@ def test_seconds
assert_equal 1, 1.seconds
assert_equal 1, 1.second
end
-
+
def test_minutes
assert_equal 60, 1.minutes
assert_equal 60, 1.minute
end
-
+
def test_hours
assert_equal 3600, 1.hours
assert_equal 3600, 1.hour
end
-
+
def test_days
assert_equal 86400, 1.days
assert_equal 86400, 1.day
end
-
+
def test_kilobytes
assert_equal 1, 1.kilobytes
assert_equal 1, 1.kilobyte
end
-
+
def test_megabytes
assert_equal 1024, 1.megabytes
assert_equal 1024, 1.megabyte
end
-
+
def test_gigabytes
assert_equal 1024 ** 2, 1.gigabytes
assert_equal 1024 ** 2, 1.gigabyte
end
-
+
def test_percent
assert_equal 1, 1.percent
end
diff --git a/test/test_system_portable_poller.rb b/test/test_system_portable_poller.rb
index f3f78516..44a2bb78 100644
--- a/test/test_system_portable_poller.rb
+++ b/test/test_system_portable_poller.rb
@@ -5,7 +5,7 @@ def setup
pid = Process.pid
@process = System::PortablePoller.new(pid)
end
-
+
def test_time_string_to_seconds
assert_equal 0, @process.bypass.time_string_to_seconds('0:00:00')
assert_equal 0, @process.bypass.time_string_to_seconds('0:00:55')
diff --git a/test/test_system_process.rb b/test/test_system_process.rb
index 9f1411a8..3fe0b5c2 100644
--- a/test/test_system_process.rb
+++ b/test/test_system_process.rb
@@ -5,24 +5,24 @@ def setup
pid = Process.pid
@process = System::Process.new(pid)
end
-
+
def test_exists_should_return_true_for_running_process
assert_equal true, @process.exists?
end
-
+
def test_exists_should_return_false_for_non_existant_process
assert_equal false, System::Process.new(9999999).exists?
end
-
+
def test_memory
assert_kind_of Integer, @process.memory
assert @process.memory > 0
end
-
+
def test_percent_memory
assert_kind_of Float, @process.percent_memory
end
-
+
def test_percent_cpu
assert_kind_of Float, @process.percent_cpu
end
diff --git a/test/test_task.rb b/test/test_task.rb
index ceb3a8b4..43f5199b 100644
--- a/test/test_task.rb
+++ b/test/test_task.rb
@@ -10,75 +10,75 @@ def setup
@task.interval = 5
@task.prepare
end
-
+
# valid?
-
+
def test_valid_should_return_false_if_no_name
@task.name = nil
no_stdout do
assert !@task.valid?
end
end
-
+
def test_valid_should_return_false_if_no_valid_states
@task.valid_states = nil
no_stdout do
assert !@task.valid?
end
end
-
+
def test_valid_should_return_false_if_no_initial_state
@task.initial_state = nil
no_stdout do
assert !@task.valid?
end
end
-
+
# transition
-
+
def test_transition_should_be_always_if_no_block_was_given
@task.transition(:foo, :bar)
-
+
assert 1, @task.metrics.size
assert Conditions::Always, @task.metrics.keys.first.class
end
-
+
# method_missing
-
+
def test_method_missing_should_create_accessor_for_states
assert_nothing_raised do
@task.foo = 'testing'
end
end
-
+
def test_method_missing_should_raise_for_non_states
assert_raise NoMethodError do
@task.baz = 5
end
end
-
+
def test_method_missing_should_raise_for_non_setters
assert_raise NoMethodError do
@task.baz
end
end
-
+
# action
-
+
def test_action_should_send_string_commands_to_system
@task.foo = 'foo'
Thread.current.stubs(:==).returns(true)
@task.expects(:system).with('foo')
no_stdout { @task.action(:foo, nil) }
end
-
+
def test_action_should_call_lambda_commands
@task.foo = lambda { }
Thread.current.stubs(:==).returns(true)
@task.foo.expects(:call)
no_stdout { @task.action(:foo, nil) }
end
-
+
def test_action_should_raise_not_implemented_on_non_string_or_lambda_action
Thread.current.stubs(:==).returns(true)
assert_raise NotImplementedError do
@@ -86,175 +86,175 @@ def test_action_should_raise_not_implemented_on_non_string_or_lambda_action
@task.action(:foo, nil)
end
end
-
+
def test_action_from_outside_driver_should_send_message_to_driver
@task.foo = 'foo'
@task.driver.expects(:message).with(:action, [:foo, nil])
@task.action(:foo, nil)
end
-
+
# attach
-
+
def test_attach_should_schedule_for_poll_condition
c = Conditions::FakePollCondition.new
@task.driver.expects(:schedule).with(c, 0)
@task.attach(c)
end
-
+
def test_attach_should_regsiter_for_event_condition
c = Conditions::FakeEventCondition.new
c.expects(:register)
@task.attach(c)
end
-
+
# detach
-
+
def test_detach_should_reset_poll_condition
c = Conditions::FakePollCondition.new
c.expects(:reset)
c.expects(:deregister).never
@task.detach(c)
end
-
+
def test_detach_should_deregister_event_conditions
c = Conditions::FakeEventCondition.new
c.expects(:deregister).once
@task.detach(c)
end
-
+
# trigger
-
+
def test_trigger_should_send_message_to_driver
c = Conditions::FakePollCondition.new
@task.driver.expects(:message).with(:handle_event, [c])
@task.trigger(c)
end
-
+
# handle_poll
-
+
def test_handle_poll_no_change_should_reschedule
c = Conditions::FakePollCondition.new
c.watch = @task
c.interval = 10
-
+
m = Metric.new(@task, {true => :up})
@task.directory[c] = m
-
+
c.expects(:test).returns(false)
@task.driver.expects(:schedule)
-
+
no_stdout do
@task.handle_poll(c)
end
end
-
+
def test_handle_poll_change_should_move
c = Conditions::FakePollCondition.new
c.watch = @task
c.interval = 10
-
+
m = Metric.new(@task, {true => :up})
@task.directory[c] = m
-
+
c.expects(:test).returns(true)
@task.expects(:move).with(:up)
-
+
no_stdout do
@task.handle_poll(c)
end
end
-
+
def test_handle_poll_should_use_overridden_transition
c = Conditions::Tries.new
c.watch = @task
c.times = 1
c.transition = :start
c.prepare
-
+
m = Metric.new(@task, {true => :up})
@task.directory[c] = m
-
+
@task.expects(:move).with(:start)
-
+
no_stdout do
@task.handle_poll(c)
end
end
-
+
def test_handle_poll_should_notify_if_triggering
c = Conditions::FakePollCondition.new
c.watch = @task
c.interval = 10
c.notify = 'tom'
-
+
m = Metric.new(@task, {true => :up})
@task.directory[c] = m
-
+
c.expects(:test).returns(true)
@task.expects(:notify)
-
+
no_stdout do
@task.handle_poll(c)
end
end
-
+
def test_handle_poll_should_not_notify_if_not_triggering
c = Conditions::FakePollCondition.new
c.watch = @task
c.interval = 10
c.notify = 'tom'
-
+
m = Metric.new(@task, {true => :up})
@task.directory[c] = m
-
+
c.expects(:test).returns(false)
@task.expects(:notify).never
-
+
no_stdout do
@task.handle_poll(c)
end
end
-
+
# handle_event
-
+
def test_handle_event_should_move
c = Conditions::FakeEventCondition.new
c.watch = @task
-
+
m = Metric.new(@task, {true => :up})
@task.directory[c] = m
-
+
@task.expects(:move).with(:up)
-
+
no_stdout do
@task.handle_event(c)
end
end
-
+
def test_handle_event_should_notify_if_triggering
c = Conditions::FakeEventCondition.new
c.watch = @task
c.notify = 'tom'
-
+
m = Metric.new(@task, {true => :up})
@task.directory[c] = m
-
+
@task.expects(:notify)
-
+
no_stdout do
@task.handle_event(c)
end
end
-
+
def test_handle_event_should_not_notify_if_no_notify_set
c = Conditions::FakeEventCondition.new
c.watch = @task
-
+
m = Metric.new(@task, {true => :up})
@task.directory[c] = m
-
+
@task.expects(:notify).never
-
+
no_stdout do
@task.handle_event(c)
end
diff --git a/test/test_timeline.rb b/test/test_timeline.rb
index 2b138877..8f362d94 100644
--- a/test/test_timeline.rb
+++ b/test/test_timeline.rb
@@ -4,32 +4,32 @@ class TestTimeline < Test::Unit::TestCase
def setup
@timeline = Timeline.new(5)
end
-
+
def test_new_should_be_empty
assert_equal 0, @timeline.size
end
-
+
def test_should_not_grow_to_more_than_size
(1..10).each do |i|
@timeline.push(i)
end
-
+
assert_equal [6, 7, 8, 9, 10], @timeline
end
-
+
def test_clear_should_clear_array
@timeline << 1
assert_equal [1], @timeline
assert_equal [], @timeline.clear
end
-
+
# def test_benchmark
# require 'benchmark'
- #
+ #
# count = 1_000_000
- #
+ #
# t = Timeline.new(10)
- #
+ #
# Benchmark.bmbm do |x|
# x.report("go") { count.times { t.push(5) } }
# end
diff --git a/test/test_trigger.rb b/test/test_trigger.rb
index 26fd1a50..9d260b2d 100644
--- a/test/test_trigger.rb
+++ b/test/test_trigger.rb
@@ -4,56 +4,56 @@ class TestTrigger < Test::Unit::TestCase
def setup
Trigger.reset
end
-
+
# base case
-
+
def test_should_have_empty_triggers
assert_equal({}, Trigger.triggers)
end
-
+
# register
-
+
def test_register_should_add_condition_to_triggers
c = Condition.new
c.watch = stub(:name => 'foo')
Trigger.register(c)
-
+
assert_equal({'foo' => [c]}, Trigger.triggers)
end
-
+
def test_register_should_add_condition_to_triggers_twice
watch = stub(:name => 'foo')
c = Condition.new
c.watch = watch
Trigger.register(c)
-
+
c2 = Condition.new
c2.watch = watch
Trigger.register(c2)
-
+
assert_equal({'foo' => [c, c2]}, Trigger.triggers)
end
-
+
# deregister
-
+
def test_deregister_should_remove_condition_from_triggers
c = Condition.new
c.watch = stub(:name => 'foo')
Trigger.register(c)
Trigger.deregister(c)
-
+
assert_equal({}, Trigger.triggers)
end
-
+
# broadcast
-
+
def test_broadcast_should_call_process_on_each_condition
c = Condition.new
c.watch = stub(:name => 'foo')
Trigger.register(c)
-
+
c.expects(:process).with(:state_change, [:up, :start])
-
+
Trigger.broadcast(c.watch, :state_change, [:up, :start])
end
end
\ No newline at end of file
diff --git a/test/test_watch.rb b/test/test_watch.rb
index 82861e3a..72feffd7 100644
--- a/test/test_watch.rb
+++ b/test/test_watch.rb
@@ -9,19 +9,19 @@ def setup
@watch.stop = lambda { }
@watch.prepare
end
-
+
# new
-
+
def test_new_should_have_no_behaviors
assert_equal [], @watch.behaviors
end
-
+
def test_new_should_have_no_metrics
Watch::VALID_STATES.each do |state|
assert_equal [], @watch.metrics[state]
end
end
-
+
def test_new_should_have_standard_attributes
assert_nothing_raised do
@watch.name = 'foo'
@@ -32,41 +32,41 @@ def test_new_should_have_standard_attributes
@watch.grace = 5
end
end
-
+
def test_new_should_have_unmonitored_state
assert_equal :unmonitored, @watch.state
end
-
+
# valid?
-
+
def test_valid?
God::Process.any_instance.expects(:valid?)
@watch.valid?
end
-
+
# behavior
-
+
def test_behavior_should_record_behavior
beh = nil
@watch.behavior(:fake_behavior) { |b| beh = b }
assert_equal 1, @watch.behaviors.size
assert_equal beh, @watch.behaviors.first
end
-
+
def test_invalid_behavior_should_abort
assert_abort do
@watch.behavior(:invalid)
end
end
-
+
# transition
-
+
def test_transition_should_abort_on_invalid_start_state
assert_abort do
@watch.transition(:foo, :bar)
end
end
-
+
def test_transition_should_accept_all_valid_start_states
assert_nothing_raised do
Watch::VALID_STATES.each do |state|
@@ -74,35 +74,35 @@ def test_transition_should_accept_all_valid_start_states
end
end
end
-
+
def test_transition_should_create_and_record_a_metric_for_the_given_start_state
@watch.transition(:init, :start) { }
assert_equal 1, @watch.metrics[:init].size
end
-
+
# lifecycle
-
+
def test_lifecycle_should_create_and_record_a_metric_for_nil_start_state
@watch.lifecycle { }
assert_equal 1, @watch.metrics[nil].size
end
-
+
# start_if
-
+
def test_start_if_should_place_a_metric_on_up_state
@watch.start_if { }
assert_equal 1, @watch.metrics[:up].size
end
-
+
# restart_if
-
+
def test_restart_if_should_place_a_metric_on_up_state
@watch.restart_if { }
assert_equal 1, @watch.metrics[:up].size
end
-
+
# monitor
-
+
def test_monitor_should_move_to_init_if_available
@watch.instance_eval do
transition(:init, :up) { }
@@ -110,27 +110,27 @@ def test_monitor_should_move_to_init_if_available
@watch.expects(:move).with(:init)
@watch.monitor
end
-
+
def test_monitor_should_move_to_up_if_no_init_available
@watch.expects(:move).with(:up)
@watch.monitor
end
-
+
# unmonitor
-
+
def test_unmonitor_should_move_to_nil
@watch.expects(:move).with(:unmonitored)
@watch.unmonitor
end
-
+
# move
-
+
def test_move_should_not_clean_up_if_from_state_is_nil
Thread.current.stubs(:==).returns(true)
@watch.driver.expects(:message).never
-
+
metric = nil
-
+
@watch.instance_eval do
transition(:init, :up) do |on|
metric = on
@@ -140,18 +140,18 @@ def test_move_should_not_clean_up_if_from_state_is_nil
end
end
end
-
+
metric.expects(:disable).never
-
+
no_stdout { @watch.move(:init) }
end
-
+
def test_move_should_clean_up_from_state_if_not_nil
Thread.current.stubs(:==).returns(true)
@watch.driver.expects(:message).never
-
+
metric = nil
-
+
@watch.instance_eval do
transition(:init, :up) do |on|
metric = on
@@ -161,40 +161,40 @@ def test_move_should_clean_up_from_state_if_not_nil
end
end
end
-
+
no_stdout { @watch.move(:init) }
-
+
metric.expects(:disable)
-
+
no_stdout { @watch.move(:up) }
end
-
+
def test_move_should_call_action
Thread.current.stubs(:==).returns(true)
@watch.driver.expects(:message).never
-
+
@watch.expects(:action).with(:start)
-
+
no_stdout { @watch.move(:start) }
end
-
+
def test_move_should_move_to_up_state_if_no_start_or_restart_metric
Thread.current.stubs(:==).returns(true)
@watch.driver.expects(:message).never
-
+
[:start, :restart].each do |state|
@watch.expects(:action)
no_stdout { @watch.move(state) }
assert_equal :up, @watch.state
end
end
-
+
def test_move_should_enable_destination_metric
Thread.current.stubs(:==).returns(true)
@watch.driver.expects(:message).never
-
+
metric = nil
-
+
@watch.instance_eval do
transition(:init, :up) do |on|
metric = on
@@ -204,53 +204,53 @@ def test_move_should_enable_destination_metric
end
end
end
-
+
metric.expects(:enable)
-
+
no_stdout { @watch.move(:init) }
end
-
+
# action
-
+
def test_action_should_pass_start_and_stop_actions_to_call_action
Thread.current.stubs(:==).returns(true)
@watch.driver.expects(:message).never
-
+
c = Conditions::FakePollCondition.new
[:start, :stop].each do |cmd|
@watch.expects(:call_action).with(c, cmd)
@watch.action(cmd, c)
end
end
-
+
def test_action_should_do_stop_then_start_if_no_restart_command
Thread.current.stubs(:==).returns(true)
@watch.driver.expects(:message).never
-
+
c = Conditions::FakePollCondition.new
@watch.expects(:call_action).with(c, :stop)
@watch.expects(:call_action).with(c, :start)
@watch.action(:restart, c)
end
-
+
def test_action_should_restart_to_call_action_if_present
Thread.current.stubs(:==).returns(true)
@watch.driver.expects(:message).never
-
+
@watch.restart = lambda { }
c = Conditions::FakePollCondition.new
@watch.expects(:call_action).with(c, :restart)
@watch.action(:restart, c)
end
-
+
# call_action
-
+
def test_call_action
c = Conditions::FakePollCondition.new
God::Process.any_instance.expects(:call_action).with(:start)
no_stdout { @watch.call_action(c, :start) }
end
-
+
def test_call_action_should_call_before_start_when_behavior_has_that
@watch.behavior(:fake_behavior)
c = Conditions::FakePollCondition.new
@@ -258,7 +258,7 @@ def test_call_action_should_call_before_start_when_behavior_has_that
Behaviors::FakeBehavior.any_instance.expects(:before_start)
no_stdout { @watch.call_action(c, :start) }
end
-
+
def test_call_action_should_call_after_start_when_behavior_has_that
@watch.behavior(:fake_behavior)
c = Conditions::FakePollCondition.new
@@ -266,13 +266,13 @@ def test_call_action_should_call_after_start_when_behavior_has_that
Behaviors::FakeBehavior.any_instance.expects(:after_start)
no_stdout { @watch.call_action(c, :start) }
end
-
+
# canonical_hash_form
-
+
def test_canonical_hash_form_should_convert_symbol_to_hash
assert_equal({true => :foo}, @watch.canonical_hash_form(:foo))
end
-
+
def test_canonical_hash_form_should_convert_hash_to_hash
assert_equal({true => :foo}, @watch.canonical_hash_form(true => :foo))
end