class Hoss::CentralConfig

@api private

Attributes

config[R]
promise[R]
scheduled_task[R]

Public Class Methods

new(config) click to toggle source
# File lib/hoss/central_config.rb, line 38
def initialize(config)
  @config = config
  @modified_options = {}
  @authorization = "Bearer #{@config.api_key}"
  @http = Transport::Connection::Http.new(config)
  @etag = 1
end

Public Instance Methods

assign(update) click to toggle source
# File lib/hoss/central_config.rb, line 87
def assign(update)
  # For each updated option, store the original value,
  # unless already stored
  update.each_key do |key|
    @modified_options[key] ||= config.get(key.to_sym)&.value
  end

  # If the new update doesn't set a previously modified option,
  # revert it to the original
  @modified_options.each_key do |key|
    next if update.key?(key)
    update[key] = @modified_options.delete(key)
  end
  @config.replace_options(update)
end
fetch_and_apply_config() click to toggle source
# File lib/hoss/central_config.rb, line 63
def fetch_and_apply_config
  @promise =
    Concurrent::Promise
    .execute(&method(:fetch_config))
    .on_success(&method(:handle_success))
    .rescue(&method(:handle_error))
end
fetch_config() click to toggle source
# File lib/hoss/central_config.rb, line 71
def fetch_config
  resp = perform_request
  case resp.status
  when 200..299
    resp
  when 300..399
    resp
  when 400..499
    resp
    # raise ClientError, resp
  when 500..599
    resp
    # raise ServerError, resp
  end
end
handle_forking!() click to toggle source
# File lib/hoss/central_config.rb, line 103
def handle_forking!
  stop
  start
end
start() click to toggle source
# File lib/hoss/central_config.rb, line 49
def start
  return unless config.central_config?

  debug 'Starting CentralConfig'

  fetch_and_apply_config
end
stop() click to toggle source
# File lib/hoss/central_config.rb, line 57
def stop
  debug 'Stopping CentralConfig'

  @scheduled_task&.cancel
end

Private Instance Methods

api_host() click to toggle source
# File lib/hoss/central_config.rb, line 160
def api_host
  @api_host ||=
    config.api_host +
    '/api/graphql'
end
handle_error(error) click to toggle source

rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity

# File lib/hoss/central_config.rb, line 140
def handle_error(error)
  puts error.backtrace
  # For tests, WebMock failures don't have real responses
  response = error.response if error.respond_to?(:response)

  debug(
    'Failed fetching config: %s, trying again in %d seconds',
    response&.body, @config.remote_config_fetch_interval
  )

  assign({})

  schedule_next_fetch(response)
end
handle_success(resp) click to toggle source

rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity

# File lib/hoss/central_config.rb, line 111
def handle_success(resp)
  if (etag = resp.headers['Etag'])
    @etag = etag
  end

  if resp.status == 304
    info 'Received 304 Not Modified'
  else
    if resp.body && !resp.body.empty?
      update = JSON.parse(resp.body.to_s)
      assign(update['data']) unless update.nil? or update['data'].nil?
    end

    if update && update.any?
      info 'Updated config'
      debug 'Modified: %s', update.inspect
      debug 'Modified original options: %s', @modified_options.inspect
    end
  end

  schedule_next_fetch(resp)

  true
rescue Exception => e
  error 'Failed to apply remote config, %s', e.inspect
  debug e.backtrace.join('\n')
end
headers() click to toggle source
# File lib/hoss/central_config.rb, line 166
def headers
  { 'Etag': @etag, 'Authorization': @authorization, 'HOSS-SKIP-INSTRUMENTATION': true }
end
perform_request() click to toggle source
# File lib/hoss/central_config.rb, line 155
def perform_request
  body = '{"query":"query AgentConfig {\n  agentConfig {\n    accountApiConfiguration {\n      uuid\n      hostBlacklist\n      sanitizedHeaders\n      sanitizedQueryParams\n      sanitizedBodyFields {\n        type\n        value\n      }\n      bodyCapture\n    }\n    apis {\n      uuid\n      name\n      rootDomain\n      hosts\n      configuration(mergeWithAccountConfiguration: true) {\n        uuid\n        sanitizedHeaders\n        sanitizedQueryParams\n        bodyCapture\n        sanitizedBodyFields {\n          type\n          value\n        }\n      }\n    }\n    accountRestrictions {\n      ingressDisabled\n    }\n  }\n}","operationName":"AgentConfig"}'
  @http.post(api_host, body: body, headers: headers)
end
schedule_next_fetch(resp = nil) click to toggle source
# File lib/hoss/central_config.rb, line 170
def schedule_next_fetch(resp = nil)
  headers = resp&.headers
  seconds =
    if headers && headers['Cache-Control']
      CacheControl.new(headers['Cache-Control']).max_age
    else
      @config.remote_config_fetch_interval
    end

  @scheduled_task =
    Concurrent::ScheduledTask
    .execute(seconds, &method(:fetch_and_apply_config))
end