class PuppetDBQuery::MongoDB

access nodes and their facts from mongo database rubocop:disable Metrics/ClassLength

Attributes

connection[R]
meta_collection[R]
node_properties_collection[R]
node_properties_update_timestamp[R]
nodes_collection[R]

Public Class Methods

new(connection, nodes = :nodes, node_properties = :node_properties, meta = :meta) click to toggle source

initialize access to mongodb

You might want to adjust the logging level, for example:

::Mongo::Logger.logger.level = logger.level

@param connection mongodb connection, should already be switched to correct database @param nodes symbol for collection that contains nodes with their facts @param node_properties symbol for collection for nodes with their update timestamps @param meta symbol for collection with update metadata

# File lib/puppetdb_query/mongodb.rb, line 39
def initialize(connection, nodes = :nodes, node_properties = :node_properties, meta = :meta)
  @connection = connection
  @nodes_collection = nodes
  @node_properties_collection = node_properties
  @meta_collection = meta
end

Public Instance Methods

all_nodes() click to toggle source

get all node names

# File lib/puppetdb_query/mongodb.rb, line 58
def all_nodes
  collection = connection[nodes_collection]
  collection.find.batch_size(999).projection(_id: 1).map { |k| k[:_id] }
end
facts(facts = []) click to toggle source

get all nodes and their facts

@param facts [Array<String>] get these facts in the result, eg ['fqdn'], empty for all

# File lib/puppetdb_query/mongodb.rb, line 146
def facts(facts = [])
  fields = Hash[facts.collect { |fact| [fact.to_sym, 1] }]
  collection = connection[nodes_collection]
  result = {}
  collection.find.batch_size(999).projection(fields).each do |values|
    id = values.delete('_id')
    result[id] = values
  end
  result
end
meta() click to toggle source

get meta informations about updates

# File lib/puppetdb_query/mongodb.rb, line 158
def meta
  collection = connection[meta_collection]
  result = collection.find.first
  result.delete(:_id)
  result
end
meta_fact_update(method, ts_begin, ts_end) click to toggle source

update or insert timestamps for given fact update method

# File lib/puppetdb_query/mongodb.rb, line 225
def meta_fact_update(method, ts_begin, ts_end)
  connection[meta_collection].find_one_and_update(
    {},
    {
      '$set' => {
        last_fact_update: {
          ts_begin: ts_begin.iso8601,
          ts_end:   ts_end.iso8601,
          method:   method
        },
        method => {
          ts_begin: ts_begin.iso8601,
          ts_end:   ts_end.iso8601
        }
      }
    },
    { upsert: true }
  )
end
meta_node_properties_update(ts_begin, ts_end) click to toggle source

update or insert timestamps for node_properties_update

# File lib/puppetdb_query/mongodb.rb, line 246
def meta_node_properties_update(ts_begin, ts_end)
  connection[meta_collection].find_one_and_update(
    {},
    {
      '$set' => {
        last_node_properties_update: {
          ts_begin: ts_begin.iso8601,
          ts_end:   ts_end.iso8601
        }
      }
    },
    { upsert: true }
  )
  @node_properties_update_timestamp = ts_begin
end
node_delete(node) click to toggle source

delete node data for given node name

@param node [String] node name

# File lib/puppetdb_query/mongodb.rb, line 201
def node_delete(node)
  connection[nodes_collection].find(_id: node).delete_one
end
node_properties() click to toggle source

get all nodes and their update dates

# File lib/puppetdb_query/mongodb.rb, line 47
def node_properties
  collection = connection[node_properties_collection]
  result = {}
  collection.find.batch_size(999).each do |values|
    id = values.delete('_id')
    result[id] = values
  end
  result
end
node_properties_update(new_node_properties) click to toggle source

update node properties

# File lib/puppetdb_query/mongodb.rb, line 206
def node_properties_update(new_node_properties)
  collection = connection[node_properties_collection]
  old_names = collection.find.batch_size(999).projection(_id: 1).map { |k| k[:_id] }
  delete = old_names - new_node_properties.keys
  data = new_node_properties.map do |k, v|
    {
      replace_one:
      {
        filter: { _id: k },
        replacement: v,
        upsert: true
      }
    }
  end
  collection.bulk_write(data)
  collection.delete_many(_id: { '$in' => delete })
end
node_update(node, facts) click to toggle source

