diff --git a/.gitignore b/.gitignore index 8e7674ed..d5b1dfc5 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,7 @@ build-iPhoneSimulator/ ## Environment normalization: /.bundle/ /vendor/bundle +/vendor/cache /lib/bundler/man/ # for a library or gem, you might want to ignore these files since the code is diff --git a/README.md b/README.md index ba3207b9..c4649cea 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,8 @@ There are some [limitations](doc/limitations.md) to a catalog-based approach, me - Obtain catalog over the network using the API to query a Puppet Master / PuppetServer (Puppet 3.x through 6.x supported) - Read catalog from a JSON file +Facts can be sourced from PuppetDB, a single fact file (`--fact-file`), or a per-node fact directory (`--fact-dir`). + ## Example Here is simulated output from running `octocatalog-diff` to compare the Puppet catalog changes between the master branch and the Puppet code in the current working directory: diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 1dd7d7dc..d5e9ce9c 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -12,6 +12,7 @@
--fact-file STRING
@@ -688,6 +703,18 @@ with `--preserve-environments`. (fact_dir.rb)
+ --from-fact-file STRING
@@ -1749,6 +1776,18 @@ with `--preserve-environments`. (fact_dir.rb)
+ --to-fact-file STRING
diff --git a/lib/octocatalog-diff/catalog-util/facts.rb b/lib/octocatalog-diff/catalog-util/facts.rb
index b30d9699..651ba10c 100644
--- a/lib/octocatalog-diff/catalog-util/facts.rb
+++ b/lib/octocatalog-diff/catalog-util/facts.rb
@@ -19,6 +19,10 @@ def initialize(options, logger = nil)
# Environment variable recognition
@options[:puppetdb_url] ||= ENV['PUPPETDB_URL'] if ENV['PUPPETDB_URL']
@options[:puppet_fact_dir] ||= ENV['PUPPET_FACT_DIR'] if ENV['PUPPET_FACT_DIR']
+
+ if @options[:fact_file_dir] && @options[:puppetdb_url]
+ raise ArgumentError, '--fact-dir and --puppetdb-url are mutually exclusive'
+ end
end
# Compute facts if needed and then return them
@@ -34,14 +38,37 @@ def facts
# @return [OctocatalogDiff::Facts] Facts object
def facts_from_file(filename)
@logger.debug("Retrieving facts from #{filename}") unless @logger.nil?
+ backend = filename =~ /\.json$/ ? :json : :yaml
opts = {
node: @options[:node],
- backend: :yaml,
+ backend: backend,
fact_file_string: File.read(filename)
}
OctocatalogDiff::Facts.new(opts)
end
+ # Retrieve facts from a directory of fact files, selecting by node name
+ # @param dir [String] Directory containing fact files
+ # @param node [String] Node name
+ # @return [OctocatalogDiff::Facts] Facts object
+ def facts_from_dir(dir, node)
+ filename = fact_file_for_node(dir, node)
+ return facts_from_file(filename) if filename
+ nil
+ end
+
+ # Determine the fact file name for a node (yaml or json)
+ # @param dir [String] Directory containing fact files
+ # @param node [String] Node name
+ # @return [String, nil] Filename if found
+ def fact_file_for_node(dir, node)
+ ['.yaml', '.yml', '.json'].each do |ext|
+ filename = File.join(dir, node + ext)
+ return filename if File.file?(filename)
+ end
+ nil
+ end
+
# Retrieve facts from PuppetDB. Either options[:puppetdb_url] or ENV['PUPPETDB_URL']
# needs to be set for this to work. Node name must also be set in options.
# @return [OctocatalogDiff::Facts] Facts object
@@ -75,6 +102,11 @@ def compute_facts
error_node_not_provided if @options[:node].nil?
+ if @options[:fact_file_dir] && File.directory?(@options[:fact_file_dir])
+ facts = facts_from_dir(@options[:fact_file_dir], @options[:node])
+ return facts if facts
+ end
+
if @options[:puppet_fact_dir] && File.directory?(@options[:puppet_fact_dir])
filename = File.join(@options[:puppet_fact_dir], @options[:node] + '.yaml')
return facts_from_file(filename) if File.file?(filename)
@@ -82,8 +114,9 @@ def compute_facts
return facts_from_puppetdb if @options[:puppetdb_url]
- message = 'Unable to compute facts for node. Please use "--fact-file FILENAME" option' \
- ' or set one of these environment variables: PUPPET_FACT_DIR or PUPPETDB_URL.'
+ message = 'Unable to compute facts for node. Please use "--fact-file FILENAME" or' \
+ ' "--fact-dir DIRECTORY" option, or set one of these environment variables:' \
+ ' PUPPET_FACT_DIR or PUPPETDB_URL.'
raise ArgumentError, message
end
end
diff --git a/lib/octocatalog-diff/cli/options/fact_dir.rb b/lib/octocatalog-diff/cli/options/fact_dir.rb
new file mode 100644
index 00000000..34a14b6a
--- /dev/null
+++ b/lib/octocatalog-diff/cli/options/fact_dir.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+# Allow a directory of per-node fact files to be provided, to avoid pulling facts from PuppetDB.
+# @param parser [OptionParser object] The OptionParser argument
+# @param options [Hash] Options hash being constructed; this is modified in this method.
+OctocatalogDiff::Cli::Options::Option.newoption(:fact_dir) do
+ has_weight 149
+
+ def parse(parser, options)
+ OctocatalogDiff::Cli::Options.option_globally_or_per_branch(
+ parser: parser,
+ options: options,
+ cli_name: 'fact-dir',
+ option_name: 'fact_file_dir',
+ desc: 'Fact directory',
+ datatype: '',
+ validator: lambda do |fact_dir|
+ base_dir = options[:basedir]
+ path = fact_dir.start_with?('/') ? File.expand_path(fact_dir) : File.expand_path(File.join(base_dir.to_s, fact_dir))
+ raise Errno::ENOENT, "Fact directory #{path} does not exist" unless Dir.exist?(path)
+ end,
+ translator: lambda do |fact_dir|
+ base_dir = options[:basedir]
+ fact_dir.start_with?('/') ? File.expand_path(fact_dir) : File.expand_path(File.join(base_dir.to_s, fact_dir))
+ end,
+ post_process: lambda do |opts|
+ if opts[:puppetdb_url]
+ raise ArgumentError, '--fact-dir and --puppetdb-url are mutually exclusive'
+ end
+ if opts[:to_facts] || opts[:from_facts] || opts[:facts] || opts[:fact_file]
+ raise ArgumentError, '--fact-dir and --fact-file are mutually exclusive'
+ end
+ end
+ )
+ end
+end
diff --git a/lib/octocatalog-diff/cli/options/fact_file.rb b/lib/octocatalog-diff/cli/options/fact_file.rb
index 10384b2e..2cf535f1 100644
--- a/lib/octocatalog-diff/cli/options/fact_file.rb
+++ b/lib/octocatalog-diff/cli/options/fact_file.rb
@@ -29,6 +29,9 @@ def parse(parser, options)
end
end,
post_process: lambda do |opts|
+ if opts[:fact_file_dir]
+ raise ArgumentError, '--fact-file and --fact-dir are mutually exclusive'
+ end
unless options[:node]
%w[to_facts from_facts facts].each do |opt|
next unless opts[opt.to_sym] && opts[opt.to_sym].node
diff --git a/lib/octocatalog-diff/cli/options/puppetdb_url.rb b/lib/octocatalog-diff/cli/options/puppetdb_url.rb
index f133b5f4..54e2391e 100644
--- a/lib/octocatalog-diff/cli/options/puppetdb_url.rb
+++ b/lib/octocatalog-diff/cli/options/puppetdb_url.rb
@@ -15,6 +15,9 @@ def parse(parser, options)
# support HTTP begrudgingly as well.
obj = URI.parse(url)
raise ArgumentError, 'PuppetDB URL must be http or https' unless obj.is_a?(URI::HTTPS) || obj.is_a?(URI::HTTP)
+ if options[:fact_file_dir] || options[:from_fact_file_dir] || options[:to_fact_file_dir]
+ raise ArgumentError, '--puppetdb-url and --fact-dir are mutually exclusive'
+ end
options[:puppetdb_url] = url
end
end
diff --git a/spec/octocatalog-diff/fixtures/fact-dirs/json/rspec-node.xyz.github.net.json b/spec/octocatalog-diff/fixtures/fact-dirs/json/rspec-node.xyz.github.net.json
new file mode 100644
index 00000000..8413d003
--- /dev/null
+++ b/spec/octocatalog-diff/fixtures/fact-dirs/json/rspec-node.xyz.github.net.json
@@ -0,0 +1,7 @@
+{
+ "apt_update_last_success":1458162123,
+ "architecture":"amd64",
+ "datacenter":"xyz",
+ "fqdn":"rspec-node.xyz.github.net",
+ "_timestamp":"2014-12-02 14:56:20 -0600"
+}
diff --git a/spec/octocatalog-diff/tests/catalog-util/facts_spec.rb b/spec/octocatalog-diff/tests/catalog-util/facts_spec.rb
index bdcab815..e954a178 100644
--- a/spec/octocatalog-diff/tests/catalog-util/facts_spec.rb
+++ b/spec/octocatalog-diff/tests/catalog-util/facts_spec.rb
@@ -32,6 +32,43 @@
end
end
+ context 'facts from fact directory' do
+ describe '#facts' do
+ it 'should read a YAML file from fact dir' do
+ fact_dir = OctocatalogDiff::Spec.fixture_path('facts')
+ testobj = OctocatalogDiff::CatalogUtil::Facts.new(node: 'valid-facts', fact_file_dir: fact_dir)
+ answer = OctocatalogDiff::Facts.new(
+ backend: :yaml,
+ fact_file_string: File.read(OctocatalogDiff::Spec.fixture_path('facts/valid-facts.yaml')),
+ node: 'valid-facts'
+ )
+ expect(testobj.facts.facts).to eq(answer.facts)
+ end
+
+ it 'should read a JSON file from fact dir' do
+ fact_dir = OctocatalogDiff::Spec.fixture_path('fact-dirs/json')
+ testobj = OctocatalogDiff::CatalogUtil::Facts.new(node: 'rspec-node.xyz.github.net', fact_file_dir: fact_dir)
+ answer = OctocatalogDiff::Facts.new(
+ backend: :json,
+ fact_file_string: File.read(OctocatalogDiff::Spec.fixture_path('fact-dirs/json/rspec-node.xyz.github.net.json')),
+ node: 'rspec-node.xyz.github.net'
+ )
+ expect(testobj.facts.facts).to eq(answer.facts)
+ end
+
+ it 'should raise an error when puppetdb_url is also provided' do
+ fact_dir = OctocatalogDiff::Spec.fixture_path('facts')
+ expect do
+ OctocatalogDiff::CatalogUtil::Facts.new(
+ node: 'valid-facts',
+ fact_file_dir: fact_dir,
+ puppetdb_url: 'http://localhost:8080'
+ )
+ end.to raise_error(ArgumentError)
+ end
+ end
+ end
+
context 'facts from YAML' do
describe '#facts' do
it 'should read a YAML file and build facts' do
diff --git a/spec/octocatalog-diff/tests/cli/options/fact_dir_spec.rb b/spec/octocatalog-diff/tests/cli/options/fact_dir_spec.rb
new file mode 100644
index 00000000..b313d7e9
--- /dev/null
+++ b/spec/octocatalog-diff/tests/cli/options/fact_dir_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require_relative '../options_helper'
+
+describe OctocatalogDiff::Cli::Options do
+ describe '#opt_fact_dir' do
+ let(:fact_dir) { OctocatalogDiff::Spec.fixture_path('facts') }
+
+ it 'should set fact_file_dir for to/from when provided' do
+ result = run_optparse(['--fact-dir', fact_dir])
+ expect(result[:to_fact_file_dir]).to eq(fact_dir)
+ expect(result[:from_fact_file_dir]).to eq(fact_dir)
+ end
+
+ it 'should allow branch-specific values' do
+ result = run_optparse(['--to-fact-dir', fact_dir])
+ expect(result[:to_fact_file_dir]).to eq(fact_dir)
+ expect(result.key?(:from_fact_file_dir)).to be(false)
+ end
+
+ it 'should resolve relative paths against basedir' do
+ result = run_optparse(['--fact-dir', 'spec/octocatalog-diff/fixtures/facts'], basedir: Dir.pwd)
+ expect(result[:to_fact_file_dir]).to eq(fact_dir)
+ expect(result[:from_fact_file_dir]).to eq(fact_dir)
+ end
+
+ it 'should throw error if --puppetdb-url is also provided' do
+ expect do
+ run_optparse(['--fact-dir', fact_dir, '--puppetdb-url', 'http://localhost:8080'])
+ end.to raise_error(ArgumentError)
+ end
+ end
+end
diff --git a/spec/octocatalog-diff/tests/cli/options/fact_file_spec.rb b/spec/octocatalog-diff/tests/cli/options/fact_file_spec.rb
index ea565439..d43f5dfb 100644
--- a/spec/octocatalog-diff/tests/cli/options/fact_file_spec.rb
+++ b/spec/octocatalog-diff/tests/cli/options/fact_file_spec.rb
@@ -47,6 +47,14 @@
run_optparse(['--fact-file', fact_file])
end.to raise_error(Errno::ENOENT)
end
+
+ it 'should throw error if --fact-dir is also provided' do
+ expect do
+ fact_file = OctocatalogDiff::Spec.fixture_path('facts/facts.yaml')
+ fact_dir = OctocatalogDiff::Spec.fixture_path('facts')
+ run_optparse(['--fact-file', fact_file, '--fact-dir', fact_dir])
+ end.to raise_error(ArgumentError)
+ end
end
describe '#opt_to_fact_file' do
diff --git a/vendor/cache/CFPropertyList-2.2.8.gem b/vendor/cache/CFPropertyList-2.2.8.gem
deleted file mode 100644
index adf1cf0c..00000000
Binary files a/vendor/cache/CFPropertyList-2.2.8.gem and /dev/null differ
diff --git a/vendor/cache/ast-2.4.2.gem b/vendor/cache/ast-2.4.2.gem
deleted file mode 100644
index abe16436..00000000
Binary files a/vendor/cache/ast-2.4.2.gem and /dev/null differ
diff --git a/vendor/cache/concurrent-ruby-1.1.7.gem b/vendor/cache/concurrent-ruby-1.1.7.gem
deleted file mode 100644
index ae9b3702..00000000
Binary files a/vendor/cache/concurrent-ruby-1.1.7.gem and /dev/null differ
diff --git a/vendor/cache/deep_merge-1.2.1.gem b/vendor/cache/deep_merge-1.2.1.gem
deleted file mode 100644
index ee9d198f..00000000
Binary files a/vendor/cache/deep_merge-1.2.1.gem and /dev/null differ
diff --git a/vendor/cache/diff-lcs-1.5.1.gem b/vendor/cache/diff-lcs-1.5.1.gem
deleted file mode 100644
index c070cb0d..00000000
Binary files a/vendor/cache/diff-lcs-1.5.1.gem and /dev/null differ
diff --git a/vendor/cache/diffy-3.4.2.gem b/vendor/cache/diffy-3.4.2.gem
deleted file mode 100644
index f6c83e44..00000000
Binary files a/vendor/cache/diffy-3.4.2.gem and /dev/null differ
diff --git a/vendor/cache/facter-2.5.7.gem b/vendor/cache/facter-2.5.7.gem
deleted file mode 100644
index 0c49e7c5..00000000
Binary files a/vendor/cache/facter-2.5.7.gem and /dev/null differ
diff --git a/vendor/cache/fast_gettext-1.1.2.gem b/vendor/cache/fast_gettext-1.1.2.gem
deleted file mode 100644
index 9dac89ed..00000000
Binary files a/vendor/cache/fast_gettext-1.1.2.gem and /dev/null differ
diff --git a/vendor/cache/gettext-3.2.6.gem b/vendor/cache/gettext-3.2.6.gem
deleted file mode 100644
index c36484ce..00000000
Binary files a/vendor/cache/gettext-3.2.6.gem and /dev/null differ
diff --git a/vendor/cache/gettext-setup-0.30.gem b/vendor/cache/gettext-setup-0.30.gem
deleted file mode 100644
index 44e32ad4..00000000
Binary files a/vendor/cache/gettext-setup-0.30.gem and /dev/null differ
diff --git a/vendor/cache/hashdiff-1.1.1.gem b/vendor/cache/hashdiff-1.1.1.gem
deleted file mode 100644
index f0a3f1b8..00000000
Binary files a/vendor/cache/hashdiff-1.1.1.gem and /dev/null differ
diff --git a/vendor/cache/hocon-1.3.1.gem b/vendor/cache/hocon-1.3.1.gem
deleted file mode 100644
index e474ff66..00000000
Binary files a/vendor/cache/hocon-1.3.1.gem and /dev/null differ
diff --git a/vendor/cache/httparty-0.21.0.gem b/vendor/cache/httparty-0.21.0.gem
deleted file mode 100644
index 7c216b03..00000000
Binary files a/vendor/cache/httparty-0.21.0.gem and /dev/null differ
diff --git a/vendor/cache/httpclient-2.8.3.gem b/vendor/cache/httpclient-2.8.3.gem
deleted file mode 100644
index 9c19ad46..00000000
Binary files a/vendor/cache/httpclient-2.8.3.gem and /dev/null differ
diff --git a/vendor/cache/json-2.7.2.gem b/vendor/cache/json-2.7.2.gem
deleted file mode 100644
index 1c3c4680..00000000
Binary files a/vendor/cache/json-2.7.2.gem and /dev/null differ
diff --git a/vendor/cache/json_pure-1.8.6.gem b/vendor/cache/json_pure-1.8.6.gem
deleted file mode 100644
index 7380e49d..00000000
Binary files a/vendor/cache/json_pure-1.8.6.gem and /dev/null differ
diff --git a/vendor/cache/json_pure-2.0.2.gem b/vendor/cache/json_pure-2.0.2.gem
deleted file mode 100644
index 6716fb4b..00000000
Binary files a/vendor/cache/json_pure-2.0.2.gem and /dev/null differ
diff --git a/vendor/cache/mime-types-3.5.2.gem b/vendor/cache/mime-types-3.5.2.gem
deleted file mode 100644
index 57a6ae2f..00000000
Binary files a/vendor/cache/mime-types-3.5.2.gem and /dev/null differ
diff --git a/vendor/cache/mime-types-data-3.2023.1205.gem b/vendor/cache/mime-types-data-3.2023.1205.gem
deleted file mode 100644
index dbe83e66..00000000
Binary files a/vendor/cache/mime-types-data-3.2023.1205.gem and /dev/null differ
diff --git a/vendor/cache/parallel-1.24.0.gem b/vendor/cache/parallel-1.24.0.gem
deleted file mode 100644
index f2b99ea2..00000000
Binary files a/vendor/cache/parallel-1.24.0.gem and /dev/null differ
diff --git a/vendor/cache/puppet-4.10.10.gem b/vendor/cache/puppet-4.10.10.gem
deleted file mode 100644
index a98710dc..00000000
Binary files a/vendor/cache/puppet-4.10.10.gem and /dev/null differ
diff --git a/vendor/cache/puppet-5.5.22.gem b/vendor/cache/puppet-5.5.22.gem
deleted file mode 100644
index 66fc27d9..00000000
Binary files a/vendor/cache/puppet-5.5.22.gem and /dev/null differ
diff --git a/vendor/cache/puppet-5.5.8.gem b/vendor/cache/puppet-5.5.8.gem
deleted file mode 100644
index 38cd7dc7..00000000
Binary files a/vendor/cache/puppet-5.5.8.gem and /dev/null differ
diff --git a/vendor/cache/puppet-6.18.0.gem b/vendor/cache/puppet-6.18.0.gem
deleted file mode 100644
index c3bcc148..00000000
Binary files a/vendor/cache/puppet-6.18.0.gem and /dev/null differ
diff --git a/vendor/cache/puppet-7.3.0.gem b/vendor/cache/puppet-7.3.0.gem
deleted file mode 100644
index 7c2705be..00000000
Binary files a/vendor/cache/puppet-7.3.0.gem and /dev/null differ
diff --git a/vendor/cache/puppet-7.32.1.gem b/vendor/cache/puppet-7.32.1.gem
deleted file mode 100644
index 2cc2ff23..00000000
Binary files a/vendor/cache/puppet-7.32.1.gem and /dev/null differ
diff --git a/vendor/cache/puppet-resource_api-1.8.13.gem b/vendor/cache/puppet-resource_api-1.8.13.gem
deleted file mode 100644
index 13f8c5ab..00000000
Binary files a/vendor/cache/puppet-resource_api-1.8.13.gem and /dev/null differ
diff --git a/vendor/cache/puppetdb-terminus-3.2.4.gem b/vendor/cache/puppetdb-terminus-3.2.4.gem
deleted file mode 100644
index 0da55b98..00000000
Binary files a/vendor/cache/puppetdb-terminus-3.2.4.gem and /dev/null differ
diff --git a/vendor/cache/rugged-0.27.5.gem b/vendor/cache/rugged-0.27.5.gem
deleted file mode 100644
index 79bb2eff..00000000
Binary files a/vendor/cache/rugged-0.27.5.gem and /dev/null differ
diff --git a/vendor/cache/rugged-1.7.2.gem b/vendor/cache/rugged-1.7.2.gem
deleted file mode 100644
index 5e4af1b1..00000000
Binary files a/vendor/cache/rugged-1.7.2.gem and /dev/null differ
diff --git a/vendor/cache/safe_yaml-1.0.4.gem b/vendor/cache/safe_yaml-1.0.4.gem
deleted file mode 100644
index 7da49f5e..00000000
Binary files a/vendor/cache/safe_yaml-1.0.4.gem and /dev/null differ
diff --git a/vendor/cache/semantic_puppet-1.0.2.gem b/vendor/cache/semantic_puppet-1.0.2.gem
deleted file mode 100644
index 305b4e61..00000000
Binary files a/vendor/cache/semantic_puppet-1.0.2.gem and /dev/null differ
diff --git a/vendor/cache/text-1.3.1.gem b/vendor/cache/text-1.3.1.gem
deleted file mode 100644
index 341f3455..00000000
Binary files a/vendor/cache/text-1.3.1.gem and /dev/null differ