class DataMapper::Adapters::PuppetdbAdapter

Attributes

host[RW]
http[RW]
port[RW]
ssl[RW]

Public Class Methods

new(name, options = {}) click to toggle source
Calls superclass method
# File lib/dm-puppetdb-adapter/adapter.rb, line 21
def initialize(name, options = {})
  super

  Puppet.initialize_settings unless Puppet[:confdir]

  # Set some defaults
  @host = @options[:host] || 'puppetdb'
  @port = @options[:port] || 443
  @ssl = @options[:ssl] || true
  @http = Puppet::Network::HttpPool.http_instance(@host, @port, @ssl)
end

Public Instance Methods

read(query) click to toggle source
# File lib/dm-puppetdb-adapter/adapter.rb, line 13
def read(query)
  model = query.model

  query.filter_records(puppetdb_get(model.storage_name(model.repository_name), build_query(query)))
end

Private Instance Methods

build_query(query) click to toggle source

contruct a puppetdb query from a datamapper query

# File lib/dm-puppetdb-adapter/adapter.rb, line 35
def build_query(query)
  conditions = query.conditions
  if conditions.nil?
    nil
  else
     puppetdb_condition(conditions, query.model)
  end
end
format_value(value) click to toggle source

format a value in a query especially make sure timestamps have correct format

# File lib/dm-puppetdb-adapter/adapter.rb, line 104
def format_value(value)
  if value.is_a? Date or value.is_a? Time
    value.strftime('%FT%T.%LZ')
  else
    value
  end
end
puppetdb_condition(c, model) click to toggle source

return puppetdb syntax for a condition

# File lib/dm-puppetdb-adapter/adapter.rb, line 46
def puppetdb_condition(c, model)
  case c
  when DataMapper::Query::Conditions::NullOperation
    nil
  when DataMapper::Query::Conditions::AbstractOperation
    q = [c.class.slug.to_s, *c.operands.map { |o| puppetdb_condition o, model }.compact]
    # In case we couldn't build any query from the contained
    # conditions return nil instead of a empty and
    return q.last if q.count == 2
    return nil if q.count < 2
    return q
  end

  # Determine the property we should match on
  if c.subject.kind_of? DataMapper::Property
    property = c.subject
  elsif c.subject.kind_of? DataMapper::Associations::Relationship
    property = c.subject.parent_key.first
  else
    puts "Unhandled subject #{c.subject.inspect}"
    raise RuntimeError, "Unhandled subject #{c.subject.inspect}"
  end

  # We can only do comparison on certain fields
  # on the server side
  if property.model.respond_to? :server_fields
    return nil unless property.model.server_fields.include? property.name
  end

  case c
  when DataMapper::Query::Conditions::EqualToComparison
    ['=', property.field, format_value(c.value)]
  when DataMapper::Query::Conditions::RegexpComparison
    ['~', property.field, format_value(c.value)]
  when DataMapper::Query::Conditions::LessThanComparison
    ['<', property.field, format_value(c.value)]
  when DataMapper::Query::Conditions::GreaterThanComparison
    ['>', property.field, format_value(c.value)]
  # The following comparison operators aren't supported by PuppetDB
  # So we emulate them
  when DataMapper::Query::Conditions::LikeComparison
    ['~', property.field, c.value.gsub('%', '.*')]
  when DataMapper::Query::Conditions::LessThanOrEqualToComparison
    ['or', ['=', property.field, format_value(c.value)], ['<', property.field, format_value(c.value)]]
  when DataMapper::Query::Conditions::GreaterThanOrEqualToComparison
    ['or', ['=', property.field, format_value(c.value)], ['>', property.field, format_value(c.value)]]
  when DataMapper::Query::Conditions::InclusionComparison
    if c.value.kind_of? Range
      ['or', ['=', property.field, format_value(c.value.first)], ['>', property.field, format_value(c.value.first)], ['<', property.field, format_value(c.value.last)], ['=', property.field, format_value(c.value.last)]]
    else
      ['or', *c.value.collect { |v| ['=', property.field, v.value]} ]
    end
  end
end
puppetdb_get(path, query=nil) click to toggle source
# File lib/dm-puppetdb-adapter/adapter.rb, line 112
def puppetdb_get(path, query=nil)
  uri = "/#{path}?query="
  uri += URI.escape query.to_json.to_s unless query.nil?
  resp = @http.get(uri, { "Accept" => "application/json" })
  raise RuntimeError, "PuppetDB query error: [#{resp.code}] #{resp.msg}, endpoint: #{path}, query: #{query.to_json}" unless resp.kind_of?(Net::HTTPSuccess)
  # Do a ugly hack because Hash and Array
  # properties aren't supported so we preserve them as JSON
  JSON.parse(resp.body).collect do |i|
    i.each do |k,v|
      i[k] = v.to_json if v.is_a? Hash or v.is_a? Array
    end
  end
end