From 1b46be3d747b64dbe4e74adad9d39c9e38c99229 Mon Sep 17 00:00:00 2001 From: Tom Werner Date: Wed, 3 Oct 2007 17:40:11 -0700 Subject: [PATCH] add host to notifications; check dir permissions on startup --- bin/god | 25 +++++++++++++++++-------- lib/god/contact.rb | 3 ++- lib/god/contacts/email.rb | 7 ++++--- lib/god/hub.rb | 3 ++- lib/god/logger.rb | 1 + lib/god/process.rb | 26 +++++++++++++++++++++++++- test/configs/contact/contact.god | 3 +++ test/test_contact.rb | 2 +- test/test_process.rb | 25 ++++++++++++++++--------- 9 files changed, 71 insertions(+), 24 deletions(-) diff --git a/bin/god b/bin/god index 0641d25..208e4c7 100755 --- a/bin/god +++ b/bin/god @@ -216,10 +216,14 @@ begin begin load File.expand_path(options[:config]) - rescue => e - puts e.message - puts e.backtrace.join("\n") - abort "There was an error in your configuration file (see above)" + rescue Exception => e + if e.instance_of?(SystemExit) + raise + else + puts e.message + puts e.backtrace.join("\n") + abort "There was an error in your configuration file (see above)" + end end end else @@ -256,10 +260,14 @@ begin begin load File.expand_path(options[:config]) - rescue => e - puts e.message - puts e.backtrace.join("\n") - abort "There was an error in your configuration file (see above)" + rescue Exception => e + if e.instance_of?(SystemExit) + raise + else + puts e.message + puts e.backtrace.join("\n") + abort "There was an error in your configuration file (see above)" + end end end @@ -287,6 +295,7 @@ rescue Exception => e if e.instance_of?(SystemExit) raise else + puts 'Uncaught exception' puts e.message puts e.backtrace.join("\n") end diff --git a/lib/god/contact.rb b/lib/god/contact.rb index 7f54fc1..5de3181 100644 --- a/lib/god/contact.rb +++ b/lib/god/contact.rb @@ -90,7 +90,8 @@ module God # +time+ is the Time at which the notification was made # +priority+ is the arbitrary priority String # +category+ is the arbitrary category String - def notify(message, time, priority, category) + # +host+ is the hostname of the server + def notify(message, time, priority, category, host) raise AbstractMethodNotOverriddenError.new("Contact#notify must be overridden in subclasses") end diff --git a/lib/god/contacts/email.rb b/lib/god/contacts/email.rb index a8db376..c888558 100644 --- a/lib/god/contacts/email.rb +++ b/lib/god/contacts/email.rb @@ -20,7 +20,7 @@ module God # :password # :authentication - self.format = lambda do |name, email, message, time, priority, category| + self.format = lambda do |name, email, message, time, priority, category, host| <<-EOF From: god <#{self.message_settings[:from]}> To: #{name} <#{email}> @@ -29,6 +29,7 @@ Date: #{Time.now.httpdate} Message-Id: Message: #{message} +Host: #{host} Priority: #{priority} Category: #{category} EOF @@ -42,9 +43,9 @@ Category: #{category} valid end - def notify(message, time, priority, category) + def notify(message, time, priority, category, host) begin - body = Email.format.call(self.name, self.email, message, time, priority, category) + body = Email.format.call(self.name, self.email, message, time, priority, category, host) args = [Email.server_settings[:address], Email.server_settings[:port]] if Email.server_settings[:authentication] diff --git a/lib/god/hub.rb b/lib/god/hub.rb index 42a4fd8..2b0f7b4 100644 --- a/lib/god/hub.rb +++ b/lib/god/hub.rb @@ -215,7 +215,8 @@ module God # notify each contact resolved_contacts.each do |c| - c.notify(message, Time.now, spec[:priority], spec[:category]) + 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})" diff --git a/lib/god/logger.rb b/lib/god/logger.rb index aa48bd5..c379305 100644 --- a/lib/god/logger.rb +++ b/lib/god/logger.rb @@ -31,6 +31,7 @@ module God # push onto capture and timeline for the given watch buf = StringIO.new templog = ::Logger.new(buf) + templog.level = Logger::INFO templog.send(level, text) @mutex.synchronize do @capture.puts(buf.string) if @capture diff --git a/lib/god/process.rb b/lib/god/process.rb index 3b35621..4db1fc8 100644 --- a/lib/god/process.rb +++ b/lib/god/process.rb @@ -22,6 +22,18 @@ module God end end + def file_writable?(file) + pid = fork do + ::Process::Sys.setgid(Etc.getgrnam(self.gid).gid) if self.gid + ::Process::Sys.setuid(Etc.getpwnam(self.uid).uid) if self.uid + + File.writable?(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 @@ -61,17 +73,29 @@ module God end # pid dir must exist if specified - if self.pid_file && !File.exist?(File.dirname(self.pid_file)) + if !@tracking_pid && !File.exist?(File.dirname(self.pid_file)) valid = false LOG.log(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_writable?(File.dirname(self.pid_file)) + valid = false + LOG.log(self, :error, "PID file directory '#{File.dirname(self.pid_file)}' is not writable by #{self.uid || Etc.getlogin}") + end + # log dir must exist if specified if self.log && !File.exist?(File.dirname(self.log)) valid = false LOG.log(self, :error, "Log directory '#{File.dirname(self.log)}' does not exist") end + # log dir must be writable if specified + if self.log && !file_writable?(File.dirname(self.log)) + valid = false + LOG.log(self, :error, "Log directory '#{File.dirname(self.log)}' is not writable by #{self.uid || Etc.getlogin}") + end + valid end diff --git a/test/configs/contact/contact.god b/test/configs/contact/contact.god index 291aaa8..da76dee 100644 --- a/test/configs/contact/contact.god +++ b/test/configs/contact/contact.god @@ -28,6 +28,9 @@ God.watch do |w| w.name = "contact" w.interval = 5.seconds w.start = "ruby " + File.join(File.dirname(__FILE__), *%w[simple_server.rb]) + 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| diff --git a/test/test_contact.rb b/test/test_contact.rb index 9b1d414..1d4427f 100644 --- a/test/test_contact.rb +++ b/test/test_contact.rb @@ -103,7 +103,7 @@ class TestContact < Test::Unit::TestCase def test_notify_should_be_abstract assert_raise(AbstractMethodNotOverriddenError) do - Contact.new.notify(:a, :b, :c, :d) + Contact.new.notify(:a, :b, :c, :d, :e) end end end \ No newline at end of file diff --git a/test/test_process.rb b/test/test_process.rb index 9e6ef39..0c7d77a 100644 --- a/test/test_process.rb +++ b/test/test_process.rb @@ -2,9 +2,9 @@ require File.dirname(__FILE__) + '/helper' module God class Process - def fork - raise "You forgot to stub fork" - end + # def fork + # raise "You forgot to stub fork" + # end def exec(*args) raise "You forgot to stub exec" @@ -19,6 +19,9 @@ class TestProcessChild < Test::Unit::TestCase @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? @@ -39,7 +42,7 @@ class TestProcessChild < Test::Unit::TestCase def test_valid_should_return_true_if_uid_exists @p.start = 'qux' - @p.log = 'bar' + @p.log = '/tmp/foo.log' @p.uid = 'root' assert @p.valid? @@ -47,17 +50,19 @@ class TestProcessChild < Test::Unit::TestCase def test_valid_should_return_true_if_uid_does_not_exists @p.start = 'qux' - @p.log = 'bar' + @p.log = '/tmp/foo.log' @p.uid = 'foobarbaz' no_stdout do - assert !@p.valid? + no_stderr do + assert !@p.valid? + end end end def test_valid_should_return_true_if_gid_exists @p.start = 'qux' - @p.log = 'bar' + @p.log = '/tmp/foo.log' @p.gid = 'wheel' assert @p.valid? @@ -65,11 +70,13 @@ class TestProcessChild < Test::Unit::TestCase def test_valid_should_return_true_if_gid_does_not_exists @p.start = 'qux' - @p.log = 'bar' + @p.log = '/tmp/foo.log' @p.gid = 'foobarbaz' no_stdout do - assert !@p.valid? + no_stderr do + assert !@p.valid? + end end end -- 2.11.4.GIT