es-scout 5.3.0.es1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (140) hide show
  1. data/AUTHORS +4 -0
  2. data/CHANGELOG +225 -0
  3. data/COPYING +340 -0
  4. data/INSTALL +18 -0
  5. data/LICENSE +6 -0
  6. data/README +66 -0
  7. data/Rakefile +74 -0
  8. data/TODO +6 -0
  9. data/bin/es-scout +10 -0
  10. data/data/cacert.pem +3154 -0
  11. data/data/code_key.pub +13 -0
  12. data/data/gpl-2.0.txt +339 -0
  13. data/data/lgpl-2.1.txt +504 -0
  14. data/lib/es-scout/command/install.rb +68 -0
  15. data/lib/es-scout/command/run.rb +56 -0
  16. data/lib/es-scout/command/test.rb +62 -0
  17. data/lib/es-scout/command/troubleshoot.rb +142 -0
  18. data/lib/es-scout/command.rb +258 -0
  19. data/lib/es-scout/plugin.rb +237 -0
  20. data/lib/es-scout/plugin_options.rb +80 -0
  21. data/lib/es-scout/scout_logger.rb +19 -0
  22. data/lib/es-scout/server.rb +578 -0
  23. data/lib/es-scout.rb +11 -0
  24. data/vendor/json_pure/CHANGES +162 -0
  25. data/vendor/json_pure/COPYING +58 -0
  26. data/vendor/json_pure/GPL +340 -0
  27. data/vendor/json_pure/README +358 -0
  28. data/vendor/json_pure/Rakefile +292 -0
  29. data/vendor/json_pure/TODO +1 -0
  30. data/vendor/json_pure/VERSION +1 -0
  31. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkComparison.log +52 -0
  32. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast-autocorrelation.dat +1000 -0
  33. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast.dat +1001 -0
  34. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty-autocorrelation.dat +900 -0
  35. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty.dat +901 -0
  36. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe-autocorrelation.dat +1000 -0
  37. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe.dat +1001 -0
  38. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt.log +261 -0
  39. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast-autocorrelation.dat +1000 -0
  40. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast.dat +1001 -0
  41. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty-autocorrelation.dat +1000 -0
  42. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty.dat +1001 -0
  43. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe-autocorrelation.dat +1000 -0
  44. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe.dat +1001 -0
  45. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure.log +262 -0
  46. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator-autocorrelation.dat +1000 -0
  47. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator.dat +1001 -0
  48. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails.log +82 -0
  49. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkComparison.log +34 -0
  50. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser-autocorrelation.dat +900 -0
  51. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser.dat +901 -0
  52. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt.log +81 -0
  53. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser-autocorrelation.dat +1000 -0
  54. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser.dat +1001 -0
  55. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure.log +82 -0
  56. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser-autocorrelation.dat +1000 -0
  57. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser.dat +1001 -0
  58. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails.log +82 -0
  59. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser-autocorrelation.dat +1000 -0
  60. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser.dat +1001 -0
  61. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML.log +82 -0
  62. data/vendor/json_pure/benchmarks/generator2_benchmark.rb +222 -0
  63. data/vendor/json_pure/benchmarks/generator_benchmark.rb +224 -0
  64. data/vendor/json_pure/benchmarks/ohai.json +1216 -0
  65. data/vendor/json_pure/benchmarks/ohai.ruby +1 -0
  66. data/vendor/json_pure/benchmarks/parser2_benchmark.rb +251 -0
  67. data/vendor/json_pure/benchmarks/parser_benchmark.rb +259 -0
  68. data/vendor/json_pure/bin/edit_json.rb +9 -0
  69. data/vendor/json_pure/bin/prettify_json.rb +75 -0
  70. data/vendor/json_pure/data/example.json +1 -0
  71. data/vendor/json_pure/data/index.html +38 -0
  72. data/vendor/json_pure/data/prototype.js +4184 -0
  73. data/vendor/json_pure/ext/json/ext/generator/extconf.rb +16 -0
  74. data/vendor/json_pure/ext/json/ext/generator/generator.c +1341 -0
  75. data/vendor/json_pure/ext/json/ext/generator/generator.h +170 -0
  76. data/vendor/json_pure/ext/json/ext/parser/extconf.rb +15 -0
  77. data/vendor/json_pure/ext/json/ext/parser/parser.c +1935 -0
  78. data/vendor/json_pure/ext/json/ext/parser/parser.h +71 -0
  79. data/vendor/json_pure/ext/json/ext/parser/parser.rl +792 -0
  80. data/vendor/json_pure/install.rb +26 -0
  81. data/vendor/json_pure/lib/json/Array.xpm +21 -0
  82. data/vendor/json_pure/lib/json/FalseClass.xpm +21 -0
  83. data/vendor/json_pure/lib/json/Hash.xpm +21 -0
  84. data/vendor/json_pure/lib/json/Key.xpm +73 -0
  85. data/vendor/json_pure/lib/json/NilClass.xpm +21 -0
  86. data/vendor/json_pure/lib/json/Numeric.xpm +28 -0
  87. data/vendor/json_pure/lib/json/String.xpm +96 -0
  88. data/vendor/json_pure/lib/json/TrueClass.xpm +21 -0
  89. data/vendor/json_pure/lib/json/add/core.rb +148 -0
  90. data/vendor/json_pure/lib/json/add/rails.rb +58 -0
  91. data/vendor/json_pure/lib/json/common.rb +397 -0
  92. data/vendor/json_pure/lib/json/editor.rb +1371 -0
  93. data/vendor/json_pure/lib/json/ext.rb +15 -0
  94. data/vendor/json_pure/lib/json/json.xpm +1499 -0
  95. data/vendor/json_pure/lib/json/pure/generator.rb +452 -0
  96. data/vendor/json_pure/lib/json/pure/parser.rb +307 -0
  97. data/vendor/json_pure/lib/json/pure.rb +77 -0
  98. data/vendor/json_pure/lib/json/version.rb +8 -0
  99. data/vendor/json_pure/lib/json.rb +10 -0
  100. data/vendor/json_pure/tests/fixtures/fail1.json +1 -0
  101. data/vendor/json_pure/tests/fixtures/fail10.json +1 -0
  102. data/vendor/json_pure/tests/fixtures/fail11.json +1 -0
  103. data/vendor/json_pure/tests/fixtures/fail12.json +1 -0
  104. data/vendor/json_pure/tests/fixtures/fail13.json +1 -0
  105. data/vendor/json_pure/tests/fixtures/fail14.json +1 -0
  106. data/vendor/json_pure/tests/fixtures/fail18.json +1 -0
  107. data/vendor/json_pure/tests/fixtures/fail19.json +1 -0
  108. data/vendor/json_pure/tests/fixtures/fail2.json +1 -0
  109. data/vendor/json_pure/tests/fixtures/fail20.json +1 -0
  110. data/vendor/json_pure/tests/fixtures/fail21.json +1 -0
  111. data/vendor/json_pure/tests/fixtures/fail22.json +1 -0
  112. data/vendor/json_pure/tests/fixtures/fail23.json +1 -0
  113. data/vendor/json_pure/tests/fixtures/fail24.json +1 -0
  114. data/vendor/json_pure/tests/fixtures/fail25.json +1 -0
  115. data/vendor/json_pure/tests/fixtures/fail27.json +2 -0
  116. data/vendor/json_pure/tests/fixtures/fail28.json +2 -0
  117. data/vendor/json_pure/tests/fixtures/fail3.json +1 -0
  118. data/vendor/json_pure/tests/fixtures/fail4.json +1 -0
  119. data/vendor/json_pure/tests/fixtures/fail5.json +1 -0
  120. data/vendor/json_pure/tests/fixtures/fail6.json +1 -0
  121. data/vendor/json_pure/tests/fixtures/fail7.json +1 -0
  122. data/vendor/json_pure/tests/fixtures/fail8.json +1 -0
  123. data/vendor/json_pure/tests/fixtures/fail9.json +1 -0
  124. data/vendor/json_pure/tests/fixtures/pass1.json +56 -0
  125. data/vendor/json_pure/tests/fixtures/pass15.json +1 -0
  126. data/vendor/json_pure/tests/fixtures/pass16.json +1 -0
  127. data/vendor/json_pure/tests/fixtures/pass17.json +1 -0
  128. data/vendor/json_pure/tests/fixtures/pass2.json +1 -0
  129. data/vendor/json_pure/tests/fixtures/pass26.json +1 -0
  130. data/vendor/json_pure/tests/fixtures/pass3.json +6 -0
  131. data/vendor/json_pure/tests/test_json.rb +340 -0
  132. data/vendor/json_pure/tests/test_json_addition.rb +162 -0
  133. data/vendor/json_pure/tests/test_json_encoding.rb +68 -0
  134. data/vendor/json_pure/tests/test_json_fixtures.rb +34 -0
  135. data/vendor/json_pure/tests/test_json_generate.rb +122 -0
  136. data/vendor/json_pure/tests/test_json_rails.rb +144 -0
  137. data/vendor/json_pure/tests/test_json_unicode.rb +76 -0
  138. data/vendor/json_pure/tools/fuzz.rb +139 -0
  139. data/vendor/json_pure/tools/server.rb +61 -0
  140. 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