Skip to content

Commit 8550721

Browse files
authored
Merge pull request #229 from seanmil/add_packages_inventory
Add support for PE package inventory facts
2 parents 5ae7f1b + f1d73ce commit 8550721

File tree

7 files changed

+285
-28
lines changed

7 files changed

+285
-28
lines changed

doc/configuration-puppetdb.md

+8
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,11 @@ SSL support is enabled via any of the `--puppetdb-ssl-...` command line options
6767
- The CA certificate should be the public certificate of the CA that signed your PuppetDB server's certificate. This file can be found in `/etc/puppetlabs/puppetdb/ssl/ca.pem` on a PuppetDB server. Since this is a public certificate, it is safe (and recommended) to distribute this file to any clients that may connect to this PuppetDB instance.
6868

6969
- The client keypair (key, certificate, and optionally password) should be generated individually for each client. You should NOT copy SSL keypairs from your PuppetDB server (or anywhere else) to your clients. If you are using `octocatalog-diff` on a system that is managed by Puppet, you may wish to use the same SSL credentials that the system uses to authenticate to Puppet. With recent versions of the Puppet agent, those certificates are found in `/etc/puppetlabs/puppet/ssl`.
70+
71+
# Puppet Enterprise PuppetDB Package Inventory
72+
73+
Puppet Enterprise customers have an optional package inventory feature which can be enabled. When this feature is enabled an inventory of all system packages
74+
is performed and uploaded as a fact which is then processed and stored independently of the normal Facter data in PuppetDB. Most environments won't need
75+
to replicate the package inventory facts for testing with Octocatalog-Diff but if you want the package inventory data (if present) to be included
76+
in the facts retrieved from PuppetDB by Octocatalog-Diff you should specify the `--puppetdb-package-inventory` flag. When enabled, this flag will instruct
77+
Octocatalog-Diff to retrieve any package data found for a node from PuppetDB and include it in the facts used during the Octocatalog-Diff compile.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# frozen_string_literal: true
2+
3+
# When pulling facts from PuppetDB in a Puppet Enterprise environment, also include
4+
# the Puppet Enterprise Package Inventory data in the fact results, if available.
5+
# Generally you should not need to specify this, but including the package inventory
6+
# data will produce a more accurate set of input facts for environments using
7+
# package inventory.
8+
# @param parser [OptionParser object] The OptionParser argument
9+
# @param options [Hash] Options hash being constructed; this is modified in this method.
10+
OctocatalogDiff::Cli::Options::Option.newoption(:puppetdb_package_inventory) do
11+
has_weight 150
12+
13+
def parse(parser, options)
14+
parser.on('--[no-]puppetdb-package-inventory', 'Include Puppet Enterprise package inventory data, if found') do |x|
15+
options[:puppetdb_package_inventory] = x
16+
end
17+
end
18+
end

lib/octocatalog-diff/facts/puppetdb.rb

