#!/usr/bin/env ruby $VERBOSE = true # -w $KCODE = "u" # -Ku $LOAD_PATH << File.join(File.dirname(__FILE__), *%w[.. lib]) require "scout" require "optparse" require "logger" require "fileutils" require "pp" CONFIG_DIR = File.join((File.expand_path("~") rescue "/"), ".scout") USER = ENV["USER"] || ENV["USERNAME"] || "root" options = { :server => "https://scoutapp.com/", :history => File.join(CONFIG_DIR , "client_history.yaml"), :verbose => false, :level => "info" } ARGV.options do |opts| opts.banner = "Usage: #{File.basename($PROGRAM_NAME)} [OPTIONS] CLIENT_KEY" opts.separator "" opts.separator "CLIENT_KEY is the indentification key assigned to this " + "client by the server." opts.separator "" opts.separator "Note: This client is meant to be installed and invoked " + "through cron or any other scheduler." opts.separator "" opts.separator "Specific Options:" opts.on( "-s", "--server SERVER", String, "The URL for the server this client reports to." ) do |url| options[:server] = url end opts.on( "-p", "--plugin PLUGIN", String, "The path to a plugin to run locally. " + "Useful for Testing." ) do |plugin| options[:plugin] = plugin end opts.separator "" opts.on( "-d", "--data DATA", String, "The data file used to track the history of executions." ) do |file| options[:history] = file end opts.on( "-l", "--level LEVEL", Logger::SEV_LABEL.map { |l| l.downcase }, "The level of logging to report." ) do |level| options[:level] = level end opts.on( "-o", "--plugin-options PLUGIN_OPTIONS", String, "The options YAML file to pass to the plugin." ) do |plugin_options| options[:plugin_options] = plugin_options end opts.separator "Common Options:" opts.on( "-h", "--help", "Show this message." ) do puts opts exit end opts.on( "-v", "--[no-]verbose", "Turn on logging to STDOUT" ) do |bool| options[:verbose] = bool end begin opts.parse! options[:client_key] = ARGV.shift if ARGV.size == 1 rescue puts opts exit end end log = Logger.new($stdout) log.datetime_format = "%Y-%m-%d %H:%M " log.level = Logger.const_get(options[:level].upcase) \ rescue Logger::INFO real_config_dir = File.dirname(options[:history]) FileUtils.mkdir_p(real_config_dir) # ensure dir exists # make sure only one copy is ever running at a time pid_file = File.join(real_config_dir, "scout_client_pid.txt") begin File.open(pid_file, File::CREAT|File::EXCL|File::WRONLY) { |pid| pid.puts $$ } at_exit do begin File.unlink(pid_file) rescue log.error "Unable to unlink pid file: #{$!.message}" end end rescue pid = File.read(pid_file).strip.to_i rescue "unknown" running = true begin Process.kill(0, pid) rescue Errno::ESRCH running = false rescue # do nothing, we didn't have permission to the running process end if running log.warn "Process #{pid} was already running" exit else log.info "Stale PID file found. Clearing it and reloading..." File.unlink(pid_file) retry end end if [:client_key, :plugin].all? { |o| options[o].nil? } and $stdin.tty? # install wizard puts <<-END_INTRO.gsub(/^ {2}/, "") == Scout Installation Wizard == You need the Client Key displayed in the Client Settings tab. It looks like: 6ecad322-0d17-4cb8-9b2c-a12c4541853f Enter the Client Key: END_INTRO options[:client_key] = gets.to_s.strip # puts "Attempting to contact the server..." begin Scout::Server.new( options[:server], options[:client_key], options[:history], options[:verbose] ? log : nil ) { |server| server.test } puts <<-END_SUCCESS.gsub(/^ {4}/, "") Success! ******* NOW, INSTALL IN CRONTAB ******* */10 * * * * #{USER} #{File.expand_path($PROGRAM_NAME)} #{options[:client_key]} ******* END CRONTAB SAMPLE ******* For help setting up Scout with crontab, please visit: http://scoutapp.com/help#cron END_SUCCESS rescue SystemExit puts <<-END_ERROR.gsub(/^ {4}/, "") Could not contact server. The client key may be incorrect. For more help, please visit: http://scoutapp.com/help END_ERROR end elsif options[:plugin] # local plugin # read the plugin_code from the file specified plugin_code = File.read(options[:plugin]) plugin_options = if options[:plugin_options].to_s[0..0] == "{" eval(options[:plugin_options]) # options from command-line elsif options[:plugin_options] # # read the plugin_options from the YAML file specified, # parse each option and use the default value specified # in the options as the value to be passed to the test plugin # Hash[ *File.open(options[:plugin_options]) { |f| YAML.load(f) }["options"]. map { |name, details| [name, details["default"]] }.flatten ] else Hash.new end Scout::Server.new( nil, options[:client_key], options[:history], options[:verbose] ? log : nil ) do |server| pp server.process_plugin( { :interval => 0, :plugin_id => 1, :name => "Local Plugin", :code => plugin_code, :options => plugin_options, :path => options[:plugin] } ) end else # normal run Scout::Server.new( options[:server], options[:client_key], options[:history], options[:verbose] ? log : nil ) do |server| server.run_plugins_by_plan end end