class Proxy::Reports::SpooledHttpClient

Public Class Methods

new() click to toggle source
# File lib/smart_proxy_reports/spooled_http_client.rb, line 19
def initialize
  @worker = nil
end

Public Instance Methods

get_endpoint(name) click to toggle source
# File lib/smart_proxy_reports/spooled_http_client.rb, line 55
def get_endpoint(name)
  if name&.end_with? 'ansible_facts'
    "/api/v2/hosts/facts"
  else
    "/api/v2/host_reports"
  end
end
initialize_directory(spool_dir = Proxy::Reports::Plugin.settings.spool_dir) click to toggle source
# File lib/smart_proxy_reports/spooled_http_client.rb, line 23
def initialize_directory(spool_dir = Proxy::Reports::Plugin.settings.spool_dir)
  raise("Setting spool_dir uninitialized") unless spool_dir
  @spool_dir = spool_dir
  ["temp", "todo", "done", "fail"].each do |state|
    FileUtils.mkdir_p(spool_path(state))
  end
  self
end
process() click to toggle source
# File lib/smart_proxy_reports/spooled_http_client.rb, line 63
def process
  processed = 0
  client = ::Proxy::HttpRequest::ForemanRequest.new
  factory = client.request_factory
  # send all files via a single persistent HTTP connection
  logger.debug "Opening HTTP connection to Foreman"
  client.http.start do |http|
    Dir.glob(spool_path("todo", "*")).sort.each do |filename|
      basename = File.basename(filename)
      endpoint = get_endpoint(basename)
      logger.debug "Sending report #{basename}"
      begin
        post = factory.create_post(endpoint, File.read(filename))
        response = http.request(post)
        logger.info "Report #{basename} sent with HTTP response #{response.code}"
        logger.debug { "Response body: #{response.body}" }
        if response.code.start_with?("2")
          if Proxy::Reports::Plugin.settings.keep_reports
            spool_move("todo", "done", basename)
          else
            FileUtils.rm_f spool_path("todo", basename)
          end
        else
          logger.debug { "Moving failed report to 'fail' spool directory" }
          spool_move("todo", "done", basename)
        end
        processed += 1
      rescue StandardError => e
        logger.warn "Unable to send #{basename}, will try on next request: #{e}", e
        raise if ENV["RACK_ENV"] == "test"
      end
    end
  end
  logger.debug "Finished uploading #{processed} reports, closing connection"
end
spool(prefix, data) click to toggle source
# File lib/smart_proxy_reports/spooled_http_client.rb, line 103
def spool(prefix, data)
  filename = unique_filename + "-" + prefix.to_s
  file = spool_path("temp", filename)
  File.open(file, "w") { |f| f.write(data) }
  spool_move("temp", "todo", filename)
  wakeup
end
spool_move(from_state, to_state, filename) click to toggle source
# File lib/smart_proxy_reports/spooled_http_client.rb, line 14
def spool_move(from_state, to_state, filename)
  # TODO: implement fsync?
  FileUtils.mv(spool_path(from_state, filename), spool_path(to_state, filename))
end
spool_path(state = "temp", filename = nil) click to toggle source
# File lib/smart_proxy_reports/spooled_http_client.rb, line 6
def spool_path(state = "temp", filename = nil)
  if filename
    File.join(@spool_dir, state, filename)
  else
    File.join(@spool_dir, state)
  end
end
start() click to toggle source
# File lib/smart_proxy_reports/spooled_http_client.rb, line 32
def start
  @worker_running = true
  @worker = Thread.new do
    while @worker_running
      begin
        logger.info "Started host reports spooled http client"
        process
      rescue StandardError => e
        logger.error "Error during spool processing: #{e}", e
      end
      Thread.stop
    end
    logger.info "Stopped host reports spooled http client"
  end
end
stop() click to toggle source

smart proxy currently does not support stopping services

# File lib/smart_proxy_reports/spooled_http_client.rb, line 49
def stop
  @worker_running = false
  wakeup
  @worker.join
end
wakeup() click to toggle source
# File lib/smart_proxy_reports/spooled_http_client.rb, line 99
def wakeup
  @worker.wakeup if @worker
end

Private Instance Methods

unique_filename() click to toggle source

Ensure that files are named so they can be sorted and processed in the same order

# File lib/smart_proxy_reports/spooled_http_client.rb, line 114
def unique_filename
  Process.clock_gettime(Process::CLOCK_REALTIME, :second).to_s(36) +
    Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond).to_s(36)
end