+43-2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def self.fact_retriever(options = {}, node)
3636
exception_class = nil
3737
exception_message = nil
3838
obj_to_return = nil
39+
packages = nil
3940
(retries + 1).times do
4041
begin
4142
result = puppetdb.get(uri)
@@ -61,8 +62,48 @@ def self.fact_retriever(options = {}, node)
6162
exception_message = "Fact retrieval failed for node #{node} from PuppetDB (#{exc.message})"
6263
end
6364
end
64-
return obj_to_return unless obj_to_return.nil?
65-
raise exception_class, exception_message
65+
66+
raise exception_class, exception_message if obj_to_return.nil?
67+
68+
return obj_to_return if puppetdb_api_version < 4 || (!options[:puppetdb_package_inventory])
69+
70+
(retries + 1).times do
71+
begin
72+
result = puppetdb.get("/pdb/query/v4/package-inventory/#{node}")
73+
packages = {}
74+
result.each do |pkg|
75+
key = "#{pkg['package_name']}+#{pkg['provider']}"
76+
# Need to handle the situation where a package has multiple versions installed.
77+
# The _puppet_inventory_1 hash lists them separated by "; ".
78+
if packages.key?(key)
79+
packages[key]['version'] += "; #{pkg['version']}"
80+
else
81+
packages[key] = pkg
82+
end
83+
end
84+
break
85+
rescue OctocatalogDiff::Errors::PuppetDBConnectionError => exc
86+
exception_class = OctocatalogDiff::Errors::FactSourceError
87+
exception_message = "Package inventory retrieval failed (#{exc.class}) (#{exc.message})"
88+
# This is not expected to occur, but we'll leave it just in case. A query to package-inventory
89+
# for a non-existant node returns a 200 OK with an empty list of packages:
90+
rescue OctocatalogDiff::Errors::PuppetDBNodeNotFoundError
91+
packages = {}
92+
rescue OctocatalogDiff::Errors::PuppetDBGenericError => exc
93+
exception_class = OctocatalogDiff::Errors::FactRetrievalError
94+
exception_message = "Package inventory retrieval failed for node #{node} from PuppetDB (#{exc.message})"
95+
end
96+
end
97+
98+
raise exception_class, exception_message if packages.nil?
99+
100+
unless packages.empty?
101+
obj_to_return['values']['_puppet_inventory_1'] = {
102+
'packages' => packages.values.map { |pkg| [pkg['package_name'], pkg['version'], pkg['provider']] }
103+
}
104+
end
105+
106+
obj_to_return
66107
end
67108
end
68109
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--- !ruby/object:Puppet::Node::Facts
2+
name: rspec-node.xyz.github.net
3+
values:
4+
_timestamp: '2016-03-16 16:02:13 -0500'
5+
apt_update_last_success: 1458162123
6+
architecture: amd64
7+
clientcert: rspec-node.github.net
8+
datacenter: xyz
9+
domain: xyz.github.net
10+
fqdn: rspec-node.xyz.github.net
11+
ipaddress: 10.20.30.40
12+
kernel: Linux
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[
2+
{
3+
"certname": "valid-packages",
4+
"package_name": "kernel",
5+
"version": "3.2.1",
6+
"provider": "yum"
7+
},
8+
{
9+
"certname": "valid-packages",
10+
"package_name": "bash",
11+
"version": "4.0.0",
12+
"provider": "yum"
13+
}
14+
]

spec/octocatalog-diff/mocks/puppetdb.rb

+16
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ def initialize(overrides = {})
2424
def get(uri)
2525
return facts(Regexp.last_match(1)) if uri =~ %r{^/pdb/query/v4/nodes/([^/]+)/facts$}
2626
return catalog(Regexp.last_match(1)) if uri =~ %r{^/pdb/query/v4/catalogs/(.+)$}
27+
return packages(Regexp.last_match(1)) if uri =~ %r{^/pdb/query/v4/package-inventory/(.+)$}
2728
raise ArgumentError, "PuppetDB URL not mocked: #{uri}"
2829
end
2930

@@ -63,6 +64,21 @@ def catalog(hostname)
6364
raise OctocatalogDiff::Errors::PuppetDBNodeNotFoundError, '404 - Not Found' unless File.file?(fixture_file)
6465
JSON.parse(File.read(fixture_file))
6566
end
67+
68+
# Mock packages from PuppetDB
69+
# @param hostname [String] Host name
70+
# @return [String] JSON catalog
71+
def packages(hostname)
72+
fixture_file = OctocatalogDiff::Spec.fixture_path(File.join('packages', "#{hostname}.json"))
73+
74+
# If packages are requested from PuppetDB for an invalid node name, it will return 200 OK
75+
# with an empty list:
76+
if File.file?(fixture_file)
77+
JSON.parse(File.read(fixture_file))
78+
else
79+
[]
80+
end
81+
end
6682
end
6783
end
6884
end

0 commit comments

Comments
 (0)