update or insert facts for given node name

@param node [String] node name @param facts [Hash] facts for the node

# File lib/puppetdb_query/mongodb.rb, line 169
def node_update(node, facts)
  logger.debug "  updating #{node}"
  connection[nodes_collection].find(_id: node).replace_one(facts,
    upsert: true,
    bypass_document_validation: true,
    check_keys: false,
    validating_keys: false)
rescue ::Mongo::Error::OperationFailure => e
  logger.warn "  updating #{node} failed with: #{e.message}"
  # mongodb doesn't support keys with a dot
  # see https://docs.mongodb.com/manual/reference/limits/#Restrictions-on-Field-Names
  # as a dirty workaround we delete the document and insert it ;-)
  # The dotted field .. in .. is not valid for storage. (57)
  # .. is an illegal key in MongoDB. Keys may not start with '$' or contain a '.'.
  # (BSON::String::IllegalKey)
  raise e unless e.message =~ /The dotted field / || e.message =~ /is an illegal key/
  logger.warn "    we transform the dots into underline characters"
  begin
    facts = Hash[facts.map { |k, v| [k.tr('.', '_'), v] }]
    connection[nodes_collection].find(_id: node).replace_one(facts,
      upsert: true,
      bypass_document_validation: true,
      check_keys: false,
      validating_keys: false)
  rescue
    logger.error "  inserting node #{node} failed again with: #{e.message}"
  end
end
query_facts(query, facts = []) click to toggle source

get nodes and their facts that fulfill given mongodb query

@param query mongodb query @param facts [Array<String>] get these facts in the result, eg ['fqdn'], empty for all

# File lib/puppetdb_query/mongodb.rb, line 75
def query_facts(query, facts = [])
  fields = Hash[facts.collect { |fact| [fact.to_sym, 1] }]
  collection = connection[nodes_collection]
  result = {}
  collection.find(query).batch_size(999).projection(fields).each do |values|
    id = values.delete('_id')
    result[id] = values
  end
  result
end
query_facts_exist(query, facts = []) click to toggle source

get nodes and their facts that fulfill given mongodb query and have at least one value for one the given fact names

@param query mongodb query @param facts [Array<String>] get these facts in the result, eg ['fqdn'], empty for all

# File lib/puppetdb_query/mongodb.rb, line 91
def query_facts_exist(query, facts = [])
  result = query_facts(query, facts)
  unless facts.empty?
    result.keep_if do |_k, v|
      facts.any? { |f| !v[f].nil? }
    end
  end
  result
end
query_nodes(query) click to toggle source

get node names that fulfill given mongodb query

@param query mongodb query

# File lib/puppetdb_query/mongodb.rb, line 66
def query_nodes(query)
  collection = connection[nodes_collection]
  collection.find(query).batch_size(999).projection(_id: 1).map { |k| k[:_id] }
end
search_facts(query, pattern, facts = [], facts_found = [], check_names = false) click to toggle source

get nodes and their facts for a pattern

@param query mongodb query @param pattern [RegExp] search for @param facts [Array<String>] get these facts in the result, eg ['fqdn'], empty for all @param facts_found [Array<String>] fact names are added to this array @param check_names [Boolean] also search fact names

# File lib/puppetdb_query/mongodb.rb, line 108
def search_facts(query, pattern, facts = [], facts_found = [], check_names = false)
  collection = connection[nodes_collection]
  result = {}
  collection.find(query).batch_size(999).each do |values|
    id = values.delete('_id')
    found = {}
    values.each do |k, v|
      if v =~ pattern
        found[k] = v
      elsif check_names && k =~ pattern
        found[k] = v
      end
    end
    next if found.empty?
    facts_found.concat(found.keys).uniq!
    facts.each do |f|
      found[f] = values[f]
    end
    result[id] = found
  end
  result
end
single_node_facts(node, facts) click to toggle source

get facts for given node name

@param node [String] node name @param facts [Array<String>] get these facts in the result, eg ['fqdn'], empty for all

# File lib/puppetdb_query/mongodb.rb, line 135
def single_node_facts(node, facts)
  fields = Hash[facts.collect { |fact| [fact.to_sym, 1] }]
  collection = connection[nodes_collection]
  result = collection.find(_id: node).limit(1).batch_size(1).projection(fields).to_a.first
  result.delete("_id") if result
  result
end