scout_agent 3.2.2 → 3.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -27,9 +27,9 @@ require "scout_agent/dispatcher"
27
27
  require "scout_agent/api"
28
28
 
29
29
  # require gems
30
- require_lib_or_gem "json", "=1.1.4"
30
+ require_lib_or_gem "json", "=1.1.6"
31
31
  require_lib_or_gem "amalgalite", "=0.9.0"
32
- require_lib_or_gem "rest_client", "=0.9.2"
32
+ require_lib_or_gem "rest_client", "=1.0"
33
33
  require_lib_or_gem "xmpp4r", "=0.4"
34
34
  require_lib_or_gem "xmpp4r/roster" # loads from xmpp4r's version
35
35
 
@@ -92,7 +92,7 @@ module ScoutAgent
92
92
  end
93
93
 
94
94
  # The version of this agent.
95
- VERSION = "3.2.2".freeze
95
+ VERSION = "3.2.3".freeze
96
96
  # A Pathname reference to the agent code directory, used in dynamic loading.
97
97
  LIB_DIR = Pathname.new(File.dirname(__FILE__)) + agent_name
98
98
  end
@@ -17,6 +17,21 @@ module ScoutAgent
17
17
  # databases and cleaning out old log files.
18
18
  #
19
19
  class MasterAgent < Agent
20
+ #
21
+ # These are the error codes and descriptions for failure conditions the
22
+ # mission process may not be able to report.
23
+ #
24
+ MISSION_ERRORS = { 76 => "was already running",
25
+ 16 => "couldn't be compiled",
26
+ 6 => "couldn't be loaded" }
27
+ #
28
+ # These are the +MISSION_ERRORS+ by name (the last word of the description
29
+ # as a Symbol).
30
+ #
31
+ MISSION_ERROR_NAMES = Hash[ *MISSION_ERRORS.map { |code, name|
32
+ [name[/\S+\z/].to_sym, code]
33
+ }.flatten ]
34
+
20
35
  #
21
36
  # Prepares the primary event loop for execution. The main function at
22
37
  # this point is to ensure that we can load all of the needed databases.
@@ -182,13 +197,26 @@ module ScoutAgent
182
197
  end
183
198
  @mission_pid = nil
184
199
  unless $?.success? # record that the Mission exited with an error
200
+ error_status = $?.exitstatus
185
201
  log.warn( "#{mission[:name]} exited with an error: " +
186
- "#{$?.exitstatus}." )
202
+ "#{error_status}." )
203
+ body = "Exit status: #{error_status}"
204
+ if description = MISSION_ERRORS[error_status]
205
+ body << <<-END_ERROR_DESCRIPTION
206
+
207
+
208
+ This error often means that a mission #{description}.
209
+ This can be a natural function of the agent cleaning up after
210
+ itself and it shouldn't be any cause for alarm if just see it
211
+ now and then. However, if you are seeing this error a lot,
212
+ please contact Scout support.
213
+ END_ERROR_DESCRIPTION
214
+ end
187
215
  @db.write_report(
188
216
  mission[:id],
189
217
  :error,
190
218
  :subject => "#{mission[:name]} exited with an error",
191
- :body => "Exit status: #{$?.exitstatus}"
219
+ :body => body
192
220
  )
193
221
  end
194
222
  rescue Timeout::Error # Mission exceeded allowed execution
@@ -345,7 +373,7 @@ module ScoutAgent
345
373
 
346
374
  # clear the parent's identity and assume mine
347
375
  IDCard.me = nil
348
- IDCard.new(:mission).authorize or exit(1)
376
+ IDCard.new(:mission).authorize or exit(MISSION_ERROR_NAMES[:running])
349
377
 
350
378
  # get a handle on the log
351
379
  @log = ScoutAgent.prepare_wire_tap(:mission)
@@ -373,7 +401,8 @@ module ScoutAgent
373
401
  :subject => "#{mission[:name]} could not be compiled",
374
402
  :body => "#{error.message}\n#{error.backtrace.join("\n")}"
375
403
  )
376
- exit(reported ? 0 : 2) # warn parent if we can't report
404
+ # warn parent if we can't report
405
+ exit(reported ? 0 : MISSION_ERROR_NAMES[:compiled])
377
406
  end
378
407
  end
379
408
 
@@ -400,7 +429,8 @@ module ScoutAgent
400
429
  :subject => "#{mission[:name]} could not be prepared",
401
430
  :body => "The code didn't define a Scout::Plugin subclass"
402
431
  )
