octocatalog-diff 1.5.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.version +1 -1
- data/README.md +4 -4
- data/doc/CHANGELOG.md +49 -0
- data/doc/advanced-filter.md +23 -0
- data/doc/advanced-ignores.md +10 -0
- data/doc/advanced-puppet-master.md +23 -5
- data/doc/configuration-puppetdb.md +11 -0
- data/doc/dev/api/v1/calls/catalog-diff.md +6 -2
- data/doc/dev/api/v1/objects/diff.md +3 -3
- data/doc/dev/releasing.md +1 -1
- data/doc/limitations.md +9 -9
- data/doc/optionsref.md +167 -11
- data/doc/requirements.md +6 -2
- data/lib/octocatalog-diff/catalog-diff/differ.rb +29 -4
- data/lib/octocatalog-diff/catalog-diff/filter.rb +2 -1
- data/lib/octocatalog-diff/catalog-diff/filter/compilation_dir.rb +29 -25
- data/lib/octocatalog-diff/catalog-diff/filter/single_item_array.rb +44 -0
- data/lib/octocatalog-diff/catalog-util/builddir.rb +3 -3
- data/lib/octocatalog-diff/catalog-util/command.rb +25 -3
- data/lib/octocatalog-diff/catalog-util/fileresources.rb +1 -1
- data/lib/octocatalog-diff/catalog.rb +22 -4
- data/lib/octocatalog-diff/catalog/computed.rb +2 -1
- data/lib/octocatalog-diff/catalog/puppetmaster.rb +43 -5
- data/lib/octocatalog-diff/cli.rb +36 -5
- data/lib/octocatalog-diff/cli/options.rb +39 -3
- data/lib/octocatalog-diff/cli/options/hostname.rb +13 -2
- data/lib/octocatalog-diff/cli/options/pe_enc_token_file.rb +1 -1
- data/lib/octocatalog-diff/cli/options/puppet_master_api_version.rb +2 -2
- data/lib/octocatalog-diff/cli/options/puppet_master_token.rb +20 -0
- data/lib/octocatalog-diff/cli/options/puppet_master_token_file.rb +35 -0
- data/lib/octocatalog-diff/cli/options/puppet_master_update_catalog.rb +20 -0
- data/lib/octocatalog-diff/cli/options/puppet_master_update_facts.rb +20 -0
- data/lib/octocatalog-diff/cli/options/puppetdb_package_inventory.rb +18 -0
- data/lib/octocatalog-diff/cli/options/puppetdb_token.rb +17 -0
- data/lib/octocatalog-diff/cli/options/puppetdb_token_file.rb +21 -0
- data/lib/octocatalog-diff/facts/puppetdb.rb +43 -2
- data/lib/octocatalog-diff/puppetdb.rb +5 -1
- data/lib/octocatalog-diff/util/parallel.rb +20 -16
- data/lib/octocatalog-diff/util/util.rb +2 -0
- data/scripts/env/env.sh +1 -1
- data/scripts/git-extract/git-extract.sh +1 -1
- data/scripts/puppet/puppet.sh +1 -1
- metadata +37 -30
data/doc/requirements.md
CHANGED
@@ -2,10 +2,14 @@
|
|
2
2
|
|
3
3
|
To run `octocatalog-diff` you will need these basics:
|
4
4
|
|
5
|
-
-
|
5
|
+
- An appropriate Puppet version and [corresponding ruby version](https://puppet.com/docs/puppet/5.4/system_requirements.html)
|
6
|
+
- Puppet 5.x officially supports Ruby 2.4
|
7
|
+
- Puppet 4.x officially supports Ruby 2.1, but seems to work fine with later versions as well
|
8
|
+
- Puppet 3.8.7 -- we attempt to maintain compatibility in `octocatalog-diff` to facilitate upgrades even though this version is no longer supported by Puppet
|
9
|
+
- We don't officially support Puppet 3.8.6 or before
|
6
10
|
- Mac OS, Linux, or other Unix-line operating system (Windows is not supported)
|
7
11
|
- Ability to install gems, e.g. with [rbenv](https://github.com/rbenv/rbenv) or [rvm](https://rvm.io/), or root privileges to install into the system Ruby
|
8
|
-
- Puppet agent for [Linux](https://docs.puppet.com/puppet/latest/reference/install_linux.html) or [Mac OS X](https://docs.puppet.com/puppet/latest/reference/install_osx.html), or installed as a gem
|
12
|
+
- Puppet agent for [Linux](https://docs.puppet.com/puppet/latest/reference/install_linux.html) or [Mac OS X](https://docs.puppet.com/puppet/latest/reference/install_osx.html), or installed as a gem
|
9
13
|
|
10
14
|
We recommend that you also have the following to get the most out of `octocatalog-diff`, but these are not absolute requirements:
|
11
15
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'diffy'
|
4
|
+
require 'digest'
|
4
5
|
require 'hashdiff'
|
5
6
|
require 'json'
|
6
7
|
require 'set'
|
@@ -11,6 +12,8 @@ require_relative '../errors'
|
|
11
12
|
require_relative '../util/util'
|
12
13
|
require_relative 'filter'
|
13
14
|
|
15
|
+
HashDiff = Hashdiff unless defined? HashDiff
|
16
|
+
|
14
17
|
module OctocatalogDiff
|
15
18
|
module CatalogDiff
|
16
19
|
# Calculate the difference between two Puppet catalogs.
|
@@ -263,7 +266,7 @@ module OctocatalogDiff
|
|
263
266
|
|
264
267
|
# Handle parameters
|
265
268
|
if k == 'parameters'
|
266
|
-
cleansed_param = cleanse_parameters_hash(v)
|
269
|
+
cleansed_param = cleanse_parameters_hash(v, resource.fetch('sensitive_parameters', []))
|
267
270
|
hsh[k] = cleansed_param unless cleansed_param.nil? || cleansed_param.empty?
|
268
271
|
elsif k == 'tags'
|
269
272
|
# The order of tags is unimportant. Sort this array to avoid false diffs if order changes.
|
@@ -294,10 +297,13 @@ module OctocatalogDiff
|
|
294
297
|
# Use diffy to get only the lines that have changed in a text object.
|
295
298
|
# As we iterate through the diff, jump out if we have our answer: either
|
296
299
|
# true if '=~>' finds ANY match, or false if '=&>' fails to find a match.
|
297
|
-
Diffy::Diff.new(old_val, new_val, context: 0)
|
300
|
+
diffy_result = Diffy::Diff.new(old_val, new_val, context: 0)
|
301
|
+
newline_alerts = diffy_result.count { |line| line.strip == '\' }
|
302
|
+
diffy_result.each do |line|
|
298
303
|
if regex.match(line.strip)
|
299
304
|
return true if operator == '=~>'
|
300
305
|
elsif operator == '=&>'
|
306
|
+
next if line.strip == '\' && newline_alerts == 2
|
301
307
|
return false
|
302
308
|
end
|
303
309
|
end
|
@@ -334,7 +340,8 @@ module OctocatalogDiff
|
|
334
340
|
# =-> Attribute must have been removed and equal this
|
335
341
|
# =~> Change must match regexp (one line of change matching is sufficient)
|
336
342
|
# =&> Change must match regexp (all lines of change MUST match regexp)
|
337
|
-
|
343
|
+
# =s> Change must be array and contain identical elements, ignoring order
|
344
|
+
if rule_attr =~ /\A(.+?)(=[\-\+~&s]?>)(.+)/m
|
338
345
|
rule_attr = Regexp.last_match(1)
|
339
346
|
operator = Regexp.last_match(2)
|
340
347
|
value = Regexp.last_match(3)
|
@@ -355,6 +362,9 @@ module OctocatalogDiff
|
|
355
362
|
raise RegexpError, "Invalid ignore regexp for #{key}: #{exc.message}"
|
356
363
|
end
|
357
364
|
matcher = ->(x, y) { regexp_operator_match?(operator, my_regex, x, y) }
|
365
|
+
elsif operator == '=s>'
|
366
|
+
raise ArgumentError, "Invalid ignore option for =s>, must be '='" unless value == '='
|
367
|
+
matcher = ->(x, y) { x.is_a?(Array) && y.is_a?(Array) && Set.new(x) == Set.new(y) }
|
358
368
|
end
|
359
369
|
end
|
360
370
|
|
@@ -394,6 +404,13 @@ module OctocatalogDiff
|
|
394
404
|
return false unless rule[:title].casecmp(hsh[:title]).zero?
|
395
405
|
end
|
396
406
|
|
407
|
+
# If rule[:attr] is a regular expression, handle that case here.
|
408
|
+
if rule[:attr].is_a?(Regexp)
|
409
|
+
return false unless hsh[:attr].is_a?(String)
|
410
|
+
return false unless rule[:attr].match(hsh[:attr])
|
411
|
+
return ignore_match_true(hsh, rule)
|
412
|
+
end
|
413
|
+
|
397
414
|
# Special 'attributes': Ignore specific diff types (+ add, - remove, ~ and ! change)
|
398
415
|
if rule[:attr] =~ /\A[\-\+~!]+\Z/
|
399
416
|
return ignore_match_true(hsh, rule) if rule[:attr].include?(diff_type)
|
@@ -446,10 +463,18 @@ module OctocatalogDiff
|
|
446
463
|
|
447
464
|
# Cleanse parameters of filtered attributes.
|
448
465
|
# @param parameters_hash [Hash] Hash of parameters
|
466
|
+
# @param sensitive_parameters [Array] Array of sensitive parameters
|
449
467
|
# @return [Hash] Cleaned parameters hash (original input hash is not altered)
|
450
|
-
def cleanse_parameters_hash(parameters_hash)
|
468
|
+
def cleanse_parameters_hash(parameters_hash, sensitive_parameters)
|
451
469
|
result = parameters_hash.dup
|
452
470
|
|
471
|
+
# hides sensitive params. We still need to know if there's a going to
|
472
|
+
# be a diff, so we hash the value.
|
473
|
+
sensitive_parameters.each do |p|
|
474
|
+
md5 = Digest::MD5.hexdigest Marshal.dump(result[p])
|
475
|
+
result[p] = 'Sensitive [md5sum ' + md5 + ']'
|
476
|
+
end
|
477
|
+
|
453
478
|
# 'before' and 'require' handle internal Puppet ordering but do not affect what
|
454
479
|
# happens on the target machine. Don't consider these for the purpose of catalog diff.
|
455
480
|
result.delete('before')
|
@@ -2,6 +2,7 @@ require_relative '../api/v1/diff'
|
|
2
2
|
require_relative 'filter/absent_file'
|
3
3
|
require_relative 'filter/compilation_dir'
|
4
4
|
require_relative 'filter/json'
|
5
|
+
require_relative 'filter/single_item_array'
|
5
6
|
require_relative 'filter/yaml'
|
6
7
|
|
7
8
|
require 'stringio'
|
@@ -13,7 +14,7 @@ module OctocatalogDiff
|
|
13
14
|
attr_accessor :logger
|
14
15
|
|
15
16
|
# List the available filters here (by class name) for use in the validator method.
|
16
|
-
AVAILABLE_FILTERS = %w(AbsentFile CompilationDir JSON YAML).freeze
|
17
|
+
AVAILABLE_FILTERS = %w(AbsentFile CompilationDir JSON SingleItemArray YAML).freeze
|
17
18
|
|
18
19
|
# Public: Determine whether a particular filter exists. This can be used to validate
|
19
20
|
# a user-submitted filter.
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../filter'
|
4
|
+
require_relative '../../util/util'
|
4
5
|
|
5
6
|
module OctocatalogDiff
|
6
7
|
module CatalogDiff
|
@@ -35,43 +36,46 @@ module OctocatalogDiff
|
|
35
36
|
|
36
37
|
# Check for a change where the difference in a parameter exactly corresponds to the difference in the
|
37
38
|
# compilation directory.
|
38
|
-
if diff.change?
|
39
|
-
|
40
|
-
|
41
|
-
from_match = false
|
42
|
-
to_before = nil
|
43
|
-
to_after = nil
|
44
|
-
to_match = false
|
39
|
+
if diff.change?
|
40
|
+
o = remove_compilation_dir(diff.old_value, dir2)
|
41
|
+
n = remove_compilation_dir(diff.new_value, dir1)
|
45
42
|
|
46
|
-
if diff.old_value
|
47
|
-
from_before = Regexp.last_match(1) || ''
|
48
|
-
from_after = Regexp.last_match(2) || ''
|
49
|
-
from_match = true
|
50
|
-
end
|
51
|
-
|
52
|
-
if diff.new_value =~ /^(.*)#{dir1}(.*)$/m
|
53
|
-
to_before = Regexp.last_match(1) || ''
|
54
|
-
to_after = Regexp.last_match(2) || ''
|
55
|
-
to_match = true
|
56
|
-
end
|
57
|
-
|
58
|
-
if from_match && to_match && to_before == from_before && to_after == from_after
|
43
|
+
if o != diff.old_value || n != diff.new_value
|
59
44
|
message = "Resource key #{diff.type}[#{diff.title}] #{diff.structure.join(' => ')}"
|
60
|
-
message += '
|
45
|
+
message += ' may depend on catalog compilation directory, but there may be differences.'
|
46
|
+
message += ' This is included in results for now, but please verify.'
|
61
47
|
@logger.warn message
|
62
|
-
return true
|
63
48
|
end
|
64
49
|
|
65
|
-
if
|
50
|
+
if o == n
|
66
51
|
message = "Resource key #{diff.type}[#{diff.title}] #{diff.structure.join(' => ')}"
|
67
|
-
message += '
|
68
|
-
message += ' This is included in results for now, but please verify.'
|
52
|
+
message += ' appears to depend on catalog compilation directory. Suppressed from results.'
|
69
53
|
@logger.warn message
|
54
|
+
return true
|
70
55
|
end
|
71
56
|
end
|
72
57
|
|
73
58
|
false
|
74
59
|
end
|
60
|
+
|
61
|
+
def remove_compilation_dir(v, dir)
|
62
|
+
value = OctocatalogDiff::Util::Util.deep_dup(v)
|
63
|
+
traverse(value) do |e|
|
64
|
+
e.gsub!(dir, '') if e.respond_to?(:gsub!)
|
65
|
+
end
|
66
|
+
value
|
67
|
+
end
|
68
|
+
|
69
|
+
def traverse(a)
|
70
|
+
case a
|
71
|
+
when Array
|
72
|
+
a.map { |v| traverse(v, &Proc.new) }
|
73
|
+
when Hash
|
74
|
+
traverse(a.values, &Proc.new)
|
75
|
+
else
|
76
|
+
yield a
|
77
|
+
end
|
78
|
+
end
|
75
79
|
end
|
76
80
|
end
|
77
81
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../filter'
|
4
|
+
|
5
|
+
module OctocatalogDiff
|
6
|
+
module CatalogDiff
|
7
|
+
class Filter
|
8
|
+
# Filter out changes in parameters when one catalog has a parameter that's an object and
|
9
|
+
# the other catalog has that same parameter as an array containing the same object.
|
10
|
+
# For example, under this filter, the following is not a change:
|
11
|
+
# catalog1: notify => "Service[foo]"
|
12
|
+
# catalog2: notify => ["Service[foo]"]
|
13
|
+
class SingleItemArray < OctocatalogDiff::CatalogDiff::Filter
|
14
|
+
# Public: Implement the filter for single-item arrays whose item exactly matches the
|
15
|
+
# item that's not in an array in the other catalog.
|
16
|
+
#
|
17
|
+
# @param diff [OctocatalogDiff::API::V1::Diff] Difference
|
18
|
+
# @param _options [Hash] Additional options (there are none for this filter)
|
19
|
+
# @return [Boolean] true if this should be filtered out, false otherwise
|
20
|
+
def filtered?(diff, _options = {})
|
21
|
+
# Skip additions or removals - focus only on changes
|
22
|
+
return false unless diff.change?
|
23
|
+
old_value = diff.old_value
|
24
|
+
new_value = diff.new_value
|
25
|
+
|
26
|
+
# Skip unless there is a single-item array under consideration
|
27
|
+
return false unless
|
28
|
+
(old_value.is_a?(Array) && old_value.size == 1) ||
|
29
|
+
(new_value.is_a?(Array) && new_value.size == 1)
|
30
|
+
|
31
|
+
# Skip if both the old value and new value are arrays
|
32
|
+
return false if old_value.is_a?(Array) && new_value.is_a?(Array)
|
33
|
+
|
34
|
+
# Do comparison
|
35
|
+
if old_value.is_a?(Array)
|
36
|
+
old_value.first == new_value
|
37
|
+
else
|
38
|
+
new_value.first == old_value
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -149,13 +149,13 @@ module OctocatalogDiff
|
|
149
149
|
raise ArgumentError, 'Called install_fact_file without node, or with an empty node'
|
150
150
|
end
|
151
151
|
|
152
|
-
facts = if options[:
|
152
|
+
facts = if options[:facts].is_a?(OctocatalogDiff::Facts)
|
153
|
+
options[:facts].dup
|
154
|
+
elsif options[:fact_file]
|
153
155
|
raise Errno::ENOENT, "Fact file #{options[:fact_file]} does not exist" unless File.file?(options[:fact_file])
|
154
156
|
fact_file_opts = { fact_file_string: File.read(options[:fact_file]) }
|
155
157
|
fact_file_opts[:backend] = Regexp.last_match(1).to_sym if options[:fact_file] =~ /.*\.(\w+)$/
|
156
158
|
OctocatalogDiff::Facts.new(fact_file_opts)
|
157
|
-
elsif options[:facts].is_a?(OctocatalogDiff::Facts)
|
158
|
-
options[:facts].dup
|
159
159
|
else
|
160
160
|
raise ArgumentError, 'No facts passed to "install_fact_file" method'
|
161
161
|
end
|
@@ -54,9 +54,21 @@ module OctocatalogDiff
|
|
54
54
|
raise ArgumentError, 'Puppet binary was not supplied' if @puppet_binary.nil?
|
55
55
|
raise Errno::ENOENT, "Puppet binary #{@puppet_binary} doesn't exist" unless File.file?(@puppet_binary)
|
56
56
|
|
57
|
+
puppet_version = Gem::Version.new(@options[:puppet_version])
|
58
|
+
|
57
59
|
# Node to compile
|
58
60
|
cmdline = []
|
59
|
-
|
61
|
+
# The 'puppet master --compile' command was removed in Puppet 6.x and replaced in
|
62
|
+
# Puppet 6.5 with an identically functioning 'puppet catalog compile' command.
|
63
|
+
# From versions 6.0.0 until 6.5.0 there is no compatible invocation method.
|
64
|
+
if puppet_version < Gem::Version.new('6.0.0')
|
65
|
+
cmdline.concat ['master', '--compile', Shellwords.escape(@node)]
|
66
|
+
elsif puppet_version < Gem::Version.new('6.5.0')
|
67
|
+
raise OctocatalogDiff::Errors::PuppetVersionError,
|
68
|
+
'Octocatalog-diff does not support Puppet versions >= 6.0.0 and < 6.5.0'
|
69
|
+
else
|
70
|
+
cmdline.concat ['catalog', 'compile', Shellwords.escape(@node)]
|
71
|
+
end
|
60
72
|
|
61
73
|
# storeconfigs?
|
62
74
|
if @options[:storeconfigs]
|
@@ -93,11 +105,21 @@ module OctocatalogDiff
|
|
93
105
|
# Some typical options for puppet
|
94
106
|
cmdline.concat %w(
|
95
107
|
--no-daemonize
|
96
|
-
--no-ca
|
97
108
|
--color=false
|
98
|
-
--config_version="/bin/echo catalogscript"
|
99
109
|
)
|
100
110
|
|
111
|
+
if puppet_version < Gem::Version.new('6.0.0')
|
112
|
+
# This config_version parameter causes an error when run with Puppet 6.x. Per
|
113
|
+
# the Puppet configuration settings docs, the below config_version argument
|
114
|
+
# may not actually be valid, but for backward compatibility's sake we'll keep it
|
115
|
+
# for the versions it has always worked with:
|
116
|
+
cmdline.concat ['--config_version="/bin/echo catalogscript"']
|
117
|
+
|
118
|
+
# The 'ca' configuration option was removed in Puppet 6, but we'll keep it
|
119
|
+
# for older versions:
|
120
|
+
cmdline.concat ['--no-ca']
|
121
|
+
end
|
122
|
+
|
101
123
|
# Add environment - only make this variable if preserve_environments is used.
|
102
124
|
# If preserve_environments is not used, the hard-coded 'production' here matches
|
103
125
|
# up with the symlink created under the temporary directory structure.
|
@@ -191,6 +191,8 @@ module OctocatalogDiff
|
|
191
191
|
build
|
192
192
|
raise OctocatalogDiff::Errors::CatalogError, 'Catalog does not appear to have been built' if !valid? && error_message.nil?
|
193
193
|
raise OctocatalogDiff::Errors::CatalogError, error_message unless valid?
|
194
|
+
# Handle the structure returned by the /puppet/v4/catalog Puppetserver endpoint:
|
195
|
+
return @catalog['catalog']['resources'] if @catalog['catalog'].is_a?(Hash) && @catalog['catalog']['resources'].is_a?(Array)
|
194
196
|
return @catalog['data']['resources'] if @catalog['data'].is_a?(Hash) && @catalog['data']['resources'].is_a?(Array)
|
195
197
|
return @catalog['resources'] if @catalog['resources'].is_a?(Array)
|
196
198
|
# This is a bug condition
|
@@ -304,20 +306,36 @@ module OctocatalogDiff
|
|
304
306
|
unless res =~ /\A([\w:]+)\[(.+)\]\z/
|
305
307
|
raise ArgumentError, "Resource #{res} is not in the expected format"
|
306
308
|
end
|
307
|
-
|
309
|
+
|
310
|
+
type = Regexp.last_match(1)
|
311
|
+
title = normalized_title(Regexp.last_match(2), type)
|
312
|
+
resource(type: type, title: title).nil?
|
308
313
|
end
|
309
314
|
end
|
310
315
|
|
316
|
+
# Private method: Given a title string, normalize it according to the rules
|
317
|
+
# used by puppet 4.10.x for file resource title normalization:
|
318
|
+
# https://github.com/puppetlabs/puppet/blob/4.10.x/lib/puppet/type/file.rb#L42
|
319
|
+
def normalized_title(title_string, type)
|
320
|
+
return title_string if type != 'File'
|
321
|
+
|
322
|
+
matches = title_string.match(%r{^(?<normalized_path>/|.+:/|.*[^/])/*\Z}m)
|
323
|
+
matches[:normalized_path] || title_string
|
324
|
+
end
|
325
|
+
|
311
326
|
# Private method: Build the resource hash to be used used for O(1) lookups by type and title.
|
312
327
|
# This method is called the first time the resource hash is accessed.
|
313
328
|
def build_resource_hash
|
314
329
|
@resource_hash = {}
|
315
330
|
resources.each do |resource|
|
316
331
|
@resource_hash[resource['type']] ||= {}
|
317
|
-
@resource_hash[resource['type']][resource['title']] = resource
|
318
332
|
|
319
|
-
|
320
|
-
|
333
|
+
title = normalized_title(resource['title'], resource['type'])
|
334
|
+
@resource_hash[resource['type']][title] = resource
|
335
|
+
|
336
|
+
if resource.key?('parameters')
|
337
|
+
@resource_hash[resource['type']][resource['parameters']['alias']] = resource if resource['parameters'].key?('alias')
|
338
|
+
@resource_hash[resource['type']][resource['parameters']['name']] = resource if resource['parameters'].key?('name')
|
321
339
|
end
|
322
340
|
end
|
323
341
|
end
|
@@ -147,7 +147,8 @@ module OctocatalogDiff
|
|
147
147
|
puppet_binary: @puppet_binary,
|
148
148
|
fact_file: @builddir.fact_file,
|
149
149
|
dir: @builddir.tempdir,
|
150
|
-
enc: @builddir.enc
|
150
|
+
enc: @builddir.enc,
|
151
|
+
puppet_version: puppet_version
|
151
152
|
)
|
152
153
|
OctocatalogDiff::CatalogUtil::Command.new(command_opts)
|
153
154
|
end
|
@@ -62,16 +62,19 @@ module OctocatalogDiff
|
|
62
62
|
fetch_catalog(logger)
|
63
63
|
end
|
64
64
|
|
65
|
-
# Returns a hash of parameters for
|
65
|
+
# Returns a hash of parameters for the requested version of the Puppet Server Catalog API.
|
66
66
|
# @return [Hash] Hash of parameters
|
67
67
|
#
|
68
68
|
# Note: The double escaping of the facts here is implemented to correspond to a long standing
|
69
69
|
# bug in the Puppet code. See https://github.com/puppetlabs/puppet/pull/1818 and
|
70
70
|
# https://docs.puppet.com/puppet/latest/http_api/http_catalog.html#parameters for explanation.
|
71
|
-
def puppet_catalog_api
|
72
|
-
{
|
71
|
+
def puppet_catalog_api(version)
|
72
|
+
api_style = {
|
73
73
|
2 => {
|
74
74
|
url: "https://#{@options[:puppet_master]}/#{@options[:branch]}/catalog/#{@node}",
|
75
|
+
headers: {
|
76
|
+
'Accept' => 'text/pson'
|
77
|
+
},
|
75
78
|
parameters: {
|
76
79
|
'facts_format' => 'pson',
|
77
80
|
'facts' => CGI.escape(@facts.fudge_timestamp.without('trusted').to_pson),
|
@@ -80,24 +83,59 @@ module OctocatalogDiff
|
|
80
83
|
},
|
81
84
|
3 => {
|
82
85
|
url: "https://#{@options[:puppet_master]}/puppet/v3/catalog/#{@node}",
|
86
|
+
headers: {
|
87
|
+
'Accept' => 'text/pson'
|
88
|
+
},
|
83
89
|
parameters: {
|
84
90
|
'environment' => @options[:branch],
|
85
91
|
'facts_format' => 'pson',
|
86
92
|
'facts' => CGI.escape(@facts.fudge_timestamp.without('trusted').to_pson),
|
87
93
|
'transaction_uuid' => SecureRandom.uuid
|
88
94
|
}
|
95
|
+
},
|
96
|
+
4 => {
|
97
|
+
url: "https://#{@options[:puppet_master]}/puppet/v4/catalog",
|
98
|
+
headers: {
|
99
|
+
'Content-Type' => 'application/json'
|
100
|
+
},
|
101
|
+
parameters: {
|
102
|
+
'certname' => @node,
|
103
|
+
'persistence' => {
|
104
|
+
'facts' => @options[:puppet_master_update_facts] || false,
|
105
|
+
'catalog' => @options[:puppet_master_update_catalog] || false
|
106
|
+
},
|
107
|
+
'environment' => @options[:branch],
|
108
|
+
'facts' => { 'values' => @facts.facts['values'] },
|
109
|
+
'options' => {
|
110
|
+
'prefer_requested_environment' => true,
|
111
|
+
'capture_logs' => false,
|
112
|
+
'log_level' => 'warning'
|
113
|
+
},
|
114
|
+
'transaction_uuid' => SecureRandom.uuid
|
115
|
+
}
|
89
116
|
}
|
90
117
|
}
|
118
|
+
|
119
|
+
params = api_style[version]
|
120
|
+
return nil if params.nil?
|
121
|
+
|
122
|
+
unless @options[:puppet_master_token].nil?
|
123
|
+
params[:headers]['X-Authentication'] = @options[:puppet_master_token]
|
124
|
+
end
|
125
|
+
|
126
|
+
params[:parameters] = params[:parameters].to_json if version >= 4
|
127
|
+
|
128
|
+
params
|
91
129
|
end
|
92
130
|
|
93
131
|
# Fetch catalog by contacting the Puppet master, sending the facts, and asking for the catalog. When the
|
94
132
|
# catalog is returned in PSON format, parse it to JSON and then set appropriate variables.
|
95
133
|
def fetch_catalog(logger)
|
96
134
|
api_version = @options[:puppet_master_api_version] || DEFAULT_PUPPET_SERVER_API
|
97
|
-
api = puppet_catalog_api
|
135
|
+
api = puppet_catalog_api(api_version)
|
98
136
|
raise ArgumentError, "Unsupported or invalid API version #{api_version}" unless api.is_a?(Hash)
|
99
137
|
|
100
|
-
more_options = { headers:
|
138
|
+
more_options = { headers: api[:headers], timeout: @timeout }
|
101
139
|
post_hash = api[:parameters]
|
102
140
|
|
103
141
|
response = nil
|