scout_agent 3.2.2 → 3.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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.