403
- exit(reported ? 0 : 3) # warn parent if we can't report
432
+ # warn parent if we can't report
433
+ exit(reported ? 0 : MISSION_ERROR_NAMES[:loaded])
404
434
  end
405
435
  end
406
436
 
@@ -4,26 +4,6 @@
4
4
  require "rbconfig" # used to find the Ruby we are running under
5
5
  require "pathname" # all paths are Pathname objects
6
6
 
7
- begin
8
- #
9
- # the agent communicates in JSON, so we need to load the gem unless we are in
10
- # something like Rails that already provides us with JSON capabilities
11
- #
12
- require "json" unless Hash.new.respond_to? :to_json
13
- rescue LoadError # library not found
14
- begin
15
- require "rubygems"
16
- begin
17
- gem("json", "=1.1.4")
18
- rescue NoMethodError
19
- abort "Please upgrade RubyGems as the gem() method is required."
20
- end
21
- require "json"
22
- rescue LoadError # library not found
23
- abort "Please install the 'json' gem to use this API."
24
- end
25
- end
26
-
27
7
  module ScoutAgent
28
8
  #
29
9
  # This module contains methods used to communicate with the agent
@@ -96,7 +76,7 @@ module ScoutAgent
96
76
  map { |s| "'#{API.shell_escape(s)}'" }.join(" ")
97
77
  begin
98
78
  response = open("| #{command} 2>&1", "r+") { |agent|
99
- agent.puts @input.to_json if @input
79
+ agent.print Marshal.dump(@input) if @input
100
80
  agent.close_write
101
81
  agent.read
102
82
  }
@@ -144,7 +124,7 @@ module ScoutAgent
144
124
  #
145
125
  def validate(mission_id_or_report_type, fields)
146
126
  unless mission_id_or_report_type.to_s =~
147
- /\A(?:report|hint|alert|error|\d*[1-9])\z/
127
+ /\A(?:report|hint|alert|error|0*[1-9]\d*)\z/
148
128
  raise ArgumentError, "Invalid mission ID or report type"
149
129
  end
150
130
 
@@ -156,7 +136,7 @@ module ScoutAgent
156
136
  unless plugin_id
157
137
  raise ArgumentError, "A :plugin_id is a required field for reports"
158
138
  end
159
- unless plugin_id.to_s =~ /\A\d*[1-9]\z/
139
+ unless plugin_id.to_s =~ /\A0*[1-9]\d*\z/
160
140
  raise ArgumentError, "The :plugin_id must be a positive Integer"
161
141
  end
162
142
  end
@@ -11,6 +11,11 @@ module ScoutAgent
11
11
  #
12
12
  # scout_agent q ID_OR_TYPE <<< '{"fields": "in JSON"}'
13
13
  #
14
+ # or:
15
+ #
16
+ # ruby -e 'print Marshal.dump(:fields => "in Ruby")' | \
17
+ # scout_agent q ID_OR_TYPE
18
+ #
14
19
  # This command queues some data from an external source for a plugin. The
15
20
  # plugin to receive the message is given by ID in +ID_OR_TYPE+. That plugin
16
21
  # will be able to collect this data during its next run.
@@ -21,6 +26,9 @@ module ScoutAgent
21
26
  # be a Hash (object in JSON terminology) that includes the key "plugin_id"
22
27
  # associated with an ID value for the reporting plugin.
23
28
  #
29
+ # If you prefer, you can pass Marshal data from Ruby for the fields instead
30
+ # of JSON.
31
+ #
24
32
  class Queue < Assignment
25
33
  #
26
34
  # A list of errors that can be sent to the user when attempting to queue a
@@ -37,7 +45,7 @@ module ScoutAgent
37
45
  [ :missing_fields,
38
46
  "You must provide fields to queue." ],
39
47
  [ :invalid_fields,
40
- "You must pass valid JSON for the fields." ],
48
+ "You must pass valid JSON or Marshal data for the fields." ],
41
49
  [ :invalid_report_fields,
42
50
  "Field data must be a Hash to pass to the server." ],
