Description
Description
When octocatalog-diff (version 2.1.0) is provided a set of facts via --facts-file
, it will fail if that file contains a json array straight out of puppetdb. Being able to use facts straight from puppetdb like this is useful for (e.g.) providing simple offline caching of facts.
For example:
$ curl -s http://puppetdb/pdb/query/v4/nodes/somehost.internal/facts > /tmp/somehost_facts.json
$ jq . /tmp/somehost_facts.json | head
[
{
"certname": "somehost.internal",
"environment": "production",
"name": "id",
"value": "root"
},
(etc)
and then:
$ octocatalog-diff --hostname somehost.internal --fact-file /tmp/somehost_facts.json
Traceback (most recent call last):
17: from /opt/puppetlabs/puppet/bin/octocatalog-diff:23:in `<main>'
16: from /opt/puppetlabs/puppet/bin/octocatalog-diff:23:in `load'
15: from /opt/puppetlabs/puppet/lib/ruby/gems/2.7.0/gems/octocatalog-diff-2.1.0/bin/octocatalog-diff:34:in `<top (required)>'
14: from /opt/puppetlabs/puppet/lib/ruby/gems/2.7.0/gems/octocatalog-diff-2.1.0/lib/octocatalog-diff/cli.rb:69:in `cli'
13: from /opt/puppetlabs/puppet/lib/ruby/gems/2.7.0/gems/octocatalog-diff-2.1.0/lib/octocatalog-diff/cli.rb:168:in `parse_opts'
12: from /opt/puppetlabs/puppet/lib/ruby/gems/2.7.0/gems/octocatalog-diff-2.1.0/lib/octocatalog-diff/cli/options.rb:66:in `parse_options'
11: from /opt/puppetlabs/puppet/lib/ruby/2.7.0/optparse.rb:1691:in `parse!'
10: from /opt/puppetlabs/puppet/lib/ruby/2.7.0/optparse.rb:1666:in `permute!'
9: from /opt/puppetlabs/puppet/lib/ruby/2.7.0/optparse.rb:1569:in `order!'
8: from /opt/puppetlabs/puppet/lib/ruby/2.7.0/optparse.rb:1575:in `parse_in_order'
7: from /opt/puppetlabs/puppet/lib/ruby/2.7.0/optparse.rb:1575:in `catch'
6: from /opt/puppetlabs/puppet/lib/ruby/2.7.0/optparse.rb:1589:in `block in parse_in_order'
5: from /opt/puppetlabs/puppet/lib/ruby/gems/2.7.0/gems/octocatalog-diff-2.1.0/lib/octocatalog-diff/cli/options.rb:128:in `block in option_globally_or_per_branch_string'
4: from /opt/puppetlabs/puppet/lib/ruby/gems/2.7.0/gems/octocatalog-diff-2.1.0/lib/octocatalog-diff/cli/options.rb:238:in `translate_option'
3: from /opt/puppetlabs/puppet/lib/ruby/gems/2.7.0/gems/octocatalog-diff-2.1.0/lib/octocatalog-diff/cli/options/fact_file.rb:23:in `block in parse'
2: from /opt/puppetlabs/puppet/lib/ruby/gems/2.7.0/gems/octocatalog-diff-2.1.0/lib/octocatalog-diff/cli/options/fact_file.rb:23:in `new'
1: from /opt/puppetlabs/puppet/lib/ruby/gems/2.7.0/gems/octocatalog-diff-2.1.0/lib/octocatalog-diff/facts.rb:27:in `initialize'
/opt/puppetlabs/puppet/lib/ruby/gems/2.7.0/gems/octocatalog-diff-2.1.0/lib/octocatalog-diff/facts/json.rb:18:in `fact_retriever': undefined method `keys' for #<Array:0x00000000024a04c8> (NoMethodError)
Possible Fix
One possible fix would be to add something similar to the following immediately after the JSON::parse
call in self.fact_retriever
, inside facts/json.rb
:
if facts.is_a?(Array) && facts[0].is_a?(Hash) && facts[0].keys.include?('certname')
# you probably gave us the raw puppetdb output
fixed_facts = {}
facts.map { |x| fixed_facts[x['name']] = x['value'] }
facts = fixed_facts
end
This works, and allows catalogs to be built using that straight-from-puppetdb json goodness.
I am not submitting this as a pull request because 1-- I don't really know ruby but the above feels a bit sloppy to me and I suspect there might be a more ruby-like way to handle this, and 2-- getting myself a test environment that can actually run and pass the entire octocatalog-diff unit test suite has been... challenging. I'll be happy to submit the above as a PR if that is your desire, though.
Environment
Although it is unlikely to matter in this specific case:
- OS:
CentOS Linux release 8.2.2004
- Ruby version:
ruby 2.7.3p183 (2021-04-05 revision 6847ee089d) [x86_64-linux]
(the bundled ruby from the puppet agent) - Puppet version:
puppet-agent-7.10.0-1.el8.x86_64
(official PuppetLabs puppet-agent RPM) - octocatalog-diff version:
octocatalog-diff 2.1.0