class VcenterLibMongodb::Mongodb

access vms and their facts from mongo database

Attributes

connection[R]
convert[R]
meta_collection[R]
vms_collection[R]

Public Class Methods

new(connection, vms = :vms, 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 vms symbol for collection that contains vms with their facts @param meta symbol for collection with update metadata

# File lib/vcenter_lib_mongodb/mongodb.rb, line 23
def initialize(connection, vms = :vms, meta = :meta)
  @connection = connection
  @vms_collection = vms
  @meta_collection = meta
  @convert = ::PuppetDBQuery::ToMongo.new
end

Public Instance Methods

all_vms() click to toggle source

get all vm names

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

get all vms and their facts

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

# File lib/vcenter_lib_mongodb/mongodb.rb, line 126
def facts(facts = [])
  fields = Hash[facts.collect { |fact| [fact.to_sym, 1] }]
  collection = connection[vms_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/vcenter_lib_mongodb/mongodb.rb, line 138
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/vcenter_lib_mongodb/mongodb.rb, line 186
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
query_facts(query, facts = []) click to toggle source

get vms and their facts that fulfill given mongodb query

@param query a query for VMs @param facts [Array<String>] get these facts in the result, eg ['boot_time'], empty for all @return [Hash<name, <fact , value>>] VM names with their facts and values

# File lib/vcenter_lib_mongodb/mongodb.rb, line 53
def query_facts(query, facts = [])
  mongo_query = convert.query(query)
  fields = Hash[facts.collect { |fact| [fact.to_sym, 1] }]
  collection = connection[vms_collection]
  result = {}
  collection.find(mongo_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 vms 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/vcenter_lib_mongodb/mongodb.rb, line 70
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_vms(query) click to toggle source

get vm names that fulfill given query

@param query [String] a query for VMs.

nil or white space only string will return all VMs

@return [Array<String>] names of VMs that fulfill the query

# File lib/vcenter_lib_mongodb/mongodb.rb, line 41
def query_vms(query)
  return all_vms if query.nil? || query.strip.empty?
  mongo_query = convert.query(query)
  collection = connection[vms_collection]
  collection.find(mongo_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 VMs 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/vcenter_lib_mongodb/mongodb.rb, line 87
def search_facts(query, pattern, facts = [], facts_found = [], check_names = false)
  mongo_query = convert.query(query)
  collection = connection[vms_collection]
  result = {}
  collection.find(mongo_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_vm_facts(vm, facts) click to toggle source

get facts for given vm name

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

# File lib/vcenter_lib_mongodb/mongodb.rb, line 115
def single_vm_facts(vm, facts)
  fields = Hash[facts.collect { |fact| [fact.to_sym, 1] }]
  collection = connection[vms_collection]
  result = collection.find(_id: vm).limit(1).batch_size(1).projection(fields).to_a.first
  result.delete("_id") if result
  result
end
vm_delete(vm) click to toggle source

delete vm data for given vm name

@param vm [String] vm name

# File lib/vcenter_lib_mongodb/mongodb.rb, line 181
def vm_delete(vm)
  connection[vms_collection].find(_id: vm).delete_one
end
vm_update(vm, facts) click to toggle source

update or insert facts for given vm name

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

# File lib/vcenter_lib_mongodb/mongodb.rb, line 149
def vm_update(vm, facts)
  logger.debug "  updating #{vm}"
  connection[vms_collection].find(_id: vm).replace_one(facts,
    upsert:                     true,
    bypass_document_validation: true,
    check_keys:                 false,
    validating_keys:            false)
rescue ::Mongo::Error::OperationFailure => e
  logger.warn "  updating #{vm} 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[vms_collection].find(_id: vm).replace_one(facts,
      upsert: true,
      bypass_document_validation: true,
      check_keys: false,
      validating_keys: false)
  rescue
    logger.error "  inserting #{vm} failed again with: #{e.message}"
  end
end