es-scout 5.3.0.es1
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +4 -0
- data/CHANGELOG +225 -0
- data/COPYING +340 -0
- data/INSTALL +18 -0
- data/LICENSE +6 -0
- data/README +66 -0
- data/Rakefile +74 -0
- data/TODO +6 -0
- data/bin/es-scout +10 -0
- data/data/cacert.pem +3154 -0
- data/data/code_key.pub +13 -0
- data/data/gpl-2.0.txt +339 -0
- data/data/lgpl-2.1.txt +504 -0
- data/lib/es-scout/command/install.rb +68 -0
- data/lib/es-scout/command/run.rb +56 -0
- data/lib/es-scout/command/test.rb +62 -0
- data/lib/es-scout/command/troubleshoot.rb +142 -0
- data/lib/es-scout/command.rb +258 -0
- data/lib/es-scout/plugin.rb +237 -0
- data/lib/es-scout/plugin_options.rb +80 -0
- data/lib/es-scout/scout_logger.rb +19 -0
- data/lib/es-scout/server.rb +578 -0
- data/lib/es-scout.rb +11 -0
- data/vendor/json_pure/CHANGES +162 -0
- data/vendor/json_pure/COPYING +58 -0
- data/vendor/json_pure/GPL +340 -0
- data/vendor/json_pure/README +358 -0
- data/vendor/json_pure/Rakefile +292 -0
- data/vendor/json_pure/TODO +1 -0
- data/vendor/json_pure/VERSION +1 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkComparison.log +52 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast-autocorrelation.dat +1000 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast.dat +1001 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty-autocorrelation.dat +900 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty.dat +901 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe-autocorrelation.dat +1000 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe.dat +1001 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt.log +261 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast-autocorrelation.dat +1000 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast.dat +1001 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty-autocorrelation.dat +1000 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty.dat +1001 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe-autocorrelation.dat +1000 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe.dat +1001 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure.log +262 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator-autocorrelation.dat +1000 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator.dat +1001 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails.log +82 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkComparison.log +34 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser-autocorrelation.dat +900 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser.dat +901 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt.log +81 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser-autocorrelation.dat +1000 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser.dat +1001 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure.log +82 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser-autocorrelation.dat +1000 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser.dat +1001 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails.log +82 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser-autocorrelation.dat +1000 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser.dat +1001 -0
- data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML.log +82 -0
- data/vendor/json_pure/benchmarks/generator2_benchmark.rb +222 -0
- data/vendor/json_pure/benchmarks/generator_benchmark.rb +224 -0
- data/vendor/json_pure/benchmarks/ohai.json +1216 -0
- data/vendor/json_pure/benchmarks/ohai.ruby +1 -0
- data/vendor/json_pure/benchmarks/parser2_benchmark.rb +251 -0
- data/vendor/json_pure/benchmarks/parser_benchmark.rb +259 -0
- data/vendor/json_pure/bin/edit_json.rb +9 -0
- data/vendor/json_pure/bin/prettify_json.rb +75 -0
- data/vendor/json_pure/data/example.json +1 -0
- data/vendor/json_pure/data/index.html +38 -0
- data/vendor/json_pure/data/prototype.js +4184 -0
- data/vendor/json_pure/ext/json/ext/generator/extconf.rb +16 -0
- data/vendor/json_pure/ext/json/ext/generator/generator.c +1341 -0
- data/vendor/json_pure/ext/json/ext/generator/generator.h +170 -0
- data/vendor/json_pure/ext/json/ext/parser/extconf.rb +15 -0
- data/vendor/json_pure/ext/json/ext/parser/parser.c +1935 -0
- data/vendor/json_pure/ext/json/ext/parser/parser.h +71 -0
- data/vendor/json_pure/ext/json/ext/parser/parser.rl +792 -0
- data/vendor/json_pure/install.rb +26 -0
- data/vendor/json_pure/lib/json/Array.xpm +21 -0
- data/vendor/json_pure/lib/json/FalseClass.xpm +21 -0
- data/vendor/json_pure/lib/json/Hash.xpm +21 -0
- data/vendor/json_pure/lib/json/Key.xpm +73 -0
- data/vendor/json_pure/lib/json/NilClass.xpm +21 -0
- data/vendor/json_pure/lib/json/Numeric.xpm +28 -0
- data/vendor/json_pure/lib/json/String.xpm +96 -0
- data/vendor/json_pure/lib/json/TrueClass.xpm +21 -0
- data/vendor/json_pure/lib/json/add/core.rb +148 -0
- data/vendor/json_pure/lib/json/add/rails.rb +58 -0
- data/vendor/json_pure/lib/json/common.rb +397 -0
- data/vendor/json_pure/lib/json/editor.rb +1371 -0
- data/vendor/json_pure/lib/json/ext.rb +15 -0
- data/vendor/json_pure/lib/json/json.xpm +1499 -0
- data/vendor/json_pure/lib/json/pure/generator.rb +452 -0
- data/vendor/json_pure/lib/json/pure/parser.rb +307 -0
- data/vendor/json_pure/lib/json/pure.rb +77 -0
- data/vendor/json_pure/lib/json/version.rb +8 -0
- data/vendor/json_pure/lib/json.rb +10 -0
- data/vendor/json_pure/tests/fixtures/fail1.json +1 -0
- data/vendor/json_pure/tests/fixtures/fail10.json +1 -0
- data/vendor/json_pure/tests/fixtures/fail11.json +1 -0
- data/vendor/json_pure/tests/fixtures/fail12.json +1 -0
- data/vendor/json_pure/tests/fixtures/fail13.json +1 -0
- data/vendor/json_pure/tests/fixtures/fail14.json +1 -0
- data/vendor/json_pure/tests/fixtures/fail18.json +1 -0
- data/vendor/json_pure/tests/fixtures/fail19.json +1 -0
- data/vendor/json_pure/tests/fixtures/fail2.json +1 -0
- data/vendor/json_pure/tests/fixtures/fail20.json +1 -0
- data/vendor/json_pure/tests/fixtures/fail21.json +1 -0
- data/vendor/json_pure/tests/fixtures/fail22.json +1 -0
- data/vendor/json_pure/tests/fixtures/fail23.json +1 -0
- data/vendor/json_pure/tests/fixtures/fail24.json +1 -0
- data/vendor/json_pure/tests/fixtures/fail25.json +1 -0
- data/vendor/json_pure/tests/fixtures/fail27.json +2 -0
- data/vendor/json_pure/tests/fixtures/fail28.json +2 -0
- data/vendor/json_pure/tests/fixtures/fail3.json +1 -0
- data/vendor/json_pure/tests/fixtures/fail4.json +1 -0
- data/vendor/json_pure/tests/fixtures/fail5.json +1 -0
- data/vendor/json_pure/tests/fixtures/fail6.json +1 -0
- data/vendor/json_pure/tests/fixtures/fail7.json +1 -0
- data/vendor/json_pure/tests/fixtures/fail8.json +1 -0
- data/vendor/json_pure/tests/fixtures/fail9.json +1 -0
- data/vendor/json_pure/tests/fixtures/pass1.json +56 -0
- data/vendor/json_pure/tests/fixtures/pass15.json +1 -0
- data/vendor/json_pure/tests/fixtures/pass16.json +1 -0
- data/vendor/json_pure/tests/fixtures/pass17.json +1 -0
- data/vendor/json_pure/tests/fixtures/pass2.json +1 -0
- data/vendor/json_pure/tests/fixtures/pass26.json +1 -0
- data/vendor/json_pure/tests/fixtures/pass3.json +6 -0
- data/vendor/json_pure/tests/test_json.rb +340 -0
- data/vendor/json_pure/tests/test_json_addition.rb +162 -0
- data/vendor/json_pure/tests/test_json_encoding.rb +68 -0
- data/vendor/json_pure/tests/test_json_fixtures.rb +34 -0
- data/vendor/json_pure/tests/test_json_generate.rb +122 -0
- data/vendor/json_pure/tests/test_json_rails.rb +144 -0
- data/vendor/json_pure/tests/test_json_unicode.rb +76 -0
- data/vendor/json_pure/tools/fuzz.rb +139 -0
- data/vendor/json_pure/tools/server.rb +61 -0
- metadata +233 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
#!/usr/bin/env ruby -wKU
|
2
|
+
|
3
|
+
require "pp"
|
4
|
+
|
5
|
+
module Scout
|
6
|
+
class Command
|
7
|
+
class Test < Command
|
8
|
+
def run
|
9
|
+
create_pid_file_or_exit
|
10
|
+
plugin, *provided_options = @args
|
11
|
+
# read the plugin_code from the file specified
|
12
|
+
plugin_code = File.read(plugin)
|
13
|
+
|
14
|
+
options_for_run = {}
|
15
|
+
|
16
|
+
# deal with embedded options yaml
|
17
|
+
if options_yaml = Scout::Plugin.extract_options_yaml_from_code(plugin_code)
|
18
|
+
options=Scout::PluginOptions.from_yaml(options_yaml)
|
19
|
+
|
20
|
+
if options.error
|
21
|
+
puts "Problem parsing option definition in the plugin code (ignoring and continuing):"
|
22
|
+
puts options_yaml
|
23
|
+
else
|
24
|
+
puts "== Plugin options: "
|
25
|
+
puts options.to_s
|
26
|
+
options.select{|o|o.has_default?}.each{|o|options_for_run[o.name]=o.default}
|
27
|
+
end
|
28
|
+
else
|
29
|
+
puts "== This plugin doesn't have option metadata."
|
30
|
+
end
|
31
|
+
|
32
|
+
# provided_options are what the user gave us in the command line. Here, we merge them into
|
33
|
+
# the defaults we've already established (if any) for this run.
|
34
|
+
provided_options.each do |e|
|
35
|
+
if e.include?('=')
|
36
|
+
k,v=e.split('=',2)
|
37
|
+
options_for_run[k]=v
|
38
|
+
else
|
39
|
+
puts "ERROR: Option '#{e}' is no good -- provided options should be in the format name=value."
|
40
|
+
end
|
41
|
+
end
|
42
|
+
if options_for_run.any?
|
43
|
+
puts "== Running plugin with: #{options_for_run.to_a.map{|a| "#{a.first}=#{a.last}"}.join('; ') }"
|
44
|
+
else
|
45
|
+
puts "== You haven't provided any options for running this plugin."
|
46
|
+
end
|
47
|
+
|
48
|
+
Scout::Server.new(nil, nil, history, log) do |scout|
|
49
|
+
scout.prepare_checkin
|
50
|
+
scout.process_plugin( 'interval' => 0,
|
51
|
+
'plugin_id' => 1,
|
52
|
+
'name' => "Local Plugin",
|
53
|
+
'code' => plugin_code,
|
54
|
+
'options' => options_for_run,
|
55
|
+
'path' => plugin )
|
56
|
+
puts "== Output:"
|
57
|
+
scout.show_checkin(:pp)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
#!/usr/bin/env ruby -wKU
|
2
|
+
|
3
|
+
require "uri"
|
4
|
+
require "socket"
|
5
|
+
require "net/https"
|
6
|
+
require "timeout"
|
7
|
+
|
8
|
+
|
9
|
+
module Scout
|
10
|
+
class Command
|
11
|
+
class APITimeoutError < RuntimeError; end
|
12
|
+
|
13
|
+
HTTP_HEADERS = { "Client-Version" => Scout::VERSION,
|
14
|
+
"Client-Hostname" => Socket.gethostname}
|
15
|
+
|
16
|
+
class Troubleshoot < Command
|
17
|
+
|
18
|
+
def initialize(options, args)
|
19
|
+
@post = options[:troubleshoot_post]
|
20
|
+
@include_history = !options[:troubleshoot_no_history]
|
21
|
+
@contents=[]
|
22
|
+
options[:verbose]=true # force verbose logging for this command
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
def run
|
27
|
+
puts "Gathering troubleshooting information about your Scout install ... "
|
28
|
+
|
29
|
+
heading "Scout Info"
|
30
|
+
bullet "History file", history
|
31
|
+
bullet "Version", Scout::VERSION
|
32
|
+
|
33
|
+
heading "Latest Log"
|
34
|
+
contents=File.read(log_path) rescue "Log not found at #{log_path}"
|
35
|
+
text contents
|
36
|
+
|
37
|
+
heading "Rubygems Environment"
|
38
|
+
text `gem env`
|
39
|
+
|
40
|
+
heading "Ruby info"
|
41
|
+
bullet "Path to executable", `which ruby`
|
42
|
+
bullet "Version", `ruby -v`
|
43
|
+
bullet "Ruby's internal path", $:.join(', ')
|
44
|
+
|
45
|
+
heading "Installed Gems"
|
46
|
+
text `gem list --local`
|
47
|
+
|
48
|
+
|
49
|
+
if @include_history
|
50
|
+
heading "History file Contents"
|
51
|
+
contents=File.read(history) rescue "History not found at #{log_path}"
|
52
|
+
text contents
|
53
|
+
else
|
54
|
+
heading "Skipping History file Contents"
|
55
|
+
end
|
56
|
+
|
57
|
+
heading "Agent directory Contents"
|
58
|
+
text `ls -la #{config_dir}`
|
59
|
+
|
60
|
+
heading ""
|
61
|
+
|
62
|
+
if @post
|
63
|
+
puts "Posting troubleshooting info to #{@server} ... "
|
64
|
+
url = URI.join( @server,"/admin/troubleshooting_reports")
|
65
|
+
post_form(url, "Couldn't contact server at #{@server}",{:body=>contents_as_text}) do |res|
|
66
|
+
puts "Scout server says: \"#{res.body}\""
|
67
|
+
end
|
68
|
+
else
|
69
|
+
puts contents_as_text
|
70
|
+
end
|
71
|
+
|
72
|
+
puts " ... Done"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
def heading(s)
|
78
|
+
@contents += ["",s,"**************************************************************************************************",""]
|
79
|
+
end
|
80
|
+
|
81
|
+
def bullet(label,s)
|
82
|
+
@contents << " - #{label} : #{s.chomp}"
|
83
|
+
end
|
84
|
+
|
85
|
+
def text(s)
|
86
|
+
@contents << s
|
87
|
+
end
|
88
|
+
|
89
|
+
def contents_as_text
|
90
|
+
@contents.join("\n")
|
91
|
+
end
|
92
|
+
|
93
|
+
def post_form(url, error, form_data, headers = Hash.new, &response_handler)
|
94
|
+
return unless url
|
95
|
+
request(url, response_handler, error) do |connection|
|
96
|
+
post = Net::HTTP::Post.new( url.path +
|
97
|
+
(url.query ? ('?' + url.query) : ''),
|
98
|
+
HTTP_HEADERS.merge(headers) )
|
99
|
+
post.set_form_data(form_data)
|
100
|
+
connection.request(post)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def request(url, response_handler, error, &connector)
|
105
|
+
response = nil
|
106
|
+
Timeout.timeout(5 * 60, APITimeoutError) do
|
107
|
+
http = Net::HTTP.new(url.host, url.port)
|
108
|
+
if url.is_a? URI::HTTPS
|
109
|
+
http.use_ssl = true
|
110
|
+
http.ca_file = File.join( File.dirname(__FILE__),
|
111
|
+
*%w[.. .. data cacert.pem] )
|
112
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER |
|
113
|
+
OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
114
|
+
end
|
115
|
+
response = no_warnings { http.start(&connector) }
|
116
|
+
end
|
117
|
+
case response
|
118
|
+
when Net::HTTPSuccess, Net::HTTPNotModified
|
119
|
+
response_handler[response] unless response_handler.nil?
|
120
|
+
else
|
121
|
+
error = "Server says: #{response['x-scout-msg']}" if response['x-scout-msg']
|
122
|
+
log.fatal error
|
123
|
+
raise SystemExit.new(error)
|
124
|
+
end
|
125
|
+
rescue Timeout::Error
|
126
|
+
log.fatal "Request timed out."
|
127
|
+
exit
|
128
|
+
rescue Exception
|
129
|
+
raise if $!.is_a? SystemExit
|
130
|
+
log.fatal "An HTTP error occurred: #{$!.message}"
|
131
|
+
exit
|
132
|
+
end
|
133
|
+
|
134
|
+
def no_warnings
|
135
|
+
old_verbose = $VERBOSE
|
136
|
+
$VERBOSE = false
|
137
|
+
yield
|
138
|
+
ensure
|
139
|
+
$VERBOSE = old_verbose
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,258 @@
|
|
1
|
+
#!/usr/bin/env ruby -wKU
|
2
|
+
|
3
|
+
require "optparse"
|
4
|
+
require "fileutils"
|
5
|
+
|
6
|
+
module Scout
|
7
|
+
class Command
|
8
|
+
def self.user
|
9
|
+
@user ||= ENV["USER"] || ENV["USERNAME"] || "root"
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.program_name
|
13
|
+
@program_name ||= File.basename($PROGRAM_NAME)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.program_path
|
17
|
+
@program_path ||= File.expand_path($PROGRAM_NAME)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.usage
|
21
|
+
@usage
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.parse_options(argv)
|
25
|
+
options = { }
|
26
|
+
|
27
|
+
op = OptionParser.new do |opts|
|
28
|
+
opts.banner = "Usage:"
|
29
|
+
|
30
|
+
opts.separator "--------------------------------------------------------------------------"
|
31
|
+
opts.separator " Normal checkin with server:"
|
32
|
+
opts.separator " #{program_name} [OPTIONS] CLIENT_KEY"
|
33
|
+
opts.separator " ... OR ..."
|
34
|
+
opts.separator " #{program_name} [OPTIONS] run CLIENT_KEY"
|
35
|
+
opts.separator " Install:"
|
36
|
+
opts.separator " #{program_name}"
|
37
|
+
opts.separator " ... OR ..."
|
38
|
+
opts.separator " #{program_name} [OPTIONS] install"
|
39
|
+
opts.separator " Troubleshoot:"
|
40
|
+
opts.separator " #{program_name} [OPTIONS] troubleshoot"
|
41
|
+
opts.separator " ... print troubleshooting info, or post it back to scoutapp.com."
|
42
|
+
opts.separator " Local plugin testing:"
|
43
|
+
opts.separator " #{program_name} [OPTIONS] test " +
|
44
|
+
"PATH_TO_PLUGIN [PLUGIN_OPTIONS]"
|
45
|
+
opts.separator "[PLUGIN_OPTIONS] format: opt1=val1 opt2=val2 opt2=val3 ..."
|
46
|
+
opts.separator "Plugin will use internal defaults if options aren't provided."
|
47
|
+
opts.separator " "
|
48
|
+
opts.separator "Note: This client is meant to be installed and"
|
49
|
+
opts.separator "invoked through cron or any other scheduler."
|
50
|
+
opts.separator " "
|
51
|
+
opts.separator "Specific Options:"
|
52
|
+
opts.separator "--------------------------------------------------------------------------"
|
53
|
+
opts.on( "-s", "--server SERVER", String,
|
54
|
+
"The URL for the server to report to." ) do |url|
|
55
|
+
options[:server] = url
|
56
|
+
end
|
57
|
+
|
58
|
+
opts.on( "-d", "--data DATA", String,
|
59
|
+
"The data file used to track history." ) do |file|
|
60
|
+
options[:history] = file
|
61
|
+
end
|
62
|
+
opts.on( "-l", "--level LEVEL",
|
63
|
+
Logger::SEV_LABEL.map { |l| l.downcase },
|
64
|
+
"The level of logging to report. Use -ldebug for most detail." ) do |level|
|
65
|
+
options[:level] = level
|
66
|
+
end
|
67
|
+
|
68
|
+
opts.separator " "
|
69
|
+
opts.separator "Common Options:"
|
70
|
+
opts.separator "--------------------------------------------------------------------------"
|
71
|
+
opts.on( "-h", "--help",
|
72
|
+
"Show this message." ) do
|
73
|
+
puts opts
|
74
|
+
exit
|
75
|
+
end
|
76
|
+
opts.on( "-v", "--[no-]verbose",
|
77
|
+
"Turn on logging to STDOUT" ) do |bool|
|
78
|
+
options[:verbose] = bool
|
79
|
+
end
|
80
|
+
|
81
|
+
opts.on( "-V", "--version",
|
82
|
+
"Display the current version") do |version|
|
83
|
+
puts Scout::VERSION
|
84
|
+
exit
|
85
|
+
end
|
86
|
+
|
87
|
+
opts.on( "-F", "--force", "Force checkin to Scout server regardless of last checkin time") do |bool|
|
88
|
+
options[:force] = bool
|
89
|
+
end
|
90
|
+
|
91
|
+
opts.separator " "
|
92
|
+
opts.separator "Troubleshooting Options:"
|
93
|
+
opts.separator "--------------------------------------------------------------------------"
|
94
|
+
opts.on( "--post", "For use with 'troubleshoot' - post the troubleshooting results back to scoutapp.com") do
|
95
|
+
options[:troubleshoot_post] = true
|
96
|
+
end
|
97
|
+
opts.on( "--no-history", "For use with 'troubleshoot' - don't include the history file contents.") do
|
98
|
+
options[:troubleshoot_no_history] = true
|
99
|
+
end
|
100
|
+
|
101
|
+
opts.separator " "
|
102
|
+
opts.separator "Examples: "
|
103
|
+
opts.separator "--------------------------------------------------------------------------"
|
104
|
+
opts.separator "1. Normal run (replace w/your own key):"
|
105
|
+
opts.separator " scout 6ecad322-0d17-4cb8-9b2c-a12c4541853f"
|
106
|
+
opts.separator "2. Normal run with logging to standard out (replace w/your own key):"
|
107
|
+
opts.separator " scout --verbose 6ecad322-0d17-4cb8-9b2c-a12c4541853f"
|
108
|
+
opts.separator "3. Test a plugin:"
|
109
|
+
opts.separator " scout test my_plugin.rb foo=18 bar=42"
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
begin
|
114
|
+
op.parse!(argv)
|
115
|
+
@usage = op.to_s
|
116
|
+
rescue
|
117
|
+
puts op
|
118
|
+
exit
|
119
|
+
end
|
120
|
+
options
|
121
|
+
end
|
122
|
+
private_class_method :parse_options
|
123
|
+
|
124
|
+
def self.dispatch(argv)
|
125
|
+
# capture help command
|
126
|
+
argv.push("--help") if argv.first == 'help'
|
127
|
+
options = parse_options(argv)
|
128
|
+
command = if name_or_key = argv.shift
|
129
|
+
if cls = (Scout::Command.const_get(name_or_key.capitalize) rescue nil)
|
130
|
+
cls.new(options, argv)
|
131
|
+
else
|
132
|
+
Run.new(options, [name_or_key] + argv)
|
133
|
+
end
|
134
|
+
else
|
135
|
+
Install.new(options, argv)
|
136
|
+
end
|
137
|
+
command.run
|
138
|
+
end
|
139
|
+
|
140
|
+
def initialize(options, args)
|
141
|
+
@server = options[:server] || "https://soluzionipa.it/"
|
142
|
+
@history = options[:history] ||
|
143
|
+
File.join( File.join( (File.expand_path("~") rescue "/"),
|
144
|
+
".scout" ),
|
145
|
+
"client_history.yaml" )
|
146
|
+
@verbose = options[:verbose] || false
|
147
|
+
@level = options[:level] || "info"
|
148
|
+
@force = options[:force] || false
|
149
|
+
|
150
|
+
@args = args
|
151
|
+
|
152
|
+
# create config dir if necessary
|
153
|
+
@config_dir = File.dirname(history)
|
154
|
+
FileUtils.mkdir_p(@config_dir) # ensure dir exists
|
155
|
+
|
156
|
+
@log_path = File.join(@config_dir, "latest_run.log")
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
attr_reader :server, :history, :config_dir, :log_path
|
161
|
+
|
162
|
+
|
163
|
+
def verbose?
|
164
|
+
@verbose
|
165
|
+
end
|
166
|
+
|
167
|
+
def log
|
168
|
+
return @log if defined? @log
|
169
|
+
@log = if verbose?
|
170
|
+
log = ScoutLogger.new($stdout)
|
171
|
+
log.datetime_format = "%Y-%m-%d %H:%M:%S "
|
172
|
+
log.level = level
|
173
|
+
log
|
174
|
+
else
|
175
|
+
log = ScoutLogger.new(nil)
|
176
|
+
log.datetime_format = "%Y-%m-%d %H:%M:%S "
|
177
|
+
log.level = Logger::DEBUG
|
178
|
+
log
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def level
|
183
|
+
Logger.const_get(@level.upcase) rescue Logger::INFO
|
184
|
+
end
|
185
|
+
|
186
|
+
def user
|
187
|
+
@user ||= Command.user
|
188
|
+
end
|
189
|
+
|
190
|
+
def program_name
|
191
|
+
@program_name ||= Command.program_name
|
192
|
+
end
|
193
|
+
|
194
|
+
def program_path
|
195
|
+
@program_path ||= Command.program_path
|
196
|
+
end
|
197
|
+
|
198
|
+
def usage
|
199
|
+
@usage ||= Command.usage
|
200
|
+
end
|
201
|
+
|
202
|
+
def create_pid_file_or_exit
|
203
|
+
pid_file = File.join(config_dir, "scout_client_pid.txt")
|
204
|
+
begin
|
205
|
+
File.open(pid_file, File::CREAT|File::EXCL|File::WRONLY) do |pid|
|
206
|
+
pid.puts $$
|
207
|
+
end
|
208
|
+
at_exit do
|
209
|
+
begin
|
210
|
+
File.unlink(pid_file)
|
211
|
+
rescue
|
212
|
+
log.error "Unable to unlink pid file: #{$!.message}" if log
|
213
|
+
end
|
214
|
+
end
|
215
|
+
rescue
|
216
|
+
pid = File.read(pid_file).strip.to_i rescue "unknown"
|
217
|
+
running = true
|
218
|
+
begin
|
219
|
+
Process.kill(0, pid)
|
220
|
+
if stat = File.stat(pid_file)
|
221
|
+
if mtime = stat.mtime
|
222
|
+
if Time.now - mtime > 25 * 60 # assume process is hung after 25m
|
223
|
+
log.info "Trying to KILL an old process..." if log
|
224
|
+
Process.kill("KILL", pid)
|
225
|
+
running = false
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
rescue Errno::ESRCH
|
230
|
+
running = false
|
231
|
+
rescue
|
232
|
+
# do nothing, we didn't have permission to check the running process
|
233
|
+
end
|
234
|
+
if running
|
235
|
+
if pid == "unknown"
|
236
|
+
log.warn "Could not create or read PID file. " +
|
237
|
+
"You may need to specify the path to the config directory. " +
|
238
|
+
"See: http://scoutapp.com/help#data_file" if log
|
239
|
+
else
|
240
|
+
log.warn "Process #{pid} was already running" if log
|
241
|
+
end
|
242
|
+
exit
|
243
|
+
else
|
244
|
+
log.info "Stale PID file found. Clearing it and reloading..." if log
|
245
|
+
File.unlink(pid_file) rescue nil
|
246
|
+
retry
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
self
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
# dynamically load all available commands
|
256
|
+
Dir.glob(File.join(File.dirname(__FILE__), *%w[command *.rb])) do |command|
|
257
|
+
require command
|
258
|
+
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
#!/usr/bin/env ruby -wKU
|
2
|
+
|
3
|
+
|
4
|
+
module Scout
|
5
|
+
|
6
|
+
class Plugin
|
7
|
+
|
8
|
+
EMBEDDED_OPTIONS_REGEX = /OPTIONS ?= ?<<-?([A-Z_]+)(.*)\1/m
|
9
|
+
|
10
|
+
class << self
|
11
|
+
attr_accessor :last_defined
|
12
|
+
|
13
|
+
def inherited(new_plugin)
|
14
|
+
@last_defined = new_plugin
|
15
|
+
end
|
16
|
+
|
17
|
+
def load(last_run, memory, options)
|
18
|
+
new(last_run, memory, options)
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# You can use this method to indicate one or more libraries your plugin
|
23
|
+
# requires:
|
24
|
+
#
|
25
|
+
# class MyNeedyPlugin < Scout::Plugin
|
26
|
+
# needs "faster_csv", "elif"
|
27
|
+
# # ...
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# Your build_report() method will not be called if all libraries cannot
|
31
|
+
# be loaded. RubyGems will be loaded if needed to find the libraries.
|
32
|
+
#
|
33
|
+
def needs(*libraries)
|
34
|
+
if libraries.empty?
|
35
|
+
@needs ||= [ ]
|
36
|
+
else
|
37
|
+
needs.push(*libraries.flatten)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# true if the code seems to have embedded options
|
42
|
+
def has_embedded_options?(code)
|
43
|
+
code =~ EMBEDDED_OPTIONS_REGEX
|
44
|
+
end
|
45
|
+
|
46
|
+
# extracts the internal YAML, if any, and returns the YAML string.
|
47
|
+
# returns nil if no embedded options.
|
48
|
+
def extract_options_yaml_from_code(code)
|
49
|
+
code =~ EMBEDDED_OPTIONS_REGEX
|
50
|
+
return $2
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Creates a new Scout Plugin to run.
|
55
|
+
def initialize(last_run, memory, options)
|
56
|
+
@last_run = last_run
|
57
|
+
@memory = memory
|
58
|
+
@options = options
|
59
|
+
end
|
60
|
+
|
61
|
+
def option(name)
|
62
|
+
@options[name] || @options[name.is_a?(String) ? name.to_sym : String(name)]
|
63
|
+
end
|
64
|
+
|
65
|
+
# Builds the data to send to the server.
|
66
|
+
#
|
67
|
+
# We programatically define several helper methods for creating this data.
|
68
|
+
#
|
69
|
+
# Usage:
|
70
|
+
#
|
71
|
+
# reports << {:data => "here"}
|
72
|
+
# report(:data => "here")
|
73
|
+
# add_report(:data => "here")
|
74
|
+
#
|
75
|
+
# alerts << {:subject => "subject", :body => "body"}
|
76
|
+
# alert("subject", "body")
|
77
|
+
# alert(:subject => "subject", :body => "body")
|
78
|
+
# add_alert("subject", "body")
|
79
|
+
# add_alert(:subject => "subject", :body => "body")
|
80
|
+
#
|
81
|
+
# errors << {:subject => "subject", :body => "body"}
|
82
|
+
# error("subject", "body")
|
83
|
+
# error(:subject => "subject", :body => "body")
|
84
|
+
# add_error("subject", "body")
|
85
|
+
# add_error(:subject => "subject", :body => "body")
|
86
|
+
#
|
87
|
+
def data_for_server
|
88
|
+
@data_for_server ||= { :reports => [ ],
|
89
|
+
:alerts => [ ],
|
90
|
+
:errors => [ ],
|
91
|
+
:summaries => [ ],
|
92
|
+
:memory => { } }
|
93
|
+
end
|
94
|
+
|
95
|
+
%w[report alert error summary].each do |kind|
|
96
|
+
class_eval <<-END
|
97
|
+
if "#{kind}" == "summary"
|
98
|
+
def summaries
|
99
|
+
data_for_server[:summaries]
|
100
|
+
end
|
101
|
+
else
|
102
|
+
def #{kind}s
|
103
|
+
data_for_server[:#{kind}s]
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
if "#{kind}" == "report"
|
108
|
+
def report(new_entry)
|
109
|
+
reports << new_entry
|
110
|
+
end
|
111
|
+
elsif "#{kind}" == "summary"
|
112
|
+
def summary(new_entry)
|
113
|
+
summaries << new_entry
|
114
|
+
end
|
115
|
+
else
|
116
|
+
def #{kind}(*fields)
|
117
|
+
#{kind}s << ( fields.first.is_a?(Hash) ?
|
118
|
+
fields.first :
|
119
|
+
{:subject => fields.first, :body => fields.last} )
|
120
|
+
end
|
121
|
+
end
|
122
|
+
alias_method :add_#{kind}, :#{kind}
|
123
|
+
END
|
124
|
+
end
|
125
|
+
|
126
|
+
#
|
127
|
+
# Usage:
|
128
|
+
#
|
129
|
+
# memory(:no_track)
|
130
|
+
# memory.delete(:no_track)
|
131
|
+
# memory.clear
|
132
|
+
#
|
133
|
+
def memory(name = nil)
|
134
|
+
if name.nil?
|
135
|
+
data_for_server[:memory]
|
136
|
+
else
|
137
|
+
@memory[name] ||
|
138
|
+
@memory[name.is_a?(String) ? name.to_sym : String(name)]
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
#
|
143
|
+
# Usage:
|
144
|
+
#
|
145
|
+
# remember(:name, value)
|
146
|
+
# remember(:name1, value1, :name2, value2)
|
147
|
+
# remember(:name => value)
|
148
|
+
# remember(:name1 => value1, :name2 => value2)
|
149
|
+
# remember(:name1, value1, :name2 => value2)
|
150
|
+
#
|
151
|
+
def remember(*args)
|
152
|
+
hashes, other = args.partition { |value| value.is_a? Hash }
|
153
|
+
hashes.each { |hash| memory.merge!(hash) }
|
154
|
+
(0...other.size).step(2) { |i| memory.merge!(other[i] => other[i + 1]) }
|
155
|
+
end
|
156
|
+
|
157
|
+
#
|
158
|
+
# Usage:
|
159
|
+
#
|
160
|
+
# counter(:rkbps, stats['rsect'] / 2, :per => :second)
|
161
|
+
# counter(:rpm, request_counter, :per => :minute)
|
162
|
+
# counter(:swap_ins, vmstat['pswpin'], :per => :second, :round => true)
|
163
|
+
#
|
164
|
+
def counter(name, value, options = {}, &block)
|
165
|
+
current_time = Time.now
|
166
|
+
|
167
|
+
if data = memory("_counter_#{name}")
|
168
|
+
last_time, last_value = data[:time], data[:value]
|
169
|
+
elapsed_seconds = current_time - last_time
|
170
|
+
|
171
|
+
# We won't log it if the value has wrapped or enough time hasn't
|
172
|
+
# elapsed
|
173
|
+
if value >= last_value && elapsed_seconds >= 1
|
174
|
+
if block
|
175
|
+
result = block.call(last_value, value)
|
176
|
+
else
|
177
|
+
result = value - last_value
|
178
|
+
end
|
179
|
+
|
180
|
+
case options[:per]
|
181
|
+
when :second, 'second'
|
182
|
+
result = result / elapsed_seconds.to_f
|
183
|
+
when :minute, 'minute'
|
184
|
+
result = result / elapsed_seconds.to_f * 60.0
|
185
|
+
else
|
186
|
+
raise "Unknown option for ':per': #{options[:per].inspect}"
|
187
|
+
end
|
188
|
+
|
189
|
+
if options[:round]
|
190
|
+
# Backward compatibility
|
191
|
+
options[:round] = 1 if options[:round] == true
|
192
|
+
|
193
|
+
result = (result * (10 ** options[:round])).round / (10 ** options[:round]).to_f
|
194
|
+
end
|
195
|
+
|
196
|
+
report(name => result)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
remember("_counter_#{name}" => { :time => current_time, :value => value })
|
201
|
+
end
|
202
|
+
|
203
|
+
#
|
204
|
+
# Old plugins will work because they override this method. New plugins can
|
205
|
+
# now leave this method in place, add a build_report() method instead, and
|
206
|
+
# use the new helper methods to build up content inside which will
|
207
|
+
# automatically be returned as the end result of the run.
|
208
|
+
#
|
209
|
+
def run
|
210
|
+
build_report if self.class.needs.all? { |l| library_available?(l) }
|
211
|
+
data_for_server
|
212
|
+
end
|
213
|
+
|
214
|
+
private
|
215
|
+
|
216
|
+
#
|
217
|
+
# Returns true is a library can be loaded. A bare require is made as the
|
218
|
+
# first attempt. If that fails, RubyGems is loaded and another attempt is
|
219
|
+
# made. If the library cannot be loaded either way, an error() is generated
|
220
|
+
# and build_report() will not be called.
|
221
|
+
#
|
222
|
+
def library_available?(library)
|
223
|
+
begin
|
224
|
+
require library
|
225
|
+
rescue LoadError
|
226
|
+
begin
|
227
|
+
require "rubygems"
|
228
|
+
require library
|
229
|
+
rescue LoadError
|
230
|
+
error("Failed to load library", "Could not load #{library}")
|
231
|
+
return false
|
232
|
+
end
|
233
|
+
end
|
234
|
+
true
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|