Class: Scout::Server

Inherits:
ServerBase show all
Defined in:
lib/scout/server.rb

Constant Summary collapse

DEFAULT_PLUGIN_TIMEOUT =

A plugin cannot take more than DEFAULT_PLUGIN_TIMEOUT seconds to execute, otherwise, a timeout error is generated. This can be overriden by individual plugins.

60
RUN_DELTA =

A fuzzy range of seconds in which it is okay to rerun a plugin. We consider the interval close enough at this point.

30

Constants inherited from ServerBase

Scout::ServerBase::HTTP_HEADERS

Constants included from HTTP

HTTP::CA_FILE, HTTP::VERIFY_MODE

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from HTTP

#build_http

Constructor Details

#initialize(server, client_key, history_file, logger = nil, server_name = nil, http_proxy = '', https_proxy = '', roles = '', hostname = nil, environment = '') ⇒ Server

Creates a new Scout Server connection.


31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/scout/server.rb', line 31

def initialize(server, client_key, history_file, logger=nil, server_name=nil, http_proxy='', https_proxy='', roles='', hostname=nil, environment='')
  @server       = server
  @client_key   = client_key
  @history_file = history_file
  @history      = Hash.new
  @logger       = logger
  @server_name  = server_name
  @http_proxy   = http_proxy
  @https_proxy  = https_proxy
  @roles        = roles || ''
  @hostname     = hostname
  @environment  = environment
  @plugin_plan  = []
  @plugins_with_signature_errors = []
  @directives   = {} # take_snapshots, interval, sleep_interval
  @streamer_command = nil
  @new_plan     = false
  @local_plugin_path = File.dirname(history_file) # just put overrides and ad-hoc plugins in same directory as history file.
  @plugin_config_path = File.join(@local_plugin_path, "plugins.properties")
  @account_public_key_path = File.join(@local_plugin_path, "scout_rsa.pub")
  @history_tmp_file = history_file+'.tmp'
  @plugin_config = load_plugin_configs(@plugin_config_path)
  @data_file = Scout::DataFile.new(@history_file,@logger)
  @started_at = Time.now # the checkin method needs to know when this scout client started
  # the block is only passed for install and test, since we split plan retrieval outside the lockfile for run
  if block_given?
    load_history
    yield self
    save_history
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Scout::ServerBase

Instance Attribute Details

#client_keyObject (readonly)

Returns the value of attribute client_key.


28
29
30
# File 'lib/scout/server.rb', line 28

def client_key
  @client_key
end

#directivesObject (readonly)

Returns the value of attribute directives.


25
26
27
# File 'lib/scout/server.rb', line 25

def directives
  @directives
end

#new_planObject (readonly)

Returns the value of attribute new_plan.


24
25
26
# File 'lib/scout/server.rb', line 24

def new_plan
  @new_plan
end

#plugin_configObject (readonly)

Returns the value of attribute plugin_config.


26
27
28
# File 'lib/scout/server.rb', line 26

def plugin_config
  @plugin_config
end

#streamer_commandObject (readonly)

Returns the value of attribute streamer_command.


27
28
29
# File 'lib/scout/server.rb', line 27

def streamer_command
  @streamer_command
end

Instance Method Details

#account_public_keyObject

Returns the account-specific public key if installed. Otherwise, nil.


244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/scout/server.rb', line 244

def 
  return @account_public_key if instance_variables.include?('@account_public_key')
  @account_public_key = nil
  begin
    public_key_text = File.read(@account_public_key_path)
    debug "Loaded account public key used for verifying code signatures (#{public_key_text.size} bytes)"
    @account_public_key=OpenSSL::PKey::RSA.new(public_key_text)
  rescue Errno::ENOENT
    debug "No account private key provided"
  rescue
    info "Error loading account public key: #{$!.message}"
  end
  return @account_public_key
end

#account_public_key_changed?Boolean

Returns:

  • (Boolean)

265
266
267
# File 'lib/scout/server.rb', line 265

def 
  @history['account_public_key'] != .to_s
end

#backup_history_and_recreate(contents, message) ⇒ Object

Called when a history file is determined to be corrupt / truncated / etc. Backup the existing file for later troubleshooting and create a fresh history file.


576
577
578
579
580
581
582
583
# File 'lib/scout/server.rb', line 576

