class Wavefront::ApiCaller

Constructs and makes API calls to Wavefront.

Attributes

calling_class[R]
debug[R]
logger[R]
net[R]
noop[R]
opts[R]
verbose[R]

Public Class Methods

new(calling_class, creds = {}, opts = {}) click to toggle source

@param calling_class [ @param creds [Hash] Wavefront credentials @param opts [Hash] @return [Nil]

# File lib/wavefront-sdk/core/api_caller.rb, line 25
def initialize(calling_class, creds = {}, opts = {})
  @calling_class = calling_class
  @opts          = opts
  setup_class_vars(opts)
  setup_endpoint(creds)
end

Public Instance Methods

delete(path) click to toggle source

Make a DELETE call to the Wavefront API and return the result as a Ruby hash.

@param path [String] path to be appended to the

#net[:api_base] path.

@return [Hash] API response

# File lib/wavefront-sdk/core/api_caller.rb, line 163
def delete(path)
  make_call(mk_conn(path), :delete)
end
end_time(opts) click to toggle source
# File lib/wavefront-sdk/core/api_caller.rb, line 120
def end_time(opts)
  Time.right_now + opts[:timeout] if opts[:timeout]&.positive?
end
get(path, query = {}) click to toggle source

Make a GET call to the Wavefront API and return the result as a Ruby hash.

@param path [String] path to be appended to the

#net[:api_base] path.

@param query [Hash] optional key-value pairs with will be made

into a query string

@param request_opts [Hash] parameters to pass through to

Faraday

@return [Hash] API response

# File lib/wavefront-sdk/core/api_caller.rb, line 70
def get(path, query = {})
  make_call(mk_conn(path, {}), :get, nil, query)
end
get_flat_params(path, query = {}) click to toggle source

Had to introduce this for the Wavefront::Dashboard#acls method, which uses a query string of multiple id=s. By default Faraday only uses the last one. You must set the `params_encoder`. Rather than convolute the existing logic, it was cleaner to add this method. Parameters are same as get.

# File lib/wavefront-sdk/core/api_caller.rb, line 80
def get_flat_params(path, query = {})
  make_call(flat_param_conn(path, query), :get)
end
get_stream(path, query = {}, opts = {}) click to toggle source

This is used by the Wavefront::Unstable::Spy methods to stream data. It prints to standard out. @param path [String] path to be appended to the net path. @param query [Hash] optional key-value pairs with will be made into a

query string

@param opts [Hash] keys:

timestamp_chunks -- prints a timestamp before each chunk of streamed
  data
timeout -- after approximately this many seconds, return. It will be
  the first chunk *after* the given time

@return

# File lib/wavefront-sdk/core/api_caller.rb, line 96
def get_stream(path, query = {}, opts = {})
  conn = flat_param_conn(path, query)
  verbosity(conn, :get, query)
  stream_connection(conn, query, opts)
rescue Faraday::TimeoutError
  raise Wavefront::Exception::NetworkTimeout
rescue StopIteration
  nil
end
mk_conn(path, headers = {}, opts = {}) click to toggle source

Create a Faraday connection object. The server comes from the endpoint passed to the initializer in the 'creds' hash; the root of the URI is dynamically derived by the setup_endpoint method.

@param path [String] uri path @param headers [Hash] additional headers @param request_opts [Hash] Faraday request parameters @return [URI::HTTPS]

# File lib/wavefront-sdk/core/api_caller.rb, line 49
def mk_conn(path, headers = {}, opts = {})
  url = format('%<scheme>s://%<endpoint>s%<path>s',
               scheme: net[:scheme],
               endpoint: net[:endpoint],
               path: [net[:api_base], path].uri_concat)
  set_opts = { url: Addressable::URI.encode(url),
               headers: net[:headers].merge(headers) }
  Faraday.new(set_opts.merge(opts))
end
post(path, body = nil, ctype = 'text/plain') click to toggle source

Make a POST call to the Wavefront API and return the result as a Ruby hash.

@param path [String] path to be appended to the

#net[:api_base] path.

@param body [String,Object] optional body text to post.

Objects will be converted to JSON

@param ctype [String] the content type to use when posting @return [Hash] API response

# File lib/wavefront-sdk/core/api_caller.rb, line 134
def post(path, body = nil, ctype = 'text/plain')
  body = body.to_json unless body.is_a?(String)
  make_call(mk_conn(path,  'Content-Type': ctype,
                           Accept: 'application/json'),
            :post, nil, body)
end
put(path, body = nil, ctype = 'application/json') click to toggle source

Make a PUT call to the Wavefront API and return the result as a Ruby hash.

@param path [String] path to be appended to the

#net[:api_base] path.

@param body [String] optional body text to post @param ctype [String] the content type to use when putting @return [Hash] API response

# File lib/wavefront-sdk/core/api_caller.rb, line 150
def put(path, body = nil, ctype = 'application/json')
  make_call(mk_conn(path,  'Content-Type': ctype,
                           Accept: 'application/json'),
            :put, nil, body.to_json)
end
respond(resp) click to toggle source

If we need to massage a raw response to fit what the Wavefront::Response class expects (I'm looking at you, 'User'), a class can provide a {#response_shim} method. @param resp [Faraday::Response] @return [String] body of response (JSON)

# File lib/wavefront-sdk/core/api_caller.rb, line 173
def respond(resp)
  body = if calling_class.respond_to?(:response_shim)
           calling_class.response_shim(resp.body, resp.status)
         else
           resp.body
         end

  return body if opts[:raw_response]

  Wavefront::Response.new(body, resp.status, opts)
end
setup_class_vars(opts) click to toggle source
# File lib/wavefront-sdk/core/api_caller.rb, line 32
def setup_class_vars(opts)
  @logger    = Wavefront::Logger.new(opts)
  @noop      = opts[:noop] || false
  @verbose   = opts[:verbose] || false
  @debug     = opts[:debug] || false
end
stream_connection(conn, query, opts) click to toggle source
# File lib/wavefront-sdk/core/api_caller.rb, line 106
def stream_connection(conn, query, opts)
  t_end = end_time(opts)

  conn.get do |req|
    req.params = query
    req.options.on_data = proc do |chunk, _size|
      raise StopIteration if t_end && Time.right_now >= t_end

      puts Time.now if opts[:timestamp_chunks]
      puts chunk
    end
  end
end
verbosity(conn, method, *args) click to toggle source

Try to describe the actual HTTP calls we make. There's a bit of clumsy guesswork here

# File lib/wavefront-sdk/core/api_caller.rb, line 188
def verbosity(conn, method, *args)
  return unless noop || verbose

  log format('uri: %<method>s %<path>s',
             method: method.upcase,
             path: conn.url_prefix)

  return unless args.last && !args.last.empty?

  log method == :get ? "params: #{args.last}" : "body: #{args.last}"
end

Private Instance Methods

_validate_credentials(creds) click to toggle source
# File lib/wavefront-sdk/core/api_caller.rb, line 270
def _validate_credentials(creds)
  %w[endpoint token].each do |k|
    unless creds.key?(k.to_sym)
      raise(Wavefront::Exception::CredentialError,
            format('credentials must contain %<key>s', key: k))
    end
  end
end
flat_param_conn(path, query) click to toggle source
# File lib/wavefront-sdk/core/api_caller.rb, line 279
def flat_param_conn(path, query)
  mk_conn(path,
          {},
          request: {
            params_encoder: Faraday::FlatParamsEncoder
          },
          params: query)
end
headers(creds) click to toggle source
# File lib/wavefront-sdk/core/api_caller.rb, line 256
def headers(creds)
  ret = { 'user-agent': creds[:agent] }
  ret[:Authorization] = "Bearer #{creds[:token]}" if creds[:token]
  ret
end
make_call(conn, method, *args) click to toggle source

A dispatcher for making API calls. We now have three methods that do the real call, two of which live inside the requisite Wavefront::Paginator class @raise [Faraday::ConnectionFailed] if cannot connect to

endpoint
# File lib/wavefront-sdk/core/api_caller.rb, line 214
def make_call(conn, method, *args)
  paginator = paginator_class(method).new(self, conn, method, *args)

  case paginator.initial_limit
  when :all, 'all'
    paginator.make_recursive_call
  when :lazy, 'lazy'
    paginator.make_lazy_call
  else
    make_single_call(conn, method, *args)
  end
end
make_single_call(conn, method, *args) click to toggle source
# File lib/wavefront-sdk/core/api_caller.rb, line 227
def make_single_call(conn, method, *args)
  verbosity(conn, method, *args)
  return if noop

  pp args if debug

  resp = conn.public_send(method, *args)

  if debug
    require 'pp'
    pp resp
  end

  respond(resp)
end
paginator_class(method) click to toggle source
# File lib/wavefront-sdk/core/api_caller.rb, line 202
def paginator_class(method)
  require_relative File.join('..', 'paginator', method.to_s)
  Object.const_get(format('Wavefront::Paginator::%<method>s',
                          method: method.to_s.capitalize))
end
setup_endpoint(creds) click to toggle source
# File lib/wavefront-sdk/core/api_caller.rb, line 243
def setup_endpoint(creds)
  validate_credentials(creds)

  unless creds.key?(:agent) && creds[:agent]
    creds[:agent] = "wavefront-sdk #{WF_SDK_VERSION}"
  end

  @net = { headers: headers(creds),
           scheme: opts[:scheme] || 'https',
           endpoint: creds[:endpoint],
           api_base: calling_class.api_path }
end
validate_credentials(creds) click to toggle source
# File lib/wavefront-sdk/core/api_caller.rb, line 262
def validate_credentials(creds)
  if calling_class.respond_to?(:validate_credentials)
    calling_class.validate_credentials(creds)
  else
    _validate_credentials(creds)
  end
end