#!/usr/bin/env ruby $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib]) require 'rubygems' require 'optparse' require 'drb' options = {:daemonize => true, :port => 17165} OptionParser.new do |opts| opts.banner = <<-EOF Usage: god [command] [options] Commands: start <watch or group name> restart <watch or group name> stop <watch or group name> monitor <watch or group name> unmonitor <watch or group name> load <file> log <watch name> status terminate Options: EOF opts.on("-cCONFIG", "--config-file CONFIG", "Configuration file") do |x| options[:config] = x end opts.on("-pPORT", "--port PORT", "Communications port") do |x| options[:port] = x end opts.on("-PFILE", "--pid FILE", "Where to write the PID file") do |x| options[:pid] = x end opts.on("-lFILE", "--log FILE", "Where to write the log file") do |x| options[:log] = x end opts.on("-D", "--no-daemonize", "Don't daemonize") do options[:daemonize] = false end opts.on("-v", "--version", "Print the version number and exit") do options[:version] = true end opts.on("-V", "Print extended version and build information") do options[:info] = true end end.parse! if options[:version] require 'god' # print version puts "Version #{God::VERSION}" exit!(0) elsif options[:info] require 'god' puts "Version: #{God::VERSION}" puts "Polls: enabled" puts "Events: " + God::EventHandler.event_system exit!(0) elsif command = ARGV[0] require 'god' # a command was specified # connect to remote drb DRb.start_service server = DRbObject.new nil, "druby://127.0.0.1:#{options[:port]}" begin server.ping rescue DRb::DRbConnError puts "The server is not available (or you do not have permissions to access it)" exit! rescue => e puts e.message puts e.backtrace.join("\n") exit! end if command == 'load' file = ARGV[1] puts "Sending '#{command}' command" code = File.read(file) watches = server.running_load(code) # output response puts 'The following watches were affected:' watches.each do |w| puts ' ' + w.name end puts "Done" elsif command == 'status' watches = server.status watches.keys.sort.each do |name| state = watches[name][:state] puts "#{name}: #{state}" end elsif command == 'log' begin Signal.trap('INT') { exit!(0) } name = ARGV[1] t = Time.at(0) loop do print server.running_log(name, t) t = Time.now sleep 1 end rescue God::NoSuchWatchError puts "No such watch" rescue DRb::DRbConnError puts "The server went away" rescue => e puts e.message puts e.backtrace.join("\n") ensure exit!(0) end elsif command == 'terminate' t = Thread.new { loop { STDOUT.print('.'); STDOUT.flush; sleep(1) } } if server.stop_all t.kill; STDOUT.puts puts 'Stopped all watches' else t.kill; STDOUT.puts puts 'Could not stop all watches within 10 seconds' end begin server.terminate abort 'Could not stop god' rescue DRb::DRbConnError puts 'Stopped god' exit!(0) end else # get the name of the watch/group name = ARGV[1] begin puts "Sending '#{command}' command" t = Thread.new { loop { STDOUT.print('.'); STDOUT.flush; sleep(1) } } # send command watches = server.control(name, command) # output response t.kill; STDOUT.puts puts 'The following watches were affected:' watches.each do |w| puts ' ' + w.name end rescue God::InvalidCommandError abort "Command '#{command}' is not valid. Run 'god --help' for usage" end end exit!(0) else # start god if !options[:daemonize] require 'god' if options[:port] God.port = options[:port] end load File.expand_path(options[:config]) else pid = fork do begin require 'god' log_file = options[:log] || "/dev/null" STDIN.reopen "/dev/null" STDOUT.reopen(log_file, "a") STDERR.reopen STDOUT puts "Starting god" unless God::EventHandler.loaded? puts puts "***********************************************************************" puts "*" puts "* Event conditions are not available for your installation of god." puts "* You may still use and write custom conditions using the poll system" puts "*" puts "***********************************************************************" puts end puts "Resetting file descriptors" puts "Loading config" if options[:port] God.port = options[:port] end load File.expand_path(options[:config]) Signal.trap('HUP') {} rescue => e File.open('god.log', 'a') { |f| f.puts e.message + "\n" + e.backtrace } abort "!!! ERROR - See god.log !!!" end end if options[:pid] File.open(options[:pid], 'w') { |f| f.write pid } end ::Process.detach pid exit!(0) end end