def backup_history_and_recreate(contents,message)
  backup_path=File.join(File.dirname(@history_file), "history.corrupt")
  info(message)
  File.open(backup_path,"w"){|f|f.write contents}
  File.delete(@history_file)
  create_blank_history
  @history = File.open(@history_file) { |file| YAML.load(file) }
end

#client_key_changed?Boolean

Returns:

  • (Boolean)

214
215
216
217
218
219
220
221
222
223
224
# File 'lib/scout/server.rb', line 214

def client_key_changed?
  last_client_key=@history['last_client_key']
  # last_client_key will be nil on versions <= 5.5.7. when the agent runs after the upgrade, it will no longer 
  # be nil. don't want to aggressively reset the history file as it clears out memory values which may impact alerts.
  if last_client_key and client_key != last_client_key
    warn "The key associated with the history file has changed [#{last_client_key}] => [#{client_key}]."
    true
  else
    false
  end
end

#create_blank_historyObject

creates a blank history file


586
587
588
589
590
# File 'lib/scout/server.rb', line 586

def create_blank_history
  debug "Creating empty history file..."
  @data_file.save(YAML.dump({"last_runs" => Hash.new, "memory" => Hash.new, "last_client_key" => client_key}))
  info "History file created."
end

#fetch_planObject

Retrieves the Plugin Plan from the server. This is the list of plugins to execute, along with all options.

This method has a couple of side effects: 1) it sets the @plugin_plan with either A) whatever is in history, B) the results of the /plan retrieval 2) it sets @checkin_to = true IF so directed by the scout server


91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/scout/server.rb', line 91

def fetch_plan
  if refresh?

    url = urlify(:plan)
    info "Fetching plan from server at #{url}..."
    headers = {"x-scout-tty" => ($stdin.tty? ? 'true' : 'false')}
    headers["x-scout-roles"] = @roles

    get(url, "Could not retrieve plan from server.", headers) do |res|
      begin
        body = res.body
        if res["Content-Encoding"] == "gzip" and body and not body.empty?
          body = Zlib::GzipReader.new(StringIO.new(body)).read
        end
        body_as_hash = JSON.parse(body)
        
        temp_plugins=Array(body_as_hash["plugins"])
        # create a second array so the array we're iterating over doesn't mutate while we're iterating
        valid_plugins = temp_plugins.dup
        temp_plugins.each do |plugin|
          # grab the index of this plugin in the valid_plugins array
          valid_index = valid_plugins.index(plugin)
          signature=plugin['signature']
          id_and_name = "#{plugin['id']}-#{plugin['name']}".sub(/\A-/, "")
          if signature
            code=plugin['code'].gsub(/ +$/,'') # we strip trailing whitespace before calculating signatures. Same here.
            decoded_signature=Base64.decode64(signature)
            if !verify_public_key(scout_public_key, decoded_signature, code)
              if 
                if !verify_public_key(, decoded_signature, code)
                  info "#{id_and_name} signature verification failed for both the Scout and account public keys"
                  plugin['sig_error'] = "The code signature failed verification against both the Scout and account public key. Please ensure the public key installed at #{@account_public_key_path} was generated with the same private key used to sign the plugin."
                  @plugins_with_signature_errors << valid_plugins.delete_at(valid_index)
                end
              else
                info "#{id_and_name} signature doesn't match!"
                plugin['sig_error'] = "The code signature failed verification. Please place your account-specific public key at #{@account_public_key_path}."
                @plugins_with_signature_errors << valid_plugins.delete_at(valid_index)
              end
            end
          # filename is set for local plugins. these don't have signatures.
          elsif plugin['filename']
            plugin['code']=nil # should not have any code.
          else
            info "#{id_and_name} has no signature!"
            plugin['sig_error'] = "The code has no signature and cannot be verified."
            @plugins_with_signature_errors << valid_plugins.delete_at(valid_index)
          end
        end

        @plugin_plan = valid_plugins
        @directives = body_as_hash["directives"].is_a?(Hash) ? body_as_hash["directives"] : Hash.new
        @history["plan_last_modified"] = res["last-modified"]
        @history["old_plugins"]        = @plugin_plan
        @history["directives"]         = @directives

        info "Plan loaded.  (#{@plugin_plan.size} plugins:  " +
             "#{@plugin_plan.map { |p| p['name'] }.join(', ')})" +
             ". Directives: #{@directives.to_a.map{|a|  "#{a.first}:#{a.last}"}.join(", ")}"

        @new_plan = true # used in determination if we should checkin this time or not

        # Add local plugins to the plan.
        @plugin_plan += get_local_plugins
      rescue Exception =>e
        fatal "Plan from server was malformed: #{e.message} - #{e.backtrace}"
        exit
      end
    end
  else
    info "Plan not modified."
    @plugin_plan = Array(@history["old_plugins"])
    @plugin_plan += get_local_plugins
    @directives = @history["directives"] || Hash.new

  end
  @plugin_plan.reject! { |p| p['code'].nil? }
