Class: Puppet::CatalogDiff::SearchFacts

Inherits:
Object
  • Object
show all
Defined in:
lib/puppet/catalog-diff/searchfacts.rb

Overview

SearchFacts returns facts from local data, Puppet API, or PuppetDB

Instance Method Summary collapse

Constructor Details

#initialize(facts) ⇒ SearchFacts

Returns a new instance of SearchFacts.



10
11
12
# File 'lib/puppet/catalog-diff/searchfacts.rb', line 10

def initialize(facts)
  @facts = facts.split(',').map { |f| f.split('=') }.to_h
end

Instance Method Details

#build_query(env, version) ⇒ Object



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/puppet/catalog-diff/searchfacts.rb', line 25

def build_query(env, version)
  base_query = ['and', ['=', %w[node active], true]]
  query_field_catalog_environment = Puppet::Util::Package.versioncmp(version, '3') >= 0 ? 'catalog_environment' : 'catalog-environment'
  base_query.concat([['=', query_field_catalog_environment, env]]) if env
  real_facts = @facts.compact
  query = base_query.concat(real_facts.map { |k, v| ['=', ['fact', k], v] })
  classes = @facts.select { |_k, v| v.nil? }.to_h.keys
  classes.each do |c|
    capit = c.split('::').map(&:capitalize).join('::')
    query.concat(
      [['in', 'certname',
        ['extract', 'certname',
         ['select-resources',
          ['and',
           ['=', 'type', 'Class'],
           ['=', 'title', capit]]]]]]
    )
  end
  query
end

#find_nodes(options = {}) ⇒ Object



14
15
16
17
18
19
20
21
22
23
# File 'lib/puppet/catalog-diff/searchfacts.rb', line 14

def find_nodes(options = {})
  # Pull all nodes from PuppetDB
  old_env = options[:old_server].split('/')[1]
  Puppet.debug('Using PuppetDB to find active nodes')
  filter_env = options[:filter_old_env] ? old_env : nil
  active_nodes = find_nodes_puppetdb(filter_env, options[:puppetdb], options[:puppetdb_tls_cert], options[:puppetdb_tls_key], options[:puppetdb_tls_ca])
  raise 'No active nodes were returned from your fact search' if active_nodes.empty?

  active_nodes
end

#find_nodes_puppetdb(env, puppetdb, puppetdb_tls_cert, puppetdb_tls_key, puppetdb_tls_ca) ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/puppet/catalog-diff/searchfacts.rb', line 63

def find_nodes_puppetdb(env, puppetdb, puppetdb_tls_cert, puppetdb_tls_key, puppetdb_tls_ca)
  puppetdb_version = get_puppetdb_version(puppetdb, puppetdb_tls_cert, puppetdb_tls_key, puppetdb_tls_ca)
  query = build_query(env, puppetdb_version)
  json_query = URI.escape(query.to_json)
  headers = { 'Accept' => 'application/json' }
  Puppet.debug("Querying #{puppetdb} for environment #{env}")
  begin
    ssl_context = Puppet::CatalogDiff::Tlsfactory.ssl_context(puppetdb_tls_cert, puppetdb_tls_key, puppetdb_tls_ca)
    uri = URI("#{puppetdb}/pdb/query/v4/nodes?query=#{json_query}")
    result = Puppet.runtime[:http].get(uri, headers: headers, options: { ssl_context: ssl_context })
    if result.code >= 400
      puppetdb_version = '2.3'
      Puppet.debug("Query returned HTTP code #{result.code}. Falling back to older version of API used in PuppetDB version #{puppetdb_version}.")
      query = build_query(env, puppetdb_version)
      json_query = URI.escape(query.to_json)
      result = Puppet.runtime[:http].get(URI("#{puppetdb}/pdb/query/v4/nodes?query=#{json_query}"), headers: headers)
    end
    filtered = PSON.parse(result.body)
  rescue PSON::ParserError => e
    raise "Error parsing json output of puppet search: #{e.message}"
  end
  filtered.map { |node| node['certname'] }
end

#get_puppetdb_version(server, puppetdb_tls_cert, puppetdb_tls_key, puppetdb_tls_ca) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/puppet/catalog-diff/searchfacts.rb', line 46

def get_puppetdb_version(server, puppetdb_tls_cert, puppetdb_tls_key, puppetdb_tls_ca)
  headers = { 'Accept' => 'application/json' }
  ssl_context = Puppet::CatalogDiff::Tlsfactory.ssl_context(puppetdb_tls_cert, puppetdb_tls_key, puppetdb_tls_ca)
  Puppet.debug("connecting to #{server}")
  uri = URI("#{server}/pdb/meta/v1/version")
  result = Puppet.runtime[:http].get(uri, headers: headers, options: { ssl_context: ssl_context })
  if result.code == 200
    body = JSON.parse(result.body)
    version = body['version']
    Puppet.debug("Got PuppetDB version: #{version} from HTTP API.")
  else
    version = '2.3'
    Puppet.debug("Getting PuppetDB version failed because HTTP API query returned code #{result.code}. Falling back to PuppetDB version #{version}.")
  end
  version
end