class ForemanApi::Base

Constants

API_VERSION

Attributes

client[R]
config[R]
logger[R]

Public Class Methods

doc() click to toggle source
# File lib/foreman_api/base.rb, line 81
def self.doc
  raise NotImplementedError
end
method_doc(method) click to toggle source
# File lib/foreman_api/base.rb, line 89
def self.method_doc(method)
  method_docs[method.to_s]
end
new(config, options = {}) click to toggle source
# File lib/foreman_api/base.rb, line 33
def initialize(config, options = {})
  config = config.dup
  self.logger = config.delete(:logger)

  headers = {
    :content_type => 'application/json',
    :accept       => "application/json;version=#{API_VERSION}"
  }
  headers.merge!(config[:headers]) unless config[:headers].nil?
  headers.merge!(options.delete(:headers)) unless options[:headers].nil?

  resource_config = {
    :user     => config[:username],
    :password => config[:password],
    :oauth    => config[:oauth],
    :headers  => headers
  }.merge(options)

  @client = RestClient::Resource.new(config[:base_url], resource_config)
  @config = config
end
validation_hash(method) click to toggle source
# File lib/foreman_api/base.rb, line 85
def self.validation_hash(method)
  validation_hashes[method.to_s]
end

Private Class Methods

construct_validation_hash(method) click to toggle source
# File lib/foreman_api/base.rb, line 198
def self.construct_validation_hash(method)
  if method['params'].any? { |p| p['params'] }
    method['params'].reduce({ }) do |h, p|
      h.update(p['name'] => (p['params'] ? p['params'].map { |pp| pp['name'] } : nil))
    end
  else
    method['params'].map { |p| p['name'] }
  end
end
method_docs() click to toggle source
# File lib/foreman_api/base.rb, line 183
def self.method_docs
  @method_docs ||= doc['methods'].inject({ }) do |hash, method|
    hash[method['name']] = method
    hash
  end
end
params_in_path(url) click to toggle source
# File lib/foreman_api/base.rb, line 208
def self.params_in_path(url)
  url.scan(/:([^\/]*)/).map { |m| m.first }
end
validation_hashes() click to toggle source
# File lib/foreman_api/base.rb, line 190
def self.validation_hashes
  @validation_hashes ||= method_docs.inject({ }) do |hash, pair|
    name, method_doc = pair
    hash[name]       = construct_validation_hash method_doc
    hash
  end
end

Public Instance Methods

http_call(http_method, path, params = { }, headers = { }) click to toggle source
# File lib/foreman_api/base.rb, line 64
def http_call(http_method, path, params = { }, headers = { })
  headers ||= { }

  args = [http_method]
  if %w[post put].include?(http_method.to_s)
    args << params.to_json
  else
    headers[:params] = params if params
  end

  logger.info "#{http_method.upcase} #{path}"
  logger.debug "Params: #{params.inspect}"
  logger.debug "Headers: #{headers.inspect}"
  args << headers if headers
  process_data client[path].send(*args)
end
logger=(logger) click to toggle source
# File lib/foreman_api/base.rb, line 106
def logger=(logger)
  if logger.nil?
    logger = Logger.new(STDOUT)
    logger.level = Logger::WARN
  end
  @logger = logger
end
perform_call(method_name, params, headers) click to toggle source
# File lib/foreman_api/base.rb, line 55
def perform_call(method_name, params, headers)
  method_doc = self.class.method_doc(method_name)
  check_params params, :allowed => method_doc['params'].any?, :method => method_name
  method_apis = method_doc['apis']
  api = find_suitable_api_call(method_apis, params)
  url, params = fill_params_in_url api['api_url'], params
  return http_call(api['http_method'].downcase, url, params, headers)
end
validate_params!(params, rules) click to toggle source
# File lib/foreman_api/base.rb, line 93
def validate_params!(params, rules)
  return unless params.is_a?(Hash)

  invalid_keys = params.keys.map(&:to_s) - (rules.is_a?(Hash) ? rules.keys : rules)
  raise ArgumentError, "Invalid keys: #{invalid_keys.join(", ")}" unless invalid_keys.empty?

  if rules.is_a? Hash
    rules.each do |key, sub_keys|
      validate_params!(params[key], sub_keys) if params[key]
    end
  end
end

Protected Instance Methods

check_params(params, options = { }) click to toggle source
# File lib/foreman_api/base.rb, line 126
def check_params(params, options = { })
  raise ArgumentError unless (method = options[:method])
  return unless config[:enable_validations]

  case options[:allowed]
  when true
    validate_params!(params, self.class.validation_hash(method))
  when false
    raise ArgumentError, "this method '#{method}' does not support params" if params && !params.empty?
  else
    raise ArgumentError, "options :allowed should be true or false, it was #{options[:allowed]}"
  end
end
fill_params_in_url(url, params) click to toggle source

@return url and rest of the params

# File lib/foreman_api/base.rb, line 168
def fill_params_in_url(url, params)
  params          ||= { }
  # insert param values
  url_param_names = self.class.params_in_path(url)
  url             = url_param_names.inject(url) do |url, param_name|
    param_value = params[param_name] or
      raise ArgumentError, "missing param '#{param_name}' in parameters"
    url.sub(":#{param_name}", URI.escape(param_value.to_s))
  end

  return url, params.reject { |param_name, _| url_param_names.include? param_name }
end
find_suitable_api_call(possible_apis, params) click to toggle source

@param possible_apis [Array] Array of hasahs in form of

[{:api_url => '/path1', :http_method => 'GET'}, {...}]

@param params [Hash] enterred params @return api that suits the enterred params mosts

Given this paths:

1. +/comments+
2. +/users/:user_id/comments+
3. +/users/:user_id/posts/:post_id/comments+

If :user_id and :post_id is pecified, the third path is used. If only :user_id is specified, the second one is used. The selection defaults to the path with the least number of incuded params in alphanumeric order.

# File lib/foreman_api/base.rb, line 154
def find_suitable_api_call(possible_apis, params)
  apis_with_params = possible_apis.map do |api|
    [api, self.class.params_in_path(api['api_url'])]
  end.sort_by { |api, url_params| [-1 * url_params.count, api['api_url']] }

  suitable_api = apis_with_params.find do |api, url_params|
    url_params.all? { |url_param| params.keys.map(&:to_s).include?(url_param) }
  end

  suitable_api ||= apis_with_params.last
  return suitable_api.first
end
process_data(response) click to toggle source
# File lib/foreman_api/base.rb, line 116
def process_data(response)
  data = begin
           JSON.parse(response.body)
         rescue JSON::ParserError
           response.body
         end
  logger.debug "Returned data: #{data.inspect}"
  return data, response
end