end

#get_local_pluginsObject

returns an array of hashes representing local plugins found on the filesystem The glob pattern requires that filenames begin with a letter, which excludes plugin overrides (like 12345.rb)


173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/scout/server.rb', line 173

def get_local_plugins
  local_plugin_paths=Dir.glob(File.join(@local_plugin_path,"[a-zA-Z]*.rb"))
  local_plugin_paths.map do |plugin_path|
    name    = File.basename(plugin_path)
    options = if directives = @plugin_plan.find { |plugin| plugin['filename'] == name }
                 directives['options']
              else 
                nil
              end
    begin
      plugin = {
        'name'            => name,
        'local_filename'  => name,
        'origin'          => 'LOCAL',
        'code'            => File.read(plugin_path),
        'interval'        => 0,
        'options'         => options
      }
      if !plugin['code'].include?('Scout::Plugin')
        info "Local Plugin [#{plugin_path}] doesn't look like a Scout::Plugin. Ignoring."
        nil
      else
        plugin
      end
    rescue => e
      info "Error trying to read local plugin: #{plugin_path} -- #{e.backtrace.join('\n')}"
      nil
    end
  end.compact
end

#get_server_metricsObject

called from the main “run_plugin_by_plan” method.


327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
# File 'lib/scout/server.rb', line 327

def get_server_metrics
  @history[:server_metrics] ||= {}

  res={}
  collectors = {:disk      => ServerMetrics::Disk,
                :cpu       => ServerMetrics::Cpu,
                :memory    => ServerMetrics::Memory,
                :network   => ServerMetrics::Network,
                :processes => ServerMetrics::Processes}

  collectors.each_pair do |key,klass|
    begin
      collector_previous_run = @history[:server_metrics][key]
      collector = collector_previous_run.is_a?(Hash) ? klass.from_hash(collector_previous_run) : klass.new() # continue with last run, or just create new
      res[key] = collector.run
      @history[:server_metrics][key] = collector.to_hash # store its state for next time
    rescue Exception => e
      raise if e.is_a?(SystemExit)
      error "Problem running server/#{key} metrics: #{e.message}: \n#{e.backtrace.join("\n")}"
    end
  end
  @checkin[:server_metrics] = res
end

#load_historyObject

Loads the history file from disk. If the file does not exist, it creates one.


552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
# File 'lib/scout/server.rb', line 552

def load_history
  if !File.exist?(@history_file) || File.zero?(@history_file)
    create_blank_history
  end
  debug "Loading history file..."
  contents=File.read(@history_file)
  begin
    @history = YAML.load(contents)
  rescue
    backup_history_and_recreate(contents,
    "Couldn't parse the history file. Deleting it and resetting to an empty history file. Keeping a backup.")
  end
  recreate_history_if_client_key_changed
  # YAML interprets an empty file as false. This condition catches that
  if !@history
    info "There is a problem with the history file at '#{@history_file}'. The root cause is sometimes a full disk. "+
             "If '#{@history_file}' exists but is empty, your disk is likely full."
    exit(1)
  end
  info "History file loaded."
end

#next_checkinObject

returns a human-readable representation of the next checkin, i.e., 5min 30sec


293
294
295
296
297
298
299
300
# File 'lib/scout/server.rb', line 293

def next_checkin
  secs= @directives['interval'].to_i*60 - (Time.now.to_i - Time.at(@history['last_checkin']).to_i).abs
  minutes=(secs.to_f/60).floor
  secs=secs%60
  "#{minutes}min #{secs} sec"
rescue
  "[next scout invocation]"
end

#ping_keyObject


