Skip to content

Commit a171724

Browse files
authored
Merge pull request #141 from github/kpaulisse-release
Next octocatalog-diff release
2 parents 40d75b8 + de4ccc3 commit a171724

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+453
-341
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
language: ruby
44
install: true
55
script: "script/cibuild"
6+
dist: precise
67

78
matrix:
89
include:

.version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.3.0
1+
1.4.0

config/puppet-versions.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[
2+
{
3+
"minimum_version": "3.0.0",
4+
"maximum_version": "3.99.99",
5+
"additional_gems": [
6+
{ "name": "safe_yaml", "version": "~> 1.0.4" },
7+
{ "name": "puppetdb-terminus", "version": "3.2.4" }
8+
]
9+
},
10+
{
11+
"minimum_version": "4.0.0",
12+
"maximum_version": "4.99.99",
13+
"additional_gems": [
14+
{ "name": "puppetdb-terminus", "version": "3.2.4" }
15+
]
16+
},
17+
{
18+
"minimum_version": "5.0.0",
19+
"maximum_version": "5.99.99",
20+
"additional_gems": [
21+
]
22+
}
23+
]

doc/CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@
88
</tr>
99
</thead><tbody>
1010
<tr valign=top>
11+
<td>1.4.0</td>
12+
<td>2017-08-03</td>
13+
<td>
14+
<li><a href="https://github.com/github/octocatalog-diff/pull/135">#135</a>: (Enhancement) Puppet 5 compatibility</li>
15+
<li><a href="https://github.com/github/octocatalog-diff/pull/140">#140</a>: (Internal) Prefix tmpdirs with ocd-</li>
16+
<li><a href="https://github.com/github/octocatalog-diff/pull/138">#138</a>: (Internal) Refactor catalog class with proper inheritance</li>
17+
</td>
18+
</tr>
19+
<tr valign=top>
1120
<td>1.3.0</td>
1221
<td>2017-06-09</td>
1322
<td>

doc/advanced-catalog-validation.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44

55
Catalog validation features include:
66

7-
- Validate references: Ensure resources targeted by `before`, `notify`, `require`, and/or `subscribe` exist in the catalog
7+
- Validate references: Ensure resources targeted by `before`, `notify`, `require`, and/or `subscribe` exist in the catalog for Puppet 4 and below.
88

99
## Validate references
1010

1111
`octocatalog-diff` includes the ability to validate references by ensuring resources targeted by `before`, `notify`, `require`, and/or `subscribe` parameters also exist in the catalog.
1212

13+
Puppet 5 already has this checking built in, so the `--validate-references` option described in this section will be ignored if Puppet 5 is being used. The same exception (`OctocatalogDiff::Errors::CatalogError`) is raised for a missing reference, whether the problem was detected by octocatalog-diff or Puppet 5.
14+
1315
Consider the following Puppet code:
1416

1517
```

doc/dev/api/v1/calls/catalog-diff.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ The following exceptions may occur during the compilation of a catalog within th
194194

195195
- `OctocatalogDiff::Errors::CatalogError`
196196

197-
Catalog failed to compile. Please note that whenever possible, a `OctocatalogDiff::API::V1::Catalog` object is still constructed for a failed catalog, with `#valid?` returning false.
197+
Catalog failed to compile. Please note that whenever possible, a `OctocatalogDiff::API::V1::Catalog` object is still constructed for a failed catalog, with `#valid?` returning false. It's also possible that the catalog contained broken references -- see [Catalog validation](/doc/advanced-catalog-validation.md).
198198

199199
- `OctocatalogDiff::Errors::GitCheckoutError`
200200

@@ -203,7 +203,3 @@ The following exceptions may occur during the compilation of a catalog within th
203203
- `OctocatalogDiff::Errors::PuppetVersionError`
204204

205205
The version of Puppet could not be determined, generally because the Puppet binary was not found, or does not respond as expected to `puppet version`.
206-
207-
- `OctocatalogDiff::Errors::ReferenceValidationError`
208-
209-
See [Catalog validation](/doc/advanced-catalog-validation.md).

doc/dev/api/v1/calls/catalog.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ The following exceptions may occur during the compilation of a catalog:
100100

101101
- `OctocatalogDiff::Errors::CatalogError`
102102

103-
Catalog failed to compile. Please note that whenever possible, a `OctocatalogDiff::API::V1::Catalog` object is still constructed for a failed catalog, with `#valid?` returning false.
103+
Catalog failed to compile. Please note that whenever possible, a `OctocatalogDiff::API::V1::Catalog` object is still constructed for a failed catalog, with `#valid?` returning false. It's also possible that the catalog contained broken references -- see [Catalog validation](/doc/advanced-catalog-validation.md).
104104

105105
- `OctocatalogDiff::Errors::GitCheckoutError`
106106

