require 'yaml' require 'open-uri' require 'cgi' def eval_and_fetch_constants(x) old = Module.constants.map{|c| c.to_s} eval(x) new = (Module.constants.map{|c| c.to_s} - old) new.map{|const| const_get(const) } end class Scout class Plugin OPTIONS = {}.to_yaml protected def report(metrics) metrics.each do |key, value| Deputy.send_report "#{clean_class_name}.#{key}", value end end def error(*args) report :error => args.map{|a| a.inspect}.join(', ') end def alert(*args) report :alert => args.map{|a| a.inspect}.join(', ') end def memory(key) complete_memory[key] end def remember(data) all = complete_memory.merge(data) File.open(memory_file, 'w'){|f| f.write all.to_yaml } end private def complete_memory return {} unless File.exist?(memory_file) YAML.load(File.read(memory_file)) || {} end def memory_file "/tmp/deputy.memory.#{clean_class_name}.yml" end def clean_class_name self.class.to_s.split('::')[1..-1].join('::') end # stub options for now... def option(key) (YAML.load(self.class::OPTIONS)[key.to_s]||{})['default'] end end def self.plugins(code) eval_and_fetch_constants(code).map do |container| interval = container.interval unless plugin = plugin_in_container(container) Deputy.send_report "Deputies.Plugin not found", code next end [interval, plugin] end.compact end def self.plugin_in_container(container) constants = container.constants.map{|constant_name| container.const_get(constant_name)} constants.detect{|c| c.instance_methods.map{|m| m.to_s}.include?('build_report') } end end module Deputy START_MINUTE = (Time.now.to_i + 30) / 60 # we could start at 58..02 seconds -> always in middle of minute VERSION = File.read( File.join(File.dirname(__FILE__),'..','VERSION') ).strip def self.install_cron `crontab -l | { cat; echo "* * * * * deputy --run-plugins 2>&1 >> /tmp/deputy.log"; } | crontab -` end def self.run_plugins content = get("/plugins.rb") Scout.plugins(content).each do |interval, plugin| run_every_n_minutes = interval/60 plugin.new.build_report if START_MINUTE % run_every_n_minutes == 0 end rescue Exception => e send_report "Deputies.Error", e.message raise e end def self.send_report(metric, value) get "/report/#{CGI.escape metric}?value=#{CGI.escape value.to_s}" end def self.get(path) url = "#{sheriff_url}#{path}" open(url).read rescue => e e.message << url raise e end def self.sheriff_url config['sheriff_url'].sub(%r{/$},'') end def self.config home = File.expand_path('~') ["#{home}/.deputy.yml", '/etc/deputy.yml'].each do |file| return YAML.load(File.read(file)) if File.exist?(file) end raise "No deputy.yml found in /etc or #{home}" end end