210
211
212
# File 'lib/scout/server.rb', line 210

def ping_key
  (@history['directives'] || {})['ping_key']
end

#prepare_checkinObject

Prepares a check-in data structure to hold Plugin generated data.


532
533
534
535
536
537
538
539
540
541
542
# File 'lib/scout/server.rb', line 532

def prepare_checkin
  @checkin = { :reports          => Array.new,
               :alerts           => Array.new,
               :errors           => Array.new,
               :summaries        => Array.new,
               :snapshot         => '',
               :config_path      => File.expand_path(File.dirname(@history_file)),
               :server_name      => @server_name,
               :options          => Array.new,
               :server_metrics   => Hash.new }
end

#process_plugin(plugin) ⇒ Object

This is the heart of Scout.

First, it determines if a plugin is past interval and needs to be run. If it is, it simply evals the code, compiling it. It then loads the plugin and runs it with a PLUGIN_TIMEOUT time limit. The plugin generates data, alerts, and errors. In addition, it will set memory and last_run information in the history file.

The plugin argument is a hash with keys: id, name, code, timeout, options, signature.


370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
# File 'lib/scout/server.rb', line 370

def process_plugin(plugin)
  info "Processing the '#{plugin['name']}' plugin:"
  id_and_name = "#{plugin['id']}-#{plugin['name']}".sub(/\A-/, "")
  plugin_id = plugin['id']
  last_run    = @history["last_runs"][id_and_name] ||
                @history["last_runs"][plugin['name']]
  memory      = @history["memory"][id_and_name] ||
                @history["memory"][plugin['name']]
  run_time    = Time.now
  delta       = last_run.nil? ? nil : run_time -
                                      (last_run + plugin['interval'] * 60)
  if last_run.nil? or last_run > run_time or delta.between?(-RUN_DELTA, 0) or delta >= 0
    if last_run != nil and (last_run > run_time)
      debug "Plugin last_run is in the future. Running the plugin now. (last run:  #{last_run})"
    else
      debug "Plugin is past interval and needs to be run.  " +
            "(last run:  #{last_run || 'nil'})"
    end
    code_to_run = plugin['code']
    if plugin_id && plugin_id != ""
      override_path=File.join(@local_plugin_path, "#{plugin_id}.rb")
      # debug "Checking for local plugin override file at #{override_path}"
      if File.exist?(override_path)
        code_to_run = File.read(override_path)
        debug "Override file found - Using #{code_to_run.size} chars of code in #{override_path} for plugin id=#{plugin_id}"
        plugin['origin'] = "OVERRIDE"
      else
        plugin['origin'] = nil
      end
    end
    debug "Compiling plugin..."
    begin
      eval( code_to_run,
            TOPLEVEL_BINDING,
            plugin['path'] || plugin['name'] )
      info "Plugin compiled."
    rescue Exception
      raise if $!.is_a? SystemExit
      error "Plugin #{plugin['path'] || plugin['name']} would not compile: #{$!.message}"
      @checkin[:errors] << build_report(plugin,:subject => "Plugin would not compile", :body=>"#{$!.message}\n\n#{$!.backtrace}")
      return
    end

    # Lookup any local options in plugin_config.properies as needed
    options=(plugin['options'] || Hash.new)
    options.each_pair do |k,v|
      if v=~/^lookup:(.+)$/
        lookup_key = $1.strip
        if plugin_config[lookup_key]
          options[k]=plugin_config[lookup_key]
        else
          info "Plugin #{id_and_name}: option #{k} appears to be a lookup, but we can't find #{lookup_key} in #{@plugin_config_path}"
        end
      end
    end

    debug "Loading plugin..."
    if job = Plugin.last_defined.load( last_run, (memory || Hash.new), options)
      info "Plugin loaded."
      debug "Running plugin..."
      begin
        data    = {}
        timeout = plugin['timeout'].to_i
        timeout = DEFAULT_PLUGIN_TIMEOUT unless timeout > 0
        Timeout.timeout(timeout, PluginTimeoutError) do
          data = job.run
        end
      rescue Timeout::Error, PluginTimeoutError
        error "Plugin took too long to run."
        @checkin[:errors] << build_report(plugin,
                                          :subject => "Plugin took too long to run",
                                          :body=>"Execution timed out.")
        return
      rescue Exception
        raise if $!.is_a? SystemExit
        error "Plugin failed to run: #{$!.class}: #{$!.message}\n" +
              "#{$!.backtrace.join("\n")}"
        @checkin[:errors] << build_report(plugin,
                                          :subject => "Plugin failed to run",
                                          :body=>"#{$!.class}: #{$!.message}\n#{$!.backtrace.join("\n")}")
      end
                
      info "Plugin completed its run."
      
      %w[report alert error summary].each do |type|
        plural  = "#{type}s".sub(/ys\z/, "ies").to_sym
        reports = data[plural].is_a?(Array) ? data[plural] :
                                              [data[plural]].compact
        if report = data[type.to_sym]
          reports << report
        end
        reports.each do |fields|
          @checkin[plural] << build_report(plugin, fields)
        end
      end
      
      report_embedded_options(plugin,code_to_run)
      
      @history["last_runs"].delete(plugin['name'])
      @history["memory"].delete(plugin['name'])
      @history["last_runs"][id_and_name] = run_time
      @history["memory"][id_and_name]    = data[:memory]
    else
      @checkin[:errors] << build_report(
        plugin,
        :subject => "Plugin would not load."
      )
    end
  else
    debug "Plugin does not need to be run at this time.  " +
          "(last run:  #{last_run || 'nil'})"
  end
  data