@@ -109,7 +109,3 @@ The following exceptions may occur during the compilation of a catalog:
109109
- `OctocatalogDiff::Errors::PuppetVersionError`
110110

111111
The version of Puppet could not be determined, generally because the Puppet binary was not found, or does not respond as expected to `puppet version`.
112-
113-
- `OctocatalogDiff::Errors::ReferenceValidationError`
114-
115-
See [Catalog validation](/doc/advanced-catalog-validation.md).

lib/octocatalog-diff/catalog-util/builddir.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class BuildDir
3838
# @param options [Hash] Options for class; see above description
3939
def initialize(options = {}, logger = nil)
4040
@options = options.dup
41-
@tempdir = Dir.mktmpdir
41+
@tempdir = Dir.mktmpdir('ocd-builddir-')
4242
at_exit { FileUtils.rm_rf(@tempdir) if File.directory?(@tempdir) }
4343

4444
@factdir = nil

lib/octocatalog-diff/catalog.rb

Lines changed: 89 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,42 @@
1212
require_relative 'errors'
1313

1414
module OctocatalogDiff
15-
# This class represents a catalog. Generation of the catalog is handled via one of the
15+
# Basic methods for interacting with a catalog. Generation of the catalog is handled via one of the
1616
# supported backends listed above as 'require_relative'. Usually, the 'computed' backend
1717
# will build the catalog from the Puppet command.
1818
class Catalog
19-
# Readable
20-
attr_reader :built, :catalog, :catalog_json
19+
attr_accessor :node
20+
attr_reader :built, :catalog, :catalog_json, :options
2121

2222
# Constructor
23+
def initialize(options = {})
24+
unless options.is_a?(Hash)
25+
raise ArgumentError, "#{self.class}.initialize requires hash argument, not #{options.class}"
26+
end
27+
@options = options
28+
29+
# Basic settings
30+
@node = options[:node]
31+
@error_message = nil
32+
@catalog = nil
33+
@catalog_json = nil
34+
@retries = nil
35+
36+
# The compilation directory can be overridden, e.g. when testing
37+
@override_compilation_dir = options[:compilation_dir]
38+
39+
# Keep track of whether references have been validated yet. Allow this to be fudged for when we do
40+
# not desire reference validation to happen (e.g., for the "from" catalog that is otherwise valid).
41+
@references_validated = options[:references_validated] || false
42+
43+
# Keep track of whether file resources have been converted.
44+
@file_resources_converted = false
45+
46+
# Keep track of whether it's built yet
47+
@built = false
48+
end
49+
50+
# Guess the backend from the input and return the appropriate catalog object.
2351
# @param :backend [Symbol] If set, this will force a backend
2452
# @param :json [String] JSON catalog content (will avoid running Puppet to compile catalog)
2553
# @param :puppetdb [Object] If set, pull the catalog from PuppetDB rather than building
@@ -30,62 +58,68 @@ class Catalog
3058
# @param :pass_env_vars [Array<String>] OPTIONAL: Additional environment vars to pass
3159
# @param :convert_file_resources [Boolean] OPTIONAL: Convert file resource source to content
3260
# @param :storeconfigs [Boolean] OPTIONAL: Pass the '-s' flag, for puppetdb (storeconfigs) integration
33-
def initialize(options = {})
34-
@options = options
35-
36-
# Call appropriate backend for catalog generation
37-
@catalog_obj = backend(options)
61+
# @return [OctocatalogDiff::Catalog::<?>] Catalog object from guessed backend
62+
def self.create(options = {})
63+
# Hard-coded backend
64+
if options[:backend]
65+
return OctocatalogDiff::Catalog::JSON.new(options) if options[:backend] == :json
66+
return OctocatalogDiff::Catalog::PuppetDB.new(options) if options[:backend] == :puppetdb
67+
return OctocatalogDiff::Catalog::PuppetMaster.new(options) if options[:backend] == :puppetmaster
68+
return OctocatalogDiff::Catalog::Computed.new(options) if options[:backend] == :computed
69+
return OctocatalogDiff::Catalog::Noop.new(options) if options[:backend] == :noop
70+
raise ArgumentError, "Unknown backend :#{options[:backend]}"
71+
end
3872

39-
# The catalog is not built yet, except if the backend has no build method
40-
@built = false
41-
build unless @catalog_obj.respond_to?(:build)
73+
# Determine backend based on arguments
74+
return OctocatalogDiff::Catalog::JSON.new(options) if options[:json]
75+
return OctocatalogDiff::Catalog::PuppetDB.new(options) if options[:puppetdb]
76+
return OctocatalogDiff::Catalog::PuppetMaster.new(options) if options[:puppet_master]
4277

43-
# The compilation directory can be overridden, e.g. when testing
44-
@override_compilation_dir = nil
78+
# Default is to build catalog ourselves
79+
OctocatalogDiff::Catalog::Computed.new(options)
4580
end
4681

