Puppet Function: extlib::remote_pql_query

Defined in:
lib/puppet/functions/extlib/remote_pql_query.rb
Function type:
Ruby 4.x API

Overview

Perform a PuppetDB query on an arbitrary PuppetDB server

If you need to query a PuppetDB server that is not connected to your Puppet Server (perhaps part of a separate Puppet installation that uses its own PKI), then this function is for you!

The ‘puppetdb-ruby` gem must be installed in your puppetserver’s ruby environment before you can use this function!

Signatures:

  • extlib::remote_pql_query(String[1] $query, HTTPSUrl $url, String[1] $key, String[1] $cert, String[1] $cacert, Optional[Hash] $options)Array

    Returns the PQL query response results

    Parameters:

    • query (String[1])

      The PQL query to run

    • url (HTTPSUrl)

      The PuppetDB HTTPS URL (SSL with cert-based authentication)

    • key (String[1])

      The client SSL key associated with the SSL client certificate

    • cert (String[1])

      The client SSL cert to present to PuppetDB

    • cacert (String[1])

      The CA certificate

    • options (Optional[Hash])

    Returns:

    • (Array)

      Returns the PQL query response results

  • extlib::remote_pql_query(String[1] $query, HTTPUrl $url, Optional[Hash] $options)Array

    Returns the PQL query response results

    Examples:

    ‘Collecting’ exported resource defined type from a foreign PuppetDB

    $pql_results = extlib::remote_pql_query(
      "resources[title,parameters] { type = \"My_Module::My_type\" and nodes { deactivated is null } and exported = true and parameters.collect_on = \"${trusted['certname']}\" }",
      'http://puppetdb.example.com:8080',
    )
    $pql_results.each |$result| {
      my_module::my_type { $result['title']:
        * => $result['parameters']
      }
    }

    Parameters:

    Returns:

    • (Array)

      Returns the PQL query response results



13
14
15
16
17
18
19
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/puppet/functions/extlib/remote_pql_query.rb', line 13

Puppet::Functions.create_function(:'extlib::remote_pql_query') do
  local_types do
    type 'HTTPUrl = Pattern[/(?i:\Ahttp:\/\/.*\z)/]'
    type 'HTTPSUrl = Pattern[/(?i:\Ahttps:\/\/.*\z)/]'
  end

  # @param query The PQL query to run
  # @param url The PuppetDB HTTPS URL (SSL with cert-based authentication)
  # @param key The client SSL key associated with the SSL client certificate
  # @param cert The client SSL cert to present to PuppetDB
  # @param cacert The CA certificate
  # @param options PuppetDB query options. (See https://www.puppet.com/docs/puppetdb/8/api/query/v4/paging)
  # @return Returns the PQL query response results
  dispatch :secure_remote_pql_query do
    param 'String[1]', :query
    param 'HTTPSUrl',  :url
    param 'String[1]', :key
    param 'String[1]', :cert
    param 'String[1]', :cacert
    optional_param 'Hash', :options
    return_type 'Array'
  end

  # @param query The PQL query to run
  # @param url The PuppetDB HTTP URL (non SSL version)
  # @param options PuppetDB query options. (See https://www.puppet.com/docs/puppetdb/8/api/query/v4/paging)
  # @return Returns the PQL query response results
  # @example 'Collecting' exported resource defined type from a foreign PuppetDB
  #   $pql_results = extlib::remote_pql_query(
  #     "resources[title,parameters] { type = \"My_Module::My_type\" and nodes { deactivated is null } and exported = true and parameters.collect_on = \"${trusted['certname']}\" }",
  #     'http://puppetdb.example.com:8080',
  #   )
  #   $pql_results.each |$result| {
  #     my_module::my_type { $result['title']:
  #       * => $result['parameters']
  #     }
  #   }
  dispatch :insecure_remote_pql_query do
    param 'String[1]', :query
    param 'HTTPUrl', :url
    optional_param 'Hash', :options
    return_type 'Array'
  end

  def secure_remote_pql_query(query, url, key, cert, cacert, options = {})
    keyfile  = Tempfile.new('remote_pql_query_keyfile')
    certfile = Tempfile.new('remote_pql_query_certfile')
    cafile   = Tempfile.new('remote_pql_query_cafile')

    begin
      keyfile.write(key)
      keyfile.close

      certfile.write(cert)
      certfile.close

      cafile.write(cacert)
      cafile.close

      client_options = {
        server: url,
        pem: {
          'key' => keyfile.path,
          'cert' => certfile.path,
          'ca_file' => cafile.path,
        }
      }

      remote_pql_query(query, options, client_options)
    ensure
      [keyfile, certfile, cafile].each(&:unlink)
    end
  end

  def insecure_remote_pql_query(query, url, options = {})
    client_options = { server: url }

    remote_pql_query(query, options, client_options)
  end

  def remote_pql_query(query, query_options, client_options)
    require 'puppetdb'

    # If the dalen/puppetdbquery module is installed, then there'll be a clash
    # of libraries/namespaces and we need to manually require the files from
    # puppetdb-ruby...
    unless PuppetDB.constants.include?(:Client)
      require 'puppetdb/client'
      require 'puppetdb/query'
      require 'puppetdb/response'
      require 'puppetdb/error'
      require 'puppetdb/config'
    end

    client = PuppetDB::Client.new(client_options)

    begin
      response = client.request(
        '', # PQL
        query,
        query_options
      )

      response.data
    rescue PuppetDB::APIError => e
      raise Puppet::Error, "PuppetDB API Error: #{e.response.inspect}"
    rescue StandardError => e
      raise Puppet::Error, "Remote PQL query failed: #{e.message}"
    end
  end
end