Module: Puppet::Resource::CapabilityFinder Private

Defined in:
lib/puppet/resource/capability_finder.rb

This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.

Class Method Summary collapse

Class Method Details

.find(environment, code_id, cap) ⇒ Puppet::Resource?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Looks the capability resource from PuppetDB.

Parameters:

  • environment (String)

    environment name

  • code_id (String, nil)

    code_id of the catalog

  • cap (Puppet::Type)

    the capability resource type instance

Returns:

  • (Puppet::Resource, nil)

    The found capability resource or ‘nil` if it could not be found



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/puppet/resource/capability_finder.rb', line 20

def self.find(environment, code_id, cap)
  unless Puppet::Util.const_defined?('Puppetdb')
    raise Puppet::DevError, 'PuppetDB is not available'
  end

  query_terms = [
    'and',
    ['=', 'type', cap.type.capitalize],
    ['=', 'title', cap.title.to_s],
    ['=', 'tag', "producer:#{environment}"]
  ]

  unless code_id.nil?
    query_terms << ['in', 'certname',
      ['extract', 'certname',
        ['select_catalogs',
          ['=', 'code_id', code_id]]]]
  end
  query = query_terms.to_json

  Puppet.notice "Capability lookup #{cap}]: #{query}"

  http = Puppet::Util.const_get('Puppetdb').const_get('Http')
  response = http.action("/pdb/query/v4/resources?query=#{CGI.escape(query)}") do |conn, uri|
    conn.get(uri, { 'Accept' => 'application/json'})
  end
  json = response.body

  # The format of the response body is documented at
  #   http://docs.puppetlabs.com/puppetdb/3.0/api/query/v4/resources.html#response-format
  # In a nutshell, we expect to get an array of resources back. If the
  # array is empty, the lookup failed and we return +nil+, if it
  # contains exactly one, we turn that resource back into a Puppet
  # ::Resource. If the array contains more than one entry, we have a
  # bug in the overall system, as we allowed multiple capabilities with
  # the same type and title to be produced in this environment.
  begin
    data = JSON.parse(json)
  rescue JSON::JSONError => e
    raise Puppet::DevError,
    "Invalid JSON from PuppetDB when looking up #{cap}\n#{e}\nRaw JSON was:\n#{json}"
  end
  unless data.is_a?(Array)
    raise Puppet::DevError,
    "Unexpected response from PuppetDB when looking up #{cap}: " +
      "expected an Array but got #{data.inspect}"
  end
  if data.size > 1
    raise Puppet::DevError,
    "Unexpected response from PuppetDB when looking up #{cap}:\n" +
      "expected exactly one resource but got #{data.size};\n" +
      "returned data is:\n#{data.inspect}"
  end

  unless data.empty?
    resource_hash = data.first
    resource = Puppet::Resource.new(resource_hash['type'],
                                    resource_hash['title'])
    real_type = Puppet::Type.type(resource.type)
    if real_type.nil?
      fail Puppet::ParseError,
        "Could not find resource type #{resource.type} returned from PuppetDB"
    end
    real_type.parameters.each do |param|
      param = param.to_s
      next if param == 'name'
      if value = resource_hash['parameters'][param]
        resource[param] = value
      else
        Puppet.debug "No capability value for #{resource}->#{param}"
      end
    end
    return resource
  end
end