ensure
  if job
    @history["last_runs"].delete(plugin['name'])
    @history["memory"].delete(plugin['name'])
    @history["last_runs"][id_and_name] = run_time
    @history["memory"][id_and_name]    = job.data_for_server[:memory]
  end
  if Plugin.last_defined
    debug "Removing plugin code..."
    begin
      Object.send(:remove_const, Plugin.last_defined.to_s.split("::").first)
      Plugin.last_defined = nil
      info "Plugin Removed."
    rescue
      raise if $!.is_a? SystemExit
      error "Unable to remove plugin."
    end
  end
  info "Plugin '#{plugin['name']}' processing complete."
end

#process_signature_errorsObject

Reports errors if there are any plugins with invalid signatures and sets a flag to force a fresh plan on the next run.


353
354
355
356
357
358
# File 'lib/scout/server.rb', line 353

def process_signature_errors
  return unless @plugins_with_signature_errors and @plugins_with_signature_errors.any?
  @plugins_with_signature_errors.each do |plugin|
    @checkin[:errors] << build_report(plugin,:subject => "Code Signature Error", :body => plugin['sig_error'])
  end
end

#recreate_history_if_client_key_changedObject

need to load the history file first to determine if the key changed. if it has, reset.


228
229
230
231
232
233
# File 'lib/scout/server.rb', line 228

def recreate_history_if_client_key_changed
  if client_key_changed?
    create_blank_history
    @history = YAML.load(File.read(@history_file))
  end
end

#refresh?Boolean

Returns:

  • (Boolean)

63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/scout/server.rb', line 63

def refresh?
  return true if !ping_key or  # fetch the plan again if the account key is modified/created

  url=URI.join( @server.sub("https://","http://"), "/clients/#{ping_key}/ping.scout?roles=#{@roles}&hostname=#{URI.encode(@hostname)}&env=#{URI.encode(@environment)}")

  headers = {"x-scout-tty" => ($stdin.tty? ? 'true' : 'false')}
  if @history["plan_last_modified"] and @history["old_plugins"]
    headers["If-Modified-Since"] = @history["plan_last_modified"]
  end
  get(url, "Could not ping #{url} for refresh info", headers) do |res|        
    @streamer_command = res["x-streamer-command"] # usually will be nil, but can be [start,abcd,1234,5678|stop]
    if res.is_a?(Net::HTTPNotModified)
      return false
    else
      info "Plan has been modified!"
      return true
    end
  end
end

#report_embedded_options(plugin, code) ⇒ Object

Adds embedded options to the checkin if the plugin is manually installed on this server.


506
507
508
509
510
511
512
513
514
515
516
517
518
# File 'lib/scout/server.rb', line 506

def report_embedded_options(plugin,code)
  return unless plugin['origin'] and Plugin.has_embedded_options?(code)
  if  options_yaml = Plugin.extract_options_yaml_from_code(code)
    options=PluginOptions.from_yaml(options_yaml)
    if options.error
      debug "Problem parsing option definition in the plugin code:"
      debug options_yaml
    else
      debug "Sending options to server"
      @checkin[:options] << build_report(plugin,options.to_hash)
    end
  end