43
51
  [ :missing_plugin_id_field,
@@ -80,8 +88,15 @@ module ScoutAgent
80
88
  end
81
89
  bytes = fields.size
82
90
  begin
83
- fields = JSON.parse(fields.to_s)
84
- rescue JSON::ParserError
91
+ if ["{", "["].include? fields[0, 1] # it's JSON
92
+ fields = JSON.parse(fields)
93
+ else # it's Marshal
94
+ fields = Marshal.load(fields)
95
+ if fields.is_a? Hash # Stringify Hash keys
96
+ fields = Hash[*fields.map { |k, v| [k.to_s, v] }.flatten]
97
+ end
98
+ end
99
+ rescue Exception
85
100
  abort_with_error(:invalid_fields)
86
101
  end
87
102
 
@@ -15,8 +15,12 @@ module ScoutAgent
15
15
  @log = log
16
16
  @rest_client = RestClient::Resource.new(
17
17
  Plan.agent_url,
18
- :headers => { :client_version => ScoutAgent::VERSION,
19
- :accept_encoding => "gzip" }
18
+ :headers => { :client_version => ScoutAgent::VERSION,
19
+ :accept_encoding => "gzip" },
20
+ :ssl_ca_file => File.join( File.dirname(__FILE__),
21
+ *%w[.. .. data cacert.pem] ),
22
+ :verify_ssl => OpenSSL::SSL::VERIFY_PEER |
23
+ OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
20
24
  )
21
25
  # make sure proxy is set, if needed
22
26
  RestClient.proxy = Plan.proxy_url
@@ -47,6 +51,9 @@ module ScoutAgent
47
51
  rescue RestClient::NotModified
48
52
  log.info("Plan was not modified.")
49
53
  "" # empty plan
54
+ rescue OpenSSL::SSL::SSLError
55
+ log.warn("SSL verification failed. The plan could not be trusted.")
56
+ nil # cannot trust any plan we received
50
57
  rescue Exception => error # networking problem
51
58
  log.warn("Plan could not be retrieved: #{error.class}.")
52
59
  nil # failed to retrieve plan
@@ -81,6 +88,10 @@ module ScoutAgent
81
88
  log.warn( "Check-in was returned as a failure code: " +
82
89
  "#{error.http_code}." )
83
90
  false
91
+ rescue OpenSSL::SSL::SSLError
92
+ log.warn( "SSL verification failed. " +
93
+ "Could not send check-in to untrusted server." )
94
+ false # cannot trust server
84
95
  rescue Exception => error # networking problem
85
96
  log.warn("Check-in could not be sent: #{error.class}.")
86
97
  false # we failed to send and will retry later
@@ -103,7 +114,11 @@ module ScoutAgent
103
114
  log.warn( "Log upload was returned as a failure code: " +
104
115
  "#{error.http_code}." )
105
116
  false
106
- rescue Errno::ECONNREFUSED, RestClient::Exception # networking problem
117
+ rescue OpenSSL::SSL::SSLError
118
+ log.warn( "SSL verification failed. " +
119
+ "Could not send log to untrusted server." )
120
+ false # cannot trust server
121
+ rescue Exception => error # networking problem
107
122
  log.warn("Log could not be sent: #{error.class}.")
108
123
  false # could not send log
109
124
  end
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env ruby -wKU
2
2
 
3
3
  require "test/unit"
4
+ require "timeout" # required for the core extensions
4
5
 
5
6
  require "scout_agent/core_extensions"
6
7
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scout_agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.2
4
+ version: 3.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Edward Gray II
@@ -12,7 +12,7 @@ autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
14
 
15
- date: 2009-05-27 00:00:00 -05:00
15
+ date: 2009-06-01 00:00:00 -05:00
16
16
  default_executable:
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
@@ -43,7 +43,7 @@ dependencies:
43
43
  requirements:
44
44
  - - "="
45
45
  - !ruby/object:Gem::Version
46
- version: 0.9.2
46
+ version: "1.0"
47
47
  version:
48
48
  - !ruby/object:Gem::Dependency
49
49
  name: json
@@ -53,7 +53,7 @@ dependencies:
53
53
  requirements:
54
54
  - - "="
55
55
  - !ruby/object:Gem::Version
56
- version: 1.1.4
56
+ version: 1.1.6
57
57
  version:
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: xmpp4r
@@ -136,6 +136,9 @@ files:
136
136
  - test/ts_all.rb
137
137
  - Rakefile
138
138
  - setup.rb
139
+ - data/cacert.pem
140
+ - data/gpl-2.0.txt
141
+ - data/lgpl-2.1.txt
139
142
  - AUTHORS
140
143
  - COPYING
141
144
  - README
@@ -182,7 +185,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
182
185
  requirements: []
183
186
 
184
187
  rubyforge_project: scout
185
- rubygems_version: 1.3.3
188
+ rubygems_version: 1.3.4
186
189
  signing_key:
187
190
  specification_version: 3
188
191
  summary: Scout makes monitoring and reporting on your servers as flexible and simple as possible.