4782
# Build catalog - this method needs to be called to build the catalog. It is separate due to
4883
# the serialization of the logger object -- the parallel gem cannot serialize/deserialize a logger
4984
# object so it cannot be part of any object that is passed around.
5085
# @param logger [Logger] Logger object, initialized to a default throwaway value
5186
def build(logger = Logger.new(StringIO.new))
52-
# Only build once
87+
# If already built, don't build again
5388
return if @built
5489
@built = true
5590

56-
# Call catalog's build method.
57-
if @catalog_obj.respond_to?(:build)
58-
logger.debug "Calling build for object #{@catalog_obj.class}"
59-
@catalog_obj.build(logger)
60-
end
61-
62-
# These methods must exist in all backends
63-
@catalog = @catalog_obj.catalog
64-
@catalog_json = @catalog_obj.catalog_json
65-
@error_message = @catalog_obj.error_message
66-
6791
# The resource hash is computed the first time it's needed. For now initialize it as nil.
6892
@resource_hash = nil
6993

94+
# Invoke the backend's build method, if there is one. There's a stub below in case there's not.
95+
logger.debug "Calling build for object #{self.class}"
96+
build_catalog(logger)
97+
7098
# Perform post-generation processing of the catalog
7199
return unless valid?
72-
unless @catalog_obj.respond_to?(:convert_file_resources) && @catalog_obj.convert_file_resources == false
73-
if @options.fetch(:compare_file_text, false)
74-
OctocatalogDiff::CatalogUtil::FileResources.convert_file_resources(self, environment)
75-
end
76-
end
100+
101+
validate_references
102+
return unless valid?
103+
104+
convert_file_resources if @options[:compare_file_text]
105+
106+
true
107+
end
108+
109+
# Stub method if the backend does not contain a build method.
110+
def build_catalog(_logger)
77111
end
78112

79113
# Compilation environment
80114
# @return [String] Compilation environment (if set), else 'production' by default
81115
def environment
82-
@catalog_obj.respond_to?(:environment) ? @catalog_obj.environment : 'production'
116+
@environment ||= 'production'
83117
end
84118

85119
# For logging we may wish to know the backend being used
86120
# @return [String] Class of backend used
87121
def builder
88-
@catalog_obj.class.to_s
122+
self.class.to_s
89123
end
90124

91125
# Set the catalog JSON
@@ -98,8 +132,7 @@ def catalog_json=(str)
98132
# This retrieves the compilation directory from the catalog, or otherwise the passed-in directory.
99133
# @return [String] Compilation directory
100134
def compilation_dir
101-
return @override_compilation_dir if @override_compilation_dir
102-
@catalog_obj.respond_to?(:compilation_dir) ? @catalog_obj.compilation_dir : @options[:basedir]
135+
@override_compilation_dir || @options[:basedir]
103136
end
104137

105138
# The compilation directory can be overridden, e.g. during testing.
@@ -108,16 +141,16 @@ def compilation_dir=(dir)
108141
@override_compilation_dir = dir
109142
end
110143

111-
# Determine whether the underlying catalog object supports :compare_file_text
112-
# @return [Boolean] Whether underlying catalog object supports :compare_file_text
113-
def convert_file_resources
114-
return true unless @catalog_obj.respond_to?(:convert_file_resources)
115-
@catalog_obj.convert_file_resources
144+
# Stub method for "convert_file_resources" -- returns false because if the underlying class does
145+
# not implement this method, it's not supported.
146+
def convert_file_resources(_dry_run = false)
147+
false
116148
end
117149

118150
# Retrieve the error message.
119151
# @return [String] Error message (maximum 20,000 characters) - nil if no error.
120152
def error_message
153+
build
121154
return nil if @error_message.nil? || !@error_message.is_a?(String)
122155
@error_message[0, 20_000]
123156
end
@@ -133,12 +166,11 @@ def error_message=(error)
133166
@resource_hash = nil
134167
end
135168

136-
# This retrieves the version of Puppet used to compile a catalog. If the underlying catalog was not
137-
# compiled by running Puppet (e.g., it was read in from JSON or puppetdb), then this returns the
138-
# puppet version optionally passed in to the constructor. This can also be nil.
169+
# Stub method to return the puppet version if the back end doesn't support this.
139170
# @return [String] Puppet version
140171
def puppet_version
141-
@catalog_obj.respond_to?(:puppet_version) ? @catalog_obj.puppet_version : @options[:puppet_version]
172+
build
173+
@options[:puppet_version]
142174
end
143175