end

#run_plugins_by_planObject

Runs all plugins from the given plan. Calls process_plugin on each plugin.


304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'lib/scout/server.rb', line 304

def run_plugins_by_plan
  prepare_checkin
  @plugin_plan.each do |plugin|
    begin
      process_plugin(plugin)
    rescue Exception
      @checkin[:errors] << build_report(
        plugin,
        :subject => "Exception:  #{$!.message}.",
        :body    => $!.backtrace
      )
      error("Encountered an error: #{$!.message}")
      puts $!.backtrace.join('\n')
    end
  end
  take_snapshot if @directives['take_snapshots']
  get_server_metrics
  process_signature_errors
  
  checkin
end

#save_historyObject

Saves the history file to disk.


593
594
595
596
597
598
# File 'lib/scout/server.rb', line 593

def save_history
  debug "Saving history file..."
  @history['last_client_key'] = client_key
  @data_file.save(YAML.dump(@history))
  info "History file saved."
end

#scout_public_keyObject

Returns the Scout public key for code verification.


236
237
238
239
240
241
# File 'lib/scout/server.rb', line 236

def scout_public_key
  return @scout_public_key if instance_variables.include?('@scout_public_key')
  public_key_text = File.read(File.join( File.dirname(__FILE__), *%w[.. .. data code_id_rsa.pub] ))
  debug "Loaded scout-wide public key used for verifying code signatures (#{public_key_text.size} bytes)"
  @scout_public_key = OpenSSL::PKey::RSA.new(public_key_text)
end

#show_checkin(printer = :p) ⇒ Object


544
545
546
# File 'lib/scout/server.rb', line 544

def show_checkin(printer = :p)
  send(printer, @checkin)
end

#sleep_intervalObject

To distribute pings across a longer timeframe, the agent will sleep for a given amount of time. When using the –force option the sleep_interval is ignored.


206
207
208
# File 'lib/scout/server.rb', line 206

def sleep_interval
  (@history['directives'] || {})['sleep_interval'].to_f
end

#store_account_public_keyObject

This is called in run_plugins_by_plan. When the agent starts its next run, it checks to see if the key has changed. If so, it forces a refresh.


261
262
263
# File 'lib/scout/server.rb', line 261

def 
  @history['account_public_key'] = .to_s
end

#take_snapshotObject

captures a list of processes running at this moment


522
523
524
525
526
527
528
529
# File 'lib/scout/server.rb', line 522

def take_snapshot
  info "Taking a process snapshot"
  ps=%x(ps aux).split("\n")[1..-1].join("\n") # get rid of the header line
  @checkin[:snapshot]=ps
  rescue Exception
    error "unable to capture processes on this server. #{$!.message}"
    return nil
end

#time_to_checkin?Boolean

uses values from history and current time to determine if we should checkin at this time

Returns:

  • (Boolean)

270
271
272
273
274
275
276
277
278
# File 'lib/scout/server.rb', line 270

def time_to_checkin?
  @history['last_checkin'] == nil ||
          @directives['interval'] == nil ||
          (Time.now.to_i - Time.at(@history['last_checkin']).to_i).abs+15+sleep_interval > @directives['interval'].to_i*60
rescue
  debug "Failed to calculate time_to_checkin. @history['last_checkin']=#{@history['last_checkin']}. "+
          "@directives['interval']=#{@directives['interval']}. Time.now.to_i=#{Time.now.to_i}"
  return true
end

#time_to_ping?Boolean

uses values from history and current time to determine if we should ping the server at this time

Returns:

  • (Boolean)

281
282
283
284
285
286
287
288
289
290
# File 'lib/scout/server.rb', line 281

def time_to_ping?
  return true if
  @history['last_ping'] == nil ||
          @directives['ping_interval'] == nil ||
          (Time.now.to_i - Time.at(@history['last_ping']).to_i).abs+15 > @directives['ping_interval'].to_i*60
rescue
  debug "Failed to calculate time_to_ping. @history['last_ping']=#{@history['last_ping']}. "+
          "@directives['ping_interval']=#{@directives['ping_interval']}. Time.now.to_i=#{Time.now.to_i}"
  return true
end