144176
# This allows retrieving a resource by type and title. This is intended for use when a O(1) lookup is required.
@@ -147,6 +179,7 @@ def puppet_version
147179
# @return [Hash] Resource item
148180
def resource(opts = {})
149181
raise ArgumentError, ':type and :title are required' unless opts[:type] && opts[:title]
182+
build
150183
build_resource_hash if @resource_hash.nil?
151184
return nil unless @resource_hash[opts[:type]].is_a?(Hash)
152185
@resource_hash[opts[:type]][opts[:title]]
@@ -155,6 +188,7 @@ def resource(opts = {})
155188
# This is a compatibility layer for the resources, which are in a different place in Puppet 3.x and Puppet 4.x
156189
# @return [Array] Resource array
157190
def resources
191+
build
158192
raise OctocatalogDiff::Errors::CatalogError, 'Catalog does not appear to have been built' if !valid? && error_message.nil?
159193
raise OctocatalogDiff::Errors::CatalogError, error_message unless valid?
160194
return @catalog['data']['resources'] if @catalog['data'].is_a?(Hash) && @catalog['data']['resources'].is_a?(Array)
@@ -165,28 +199,37 @@ def resources
165199
# :nocov:
166200
end
167201

168-
# This retrieves the number of retries necessary to compile the catalog. If the underlying catalog
202+
# Stub method of the the number of retries necessary to compile the catalog. If the underlying catalog
169203
# generation backend does not support retries, nil is returned.
170204
# @return [Integer] Retry count
171205
def retries
172-
@retries = @catalog_obj.respond_to?(:retries) ? @catalog_obj.retries : nil
206+
nil
173207
end
174208

175209
# Determine if the catalog build was successful.
176210
# @return [Boolean] Whether the catalog is valid
177211
def valid?
212+
build
178213
!@catalog.nil?
179214
end
180215

181216
# Determine if all of the (before, notify, require, subscribe) targets are actually in the catalog.
182217
# Raise a OctocatalogDiff::Errors::ReferenceValidationError for any found to be missing.
183218
# Uses @options[:validate_references] to influence which references are checked.
184219
def validate_references
220+
# If we've already done the validation, don't do it again
221+
return if @references_validated
222+
@references_validated = true
223+
185224
# Skip out early if no reference validation has been requested.
186225
unless @options[:validate_references].is_a?(Array) && @options[:validate_references].any?
187226
return
188227
end
189228

229+
# Puppet 5 has reference validation built-in and enabled, so there won't even be a valid catalog if
230+
# there were invalid references. It's pointless to perform validation of our own.
231+
return if puppet_version && puppet_version >= '5.0.0'
232+
190233
# Iterate over all the resources and check each one that has one of the attributes being checked.
191234
# Keep track of all references that are missing for ultimate inclusion in the error message.
192235
missing = []
@@ -204,7 +247,7 @@ def validate_references
204247
# At this point there is at least one broken/missing reference. Format an error message and raise.
205248
errors = format_missing_references(missing)
206249
plural = errors =~ /;/ ? 's' : ''
207-
raise OctocatalogDiff::Errors::ReferenceValidationError, "Catalog has broken reference#{plural}: #{errors}"
250+
self.error_message = "Catalog has broken reference#{plural}: #{errors}"
208251
end
209252

210253
private
@@ -265,29 +308,6 @@ def resources_missing_from_catalog(resources_to_check)
265308
end
266309
end
267310

268-
# Private method: Choose backend based on passed-in options
269-
# @param options [Hash] Options passed into constructor
270-
# @return [Object] OctocatalogDiff::Catalog::<whatever> object
271-
def backend(options)
272-
# Hard-coded backend
273-
if options[:backend]
274-
return OctocatalogDiff::Catalog::JSON.new(options) if options[:backend] == :json
275-
return OctocatalogDiff::Catalog::PuppetDB.new(options) if options[:backend] == :puppetdb
276-
return OctocatalogDiff::Catalog::PuppetMaster.new(options) if options[:backend] == :puppetmaster
277-
return OctocatalogDiff::Catalog::Computed.new(options) if options[:backend] == :computed
278-
return OctocatalogDiff::Catalog::Noop.new(options) if options[:backend] == :noop
279-
raise ArgumentError, "Unknown backend :#{options[:backend]}"
280-
end
281-
282-
# Determine backend based on arguments
283-
return OctocatalogDiff::Catalog::JSON.new(options) if options[:json]
284-
return OctocatalogDiff::Catalog::PuppetDB.new(options) if options[:puppetdb]
285-
return OctocatalogDiff::Catalog::PuppetMaster.new(options) if options[:puppet_master]
286-
287-
# Default is to build catalog ourselves
288-
OctocatalogDiff::Catalog::Computed.new(options)
289-
end
290-
291311
# Private method: Build the resource hash to be used used for O(1) lookups by type and title.
292312
# This method is called the first time the resource hash is accessed.
293313
def build_resource_hash

0 commit comments

Comments
 (0)