octocatalog-diff 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.version +1 -0
- data/LICENSE +20 -0
- data/README.md +82 -0
- data/bin/octocatalog-diff +75 -0
- data/doc/advanced-bootstrap.md +33 -0
- data/doc/advanced-cache-dir.md +24 -0
- data/doc/advanced-catalog-only.md +37 -0
- data/doc/advanced-ci.md +13 -0
- data/doc/advanced-dynamic-ignores.md +123 -0
- data/doc/advanced-future-parser.md +11 -0
- data/doc/advanced-ignores.md +224 -0
- data/doc/advanced-output-formats.md +96 -0
- data/doc/advanced-output-hacks.md +45 -0
- data/doc/advanced-override-facts.md +67 -0
- data/doc/advanced-pe-enc.md +52 -0
- data/doc/advanced-puppet-master.md +50 -0
- data/doc/advanced-puppet-versions.md +9 -0
- data/doc/advanced-storeconfigs.md +72 -0
- data/doc/advanced-using-without-git.md +15 -0
- data/doc/advanced.md +43 -0
- data/doc/basic.md +70 -0
- data/doc/configuration-enc.md +69 -0
- data/doc/configuration-hiera.md +103 -0
- data/doc/configuration-puppetdb.md +49 -0
- data/doc/configuration.md +51 -0
- data/doc/dev/README.md +1 -0
- data/doc/dev/coverage.md +34 -0
- data/doc/dev/how-to-add-options.md +83 -0
- data/doc/dev/integration-tests.md +63 -0
- data/doc/dev/releasing.md +19 -0
- data/doc/installation.md +49 -0
- data/doc/limitations.md +34 -0
- data/doc/optionsref.md +947 -0
- data/doc/requirements.md +16 -0
- data/doc/roadmap.md +26 -0
- data/doc/similar.md +17 -0
- data/doc/troubleshooting.md +54 -0
- data/lib/octocatalog-diff.rb +12 -0
- data/lib/octocatalog-diff/bootstrap.rb +53 -0
- data/lib/octocatalog-diff/catalog-diff/cli.rb +205 -0
- data/lib/octocatalog-diff/catalog-diff/cli/catalogs.rb +240 -0
- data/lib/octocatalog-diff/catalog-diff/cli/diffs.rb +145 -0
- data/lib/octocatalog-diff/catalog-diff/cli/helpers/fact_override.rb +99 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options.rb +173 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/basedir.rb +14 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/bootstrap_environment.rb +18 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/bootstrap_script.rb +14 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/bootstrap_then_exit.rb +12 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/bootstrapped_dirs.rb +18 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/cached_master_dir.rb +21 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/catalog_only.rb +14 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/color.rb +13 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/compare_file_text.rb +15 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/debug.rb +12 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/display_datatype_changes.rb +16 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/display_detail_add.rb +12 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/display_source_file_line.rb +12 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/enc.rb +31 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/existing_catalogs.rb +25 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/fact_file.rb +23 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/fact_override.rb +19 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/facts_terminus.rb +16 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/from_puppetdb.rb +13 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/header.rb +24 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/hiera_config.rb +18 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/hiera_path_strip.rb +12 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/hostname.rb +13 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/ignore.rb +24 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/ignore_attr.rb +16 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/ignore_tags.rb +23 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/include_tags.rb +12 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/master_cache_branch.rb +12 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/output_file.rb +15 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/output_format.rb +15 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/parallel.rb +12 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/parser.rb +48 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/pass_env_vars.rb +19 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_ssl_ca.rb +15 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_ssl_client_cert.rb +14 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_ssl_client_key.rb +14 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_token.rb +15 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_token_file.rb +17 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_url.rb +19 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/puppet_binary.rb +16 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/puppet_master.rb +16 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/puppet_master_api_version.rb +20 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/puppet_master_ssl_ca.rb +19 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/puppet_master_ssl_client_cert.rb +19 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/puppet_master_ssl_client_key.rb +19 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_ssl_ca.rb +15 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_ssl_client_cert.rb +14 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_ssl_client_key.rb +14 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_ssl_client_password.rb +14 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_ssl_client_password_file.rb +13 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_url.rb +18 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/quiet.rb +12 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/retry_failed_catalog.rb +13 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/safe_to_delete_cached_master_dir.rb +15 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/storeconfigs.rb +12 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/suppress_absent_file_details.rb +14 -0
- data/lib/octocatalog-diff/catalog-diff/cli/options/to_from_branch.rb +16 -0
- data/lib/octocatalog-diff/catalog-diff/cli/printer.rb +52 -0
- data/lib/octocatalog-diff/catalog-diff/differ.rb +615 -0
- data/lib/octocatalog-diff/catalog-diff/display.rb +125 -0
- data/lib/octocatalog-diff/catalog-diff/display/json.rb +25 -0
- data/lib/octocatalog-diff/catalog-diff/display/text.rb +452 -0
- data/lib/octocatalog-diff/catalog-util/bootstrap.rb +145 -0
- data/lib/octocatalog-diff/catalog-util/builddir.rb +289 -0
- data/lib/octocatalog-diff/catalog-util/cached_master_directory.rb +169 -0
- data/lib/octocatalog-diff/catalog-util/command.rb +96 -0
- data/lib/octocatalog-diff/catalog-util/enc.rb +77 -0
- data/lib/octocatalog-diff/catalog-util/enc/noop.rb +22 -0
- data/lib/octocatalog-diff/catalog-util/enc/pe.rb +99 -0
- data/lib/octocatalog-diff/catalog-util/enc/pe/v1.rb +61 -0
- data/lib/octocatalog-diff/catalog-util/enc/script.rb +88 -0
- data/lib/octocatalog-diff/catalog-util/facts.rb +89 -0
- data/lib/octocatalog-diff/catalog-util/fileresources.rb +83 -0
- data/lib/octocatalog-diff/catalog-util/git.rb +65 -0
- data/lib/octocatalog-diff/catalog.rb +209 -0
- data/lib/octocatalog-diff/catalog/computed.rb +205 -0
- data/lib/octocatalog-diff/catalog/json.rb +30 -0
- data/lib/octocatalog-diff/catalog/noop.rb +19 -0
- data/lib/octocatalog-diff/catalog/puppetdb.rb +82 -0
- data/lib/octocatalog-diff/catalog/puppetmaster.rb +121 -0
- data/lib/octocatalog-diff/external/pson/LICENSE +17 -0
- data/lib/octocatalog-diff/external/pson/README.md +20 -0
- data/lib/octocatalog-diff/external/pson/common.rb +370 -0
- data/lib/octocatalog-diff/external/pson/pure.rb +15 -0
- data/lib/octocatalog-diff/external/pson/pure/generator.rb +395 -0
- data/lib/octocatalog-diff/external/pson/pure/parser.rb +307 -0
- data/lib/octocatalog-diff/external/pson/version.rb +8 -0
- data/lib/octocatalog-diff/facts.rb +125 -0
- data/lib/octocatalog-diff/facts/json.rb +20 -0
- data/lib/octocatalog-diff/facts/puppetdb.rb +59 -0
- data/lib/octocatalog-diff/facts/yaml.rb +29 -0
- data/lib/octocatalog-diff/puppetdb.rb +163 -0
- data/lib/octocatalog-diff/util/colored.rb +20 -0
- data/lib/octocatalog-diff/util/httparty.rb +158 -0
- data/lib/octocatalog-diff/util/parallel.rb +170 -0
- data/lib/octocatalog-diff/util/puppetversion.rb +24 -0
- data/lib/octocatalog-diff/version.rb +7 -0
- metadata +386 -0
data/doc/requirements.md
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# Requirements
|
2
|
+
|
3
|
+
To run `octocatalog-diff` you will need these basics:
|
4
|
+
|
5
|
+
- Ruby 2.0 or higher
|
6
|
+
- Mac OS, Linux, or other Unix-line operating system (Windows is not supported)
|
7
|
+
- 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
|
9
|
+
|
10
|
+
We recommend that you also have the following to get the most out of `octocatalog-diff`, but these are not absolute requirements:
|
11
|
+
|
12
|
+
- If your Puppet code stored in a git repository, `octocatalog-diff` can check out branches for you as it does its comparisons. Your git repository can be stored on [GitHub.com](https://github.com/), [GitHub Enterprise](https://enterprise.github.com/home), or similar. If your Puppet code is not stored in a git repository, you can still point the tool at "from" and "to" directories, but you'll have to check them out yourself.
|
13
|
+
|
14
|
+
- If you have API access (HTTPS) to PuppetDB, `octocatalog-diff` can retrieve facts automatically and also support [exported resources](https://docs.puppet.com/puppet/latest/reference/lang_exported.html) if you use them. If you are not using PuppetDB or don't have access, the tool can still read facts from YAML files.
|
15
|
+
|
16
|
+
- If your site uses an [external node classifier](https://docs.puppet.com/guides/external_nodes.html), `octocatalog-diff` can execute the ENC script as part of its catalog compiles. Depending on how your ENC is designed, this may require network access or credentials to some service. If you are not using an ENC, that's fine. If you have an ENC but don't have the requisite access, depending on your setup the tool could produce unexpected results.
|
data/doc/roadmap.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# Roadmap
|
2
|
+
|
3
|
+
This document outlines our philosophy and goals for the continued development of `octocatalog-diff`.
|
4
|
+
|
5
|
+
## Goals
|
6
|
+
|
7
|
+
- Work on a system without a full Puppet installation
|
8
|
+
- Cause no added load on production Puppet masters (unless you specifically choose to do so with non-default options)
|
9
|
+
- Offer a command line tool to help make developers more efficient
|
10
|
+
- Offer the ability to in a Continuous Integration (CI) environment
|
11
|
+
- Be compatible with Puppet 3.8.7, 4.5, and later versions
|
12
|
+
- Provide flexibility to build and compare catalogs even in esoteric Puppet codebases
|
13
|
+
|
14
|
+
## Areas for future development
|
15
|
+
|
16
|
+
We are considering these areas for possible future development:
|
17
|
+
|
18
|
+
- Improved display of diffs, perhaps a web interface
|
19
|
+
- Additional CI use cases
|
20
|
+
- CI output display to summarize a change and a list of affected hosts, rather than listing all changes host-by-host
|
21
|
+
|
22
|
+
## Antipatterns
|
23
|
+
|
24
|
+
These are ideas we've evaluated and decided not to pursue. (If you are considering a [contribution](/.github/CONTRIBUTING.md) along these lines, please [open an issue](https://github.com/github/octocatalog-diff/issues/new) before start working on it. We would feel badly if you did a bunch of work that we could not accept.)
|
25
|
+
|
26
|
+
- Making this into a Puppet module with a "face" so that it can be run with `puppet octocatalog-diff ...` or similar. (We have specifically designed this tool to run without a full Puppet installation. There are [similar projects](/doc/similar.md) that are distributed as Puppet modules.)
|
data/doc/similar.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# Similar Projects
|
2
|
+
|
3
|
+
We are aware of the following projects that do similar things to octocatalog-diff:
|
4
|
+
|
5
|
+
- [Puppet's catalog_preview Puppet module](https://forge.puppet.com/puppetlabs/catalog_preview)
|
6
|
+
|
7
|
+
Installs as a module into your Puppet codebase and helps with migration from older Puppet versions to newer ones, or from open source Puppet to Puppet Enterprise. Also provides the ability to compare environments (branches). Requires a full working Puppet installation.
|
8
|
+
|
9
|
+
- [Zack Smith's catalog_diff Puppet module](https://forge.puppet.com/zack/catalog_diff)
|
10
|
+
|
11
|
+
Installs as a module into your Puppet codebase, allowing you to diff catalogs created by different versions of Puppet. Requires a full working Puppet installation.
|
12
|
+
|
13
|
+
- [camptocamp's puppet-catalog-diff-viewer](https://github.com/camptocamp/puppet-catalog-diff-viewer)
|
14
|
+
|
15
|
+
A viewer for JSON reports produced by the catalog_diff Puppet module.
|
16
|
+
|
17
|
+
`octocatalog-diff` differs from the above projects by running on a system without a fully configured Puppet installation (such as a developer workstation or CI server). This approach allows developers to run it without having access to the production Puppet servers, and it does not put any load on production Puppet masters when it compiles and compares catalogs.
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# Troubleshooting
|
2
|
+
|
3
|
+
Things not quite working as expected? This section will contain hints to help you get up and running.
|
4
|
+
|
5
|
+
### Make sure the tests pass
|
6
|
+
|
7
|
+
If you are getting errors from ruby, we'd really like to know if the tests are passing on your platform. Please follow the [installation instructions](/doc/installation.md#installing-from-source) to install octocatalog-diff from source, if you have not already done so. Once the repository is checked out, change into the directory run `rake` to perform the tests.
|
8
|
+
|
9
|
+
If you get test failures from a clean checkout of the master branch, please [open an issue](https://github.com/github/octocatalog-diff/issues/new) to let us know.
|
10
|
+
|
11
|
+
### Make sure your configuration file is found and error-free
|
12
|
+
|
13
|
+
Run the following command to test for the existence and integrity of your configuration file.
|
14
|
+
|
15
|
+
```
|
16
|
+
octocatalog-diff --config-test
|
17
|
+
```
|
18
|
+
|
19
|
+
If you get an error indicating that the file can't be found, or you get errors arising from the content of the file, please review the [configuration instructions](/doc/configuration.md) to make sure you've set things up correctly.
|
20
|
+
|
21
|
+
### Run the command in debug mode
|
22
|
+
|
23
|
+
Supplying `-d` on the command line, in addition to the node name and any other arguments, will provide a substantial amount of debugging information to the terminal window. If you ultimately end up requesting our help, we will need this debugging output.
|
24
|
+
|
25
|
+
Example:
|
26
|
+
|
27
|
+
```
|
28
|
+
octocatalog-diff -d -n SomeNodeName.yourdomain.com
|
29
|
+
```
|
30
|
+
|
31
|
+
### Run only certain components of the command
|
32
|
+
|
33
|
+
To perform the bootstrapping and catalog compilation in separate steps, you can run octocatalog-diff with arguments asking it to do only one or the other. This will help you narrow down whether the problem is in the bootstrapping (first command) or catalog compilation (second command).
|
34
|
+
|
35
|
+
Be sure you are in the directory where your Puppet code is checked out when you run these commands.
|
36
|
+
|
37
|
+
To run just the bootstrapping code (do this within a checkout of your Puppet repository):
|
38
|
+
|
39
|
+
```
|
40
|
+
mkdir /tmp/octo-test
|
41
|
+
octocatalog-diff -d --bootstrap-then-exit --bootstrapped-from-dir=/tmp/octo-test
|
42
|
+
```
|
43
|
+
|
44
|
+
To run just the catalog compilation code (do this within a checkout of your Puppet repository):
|
45
|
+
|
46
|
+
```
|
47
|
+
octocatalog-diff -d -n SomeNodeName.yourdomain.com -o /tmp/catalog.json --bootstrapped-to-dir=$PWD --catalog-only
|
48
|
+
```
|
49
|
+
|
50
|
+
### Contact us
|
51
|
+
|
52
|
+
Still having trouble? Please [open an issue](https://github.com/github/octocatalog-diff/issues/new) and we will do our best to help.
|
53
|
+
|
54
|
+
Please follow the provided issue template, which will ask you for certain output that we need to diagnose the problem.
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# These are all the classes we believe people might want to call directly, so load
|
2
|
+
# them in response to a 'require octocatalog-diff'.
|
3
|
+
|
4
|
+
loads = [
|
5
|
+
'bootstrap',
|
6
|
+
'catalog',
|
7
|
+
'facts',
|
8
|
+
'puppetdb',
|
9
|
+
'version',
|
10
|
+
'catalog-diff/cli'
|
11
|
+
]
|
12
|
+
loads.each { |f| require_relative "octocatalog-diff/#{f}" }
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'open3'
|
2
|
+
require 'shellwords'
|
3
|
+
|
4
|
+
module OctocatalogDiff
|
5
|
+
# Contains bootstrap function to bootstrap a checked-out Puppet environment.
|
6
|
+
class Bootstrap
|
7
|
+
# Bootstrap a checked-out Puppet environment
|
8
|
+
# @param options [Hash] Options hash:
|
9
|
+
# :path [String] => Directory to bootstrap
|
10
|
+
# :bootstrap_script [String] => Bootstrap script, relative to directory
|
11
|
+
# @return [Hash] => [Fixnum] :status_code, [String] :output
|
12
|
+
def self.bootstrap(options = {})
|
13
|
+
# Options validation
|
14
|
+
unless options[:path].is_a?(String)
|
15
|
+
raise ArgumentError, 'Directory to bootstrap (:path) undefined or wrong data type'
|
16
|
+
end
|
17
|
+
unless File.directory?(options[:path])
|
18
|
+
raise Errno::ENOENT, "Non-existent directory '#{options[:path]}' in bootstrap"
|
19
|
+
end
|
20
|
+
unless options[:bootstrap_script].is_a?(String)
|
21
|
+
raise ArgumentError, 'Bootstrap script (:bootstrap_script) undefined or wrong data type'
|
22
|
+
end
|
23
|
+
bootstrap_script = File.join(options[:path], options[:bootstrap_script])
|
24
|
+
unless File.file?(bootstrap_script)
|
25
|
+
raise Errno::ENOENT, "Non-existent bootstrap script '#{options[:bootstrap_script]}'"
|
26
|
+
end
|
27
|
+
|
28
|
+
# 'env' sets up the environment variables that will be passed to the script.
|
29
|
+
# This is a clean environment.
|
30
|
+
env = {
|
31
|
+
'PWD' => options[:path],
|
32
|
+
'HOME' => ENV['HOME'],
|
33
|
+
'PATH' => ENV['PATH'],
|
34
|
+
'BASEDIR' => options[:basedir]
|
35
|
+
}
|
36
|
+
env.merge!(options[:bootstrap_environment]) if options[:bootstrap_environment].is_a?(Hash)
|
37
|
+
|
38
|
+
# 'opts' are options passed to the Open3.capture2e command which are described
|
39
|
+
# here: http://ruby-doc.org/stdlib-2.1.0/libdoc/open3/rdoc/Open3.html#method-c-capture2e
|
40
|
+
# Setting { :chdir => dir } means the shelled-out script will execute in the specified directory
|
41
|
+
# This natively avoids the need to shell out to 'cd $dir && script/bootstrap'
|
42
|
+
opts = { chdir: options[:path], unsetenv_others: true }
|
43
|
+
|
44
|
+
# Actually execute the command and capture the output (combined stdout and stderr).
|
45
|
+
cmd = [bootstrap_script, options[:bootstrap_args]].compact.map { |x| Shellwords.escape(x) }.join(' ')
|
46
|
+
output, status = Open3.capture2e(env, cmd, opts)
|
47
|
+
{
|
48
|
+
status_code: status.exitstatus,
|
49
|
+
output: output
|
50
|
+
}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
require_relative 'cli/catalogs'
|
2
|
+
require_relative 'cli/diffs'
|
3
|
+
require_relative 'cli/options'
|
4
|
+
require_relative 'cli/printer'
|
5
|
+
require_relative '../catalog-util/cached_master_directory'
|
6
|
+
require_relative 'cli/helpers/fact_override'
|
7
|
+
require_relative '../version'
|
8
|
+
|
9
|
+
require 'logger'
|
10
|
+
require 'socket'
|
11
|
+
|
12
|
+
module OctocatalogDiff
|
13
|
+
module CatalogDiff
|
14
|
+
# This is the CLI for catalog-diff. It's responsible for parsing the command line
|
15
|
+
# arguments and then handing off to appropriate methods to perform the catalog-diff.
|
16
|
+
class Cli
|
17
|
+
# Version number
|
18
|
+
VERSION = OctocatalogDiff::Version::VERSION
|
19
|
+
|
20
|
+
# Exit codes
|
21
|
+
EXITCODE_SUCCESS_NO_DIFFS = 0
|
22
|
+
EXITCODE_FAILURE = 1
|
23
|
+
EXITCODE_SUCCESS_WITH_DIFFS = 2
|
24
|
+
|
25
|
+
# The default type+title+attribute to ignore in catalog-diff.
|
26
|
+
DEFAULT_IGNORES = [
|
27
|
+
{ type: 'Class' } # Don't care about classes themselves, only what they actually do!
|
28
|
+
].freeze
|
29
|
+
|
30
|
+
# The default options.
|
31
|
+
DEFAULT_OPTIONS = {
|
32
|
+
from_env: 'origin/master',
|
33
|
+
to_env: '.',
|
34
|
+
colors: true,
|
35
|
+
debug: false,
|
36
|
+
quiet: false,
|
37
|
+
format: :color_text,
|
38
|
+
display_source_file_line: false,
|
39
|
+
compare_file_text: true,
|
40
|
+
display_datatype_changes: true,
|
41
|
+
parallel: true,
|
42
|
+
suppress_absent_file_details: true
|
43
|
+
}.freeze
|
44
|
+
|
45
|
+
# This method is the one to call externally. It is possible to specify alternate
|
46
|
+
# command line arguments, for testing.
|
47
|
+
# @param argv [Array] Use specified arguments (defaults to ARGV)
|
48
|
+
# @param logger [Logger] Logger object
|
49
|
+
# @param opts [Hash] Additional options
|
50
|
+
# @return [Fixnum] Exit code: 0=no diffs, 1=something went wrong, 2=worked but there are diffs
|
51
|
+
def self.cli(argv = ARGV, logger = Logger.new(STDERR), opts = {})
|
52
|
+
# Save a copy of argv to print out later in debugging
|
53
|
+
argv_save = argv.dup
|
54
|
+
|
55
|
+
# Are there additional ARGV to munge, e.g. that have been supplied in the options from a
|
56
|
+
# configuration file?
|
57
|
+
if opts.key?(:additional_argv)
|
58
|
+
raise ArgumentError, ':additional_argv must be array!' unless opts[:additional_argv].is_a?(Array)
|
59
|
+
argv.concat opts[:additional_argv]
|
60
|
+
end
|
61
|
+
|
62
|
+
# Parse command line
|
63
|
+
options = parse_opts(argv)
|
64
|
+
|
65
|
+
# Additional options from hard-coded specified options. These are only processed if
|
66
|
+
# there are not already values defined from command line options.
|
67
|
+
# Note: do NOT use 'options[k] ||= v' here because if the value of options[k] is boolean(false)
|
68
|
+
# it will then be overridden. Whereas the intent is to define values only for those keys that don't exist.
|
69
|
+
opts.each { |k, v| options[k] = v unless options.key?(k) }
|
70
|
+
veto_options = %w(enc header hiera_config include_tags)
|
71
|
+
veto_options.each { |x| options.delete(x.to_sym) if options["no_#{x}".to_sym] }
|
72
|
+
options[:ignore].concat opts.fetch(:additional_ignores, [])
|
73
|
+
|
74
|
+
# Incorporate default options where needed.
|
75
|
+
# Note: do NOT use 'options[k] ||= v' here because if the value of options[k] is boolean(false)
|
76
|
+
# it will then be overridden. Whereas the intent is to define values only for those keys that don't exist.
|
77
|
+
DEFAULT_OPTIONS.each { |k, v| options[k] = v unless options.key?(k) }
|
78
|
+
|
79
|
+
# Fact overrides come in here - 'options' is modified
|
80
|
+
setup_fact_overrides(options)
|
81
|
+
|
82
|
+
# Configure the logger and logger.debug initial information
|
83
|
+
# 'logger' is modified and used
|
84
|
+
setup_logger(logger, options, argv_save)
|
85
|
+
|
86
|
+
# --catalog-only is a special case that compiles the catalog for the "to" branch
|
87
|
+
# and then exits, without doing any 'diff' whatsoever. Support that option.
|
88
|
+
return catalog_only(logger, options) if options[:catalog_only]
|
89
|
+
|
90
|
+
# Set up the cached master directory - maintain it, adjust options if needed. However, if we
|
91
|
+
# are getting the 'from' catalog from PuppetDB, then don't do this.
|
92
|
+
unless options[:cached_master_dir].nil? || options[:from_puppetdb]
|
93
|
+
OctocatalogDiff::CatalogUtil::CachedMasterDirectory.run(options, logger)
|
94
|
+
end
|
95
|
+
|
96
|
+
# bootstrap_then_exit is a special case that only prepares directories and does not
|
97
|
+
# depend on facts. This happens within the 'catalogs' object, since bootstrapping and
|
98
|
+
# preparing catalogs are tightly coupled operations. However this does not actually
|
99
|
+
# build catalogs.
|
100
|
+
catalogs_obj = OctocatalogDiff::CatalogDiff::Cli::Catalogs.new(options, logger)
|
101
|
+
return bootstrap_then_exit(logger, catalogs_obj) if options[:bootstrap_then_exit]
|
102
|
+
|
103
|
+
# Compile catalogs
|
104
|
+
catalogs = catalogs_obj.catalogs
|
105
|
+
logger.info "Catalogs compiled for #{options[:node]}"
|
106
|
+
|
107
|
+
# Cache catalogs if master caching is enabled. If a catalog is being read from the cached master
|
108
|
+
# directory, set the compilation directory attribute, so that the "compilation directory dependent"
|
109
|
+
# suppressor will still work.
|
110
|
+
%w(from to).each do |x|
|
111
|
+
next unless options["#{x}_env".to_sym] == options.fetch(:master_cache_branch, 'origin/master')
|
112
|
+
next if options[:cached_master_dir].nil?
|
113
|
+
catalogs[x.to_sym].compilation_dir = options["#{x}_catalog_compilation_dir".to_sym] || options[:cached_master_dir]
|
114
|
+
rc = OctocatalogDiff::CatalogUtil::CachedMasterDirectory.save_catalog_in_cache_dir(
|
115
|
+
options[:node],
|
116
|
+
options[:cached_master_dir],
|
117
|
+
catalogs[x.to_sym]
|
118
|
+
)
|
119
|
+
logger.debug "Cached master catalog for #{options[:node]}" if rc
|
120
|
+
end
|
121
|
+
|
122
|
+
# Compute diffs
|
123
|
+
diffs_obj = OctocatalogDiff::CatalogDiff::Cli::Diffs.new(options, logger)
|
124
|
+
diffs = diffs_obj.diffs(catalogs)
|
125
|
+
logger.info "Diffs computed for #{options[:node]}"
|
126
|
+
|
127
|
+
# Display diffs
|
128
|
+
logger.info 'No differences' if diffs.empty?
|
129
|
+
printer_obj = OctocatalogDiff::CatalogDiff::Cli::Printer.new(options, logger)
|
130
|
+
printer_obj.printer(diffs, catalogs[:from].compilation_dir, catalogs[:to].compilation_dir)
|
131
|
+
|
132
|
+
# Return the diff object if requested (generally for testing) or otherwise return exit code
|
133
|
+
return diffs if opts[:RETURN_DIFFS]
|
134
|
+
diffs.any? ? EXITCODE_SUCCESS_WITH_DIFFS : EXITCODE_SUCCESS_NO_DIFFS
|
135
|
+
end
|
136
|
+
|
137
|
+
# Parse command line options with 'optparse'. Returns a hash with the parsed arguments.
|
138
|
+
# @param argv [Array] Command line arguments (MUST be specified)
|
139
|
+
# @return [Hash] Options
|
140
|
+
def self.parse_opts(argv)
|
141
|
+
options = { ignore: DEFAULT_IGNORES.dup }
|
142
|
+
Options.parse_options(argv, options)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Fact overrides come in here
|
146
|
+
def self.setup_fact_overrides(options)
|
147
|
+
[:from_fact_override, :to_fact_override].each do |key|
|
148
|
+
o = options["#{key}_in".to_sym]
|
149
|
+
next unless o.is_a?(Array)
|
150
|
+
next unless o.any?
|
151
|
+
options[key] ||= []
|
152
|
+
options[key].concat o.map { |x| OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new(x) }
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Helper method: Configure and setup logger
|
157
|
+
def self.setup_logger(logger, options, argv_save)
|
158
|
+
# Configure the logger
|
159
|
+
logger.level = Logger::INFO
|
160
|
+
logger.level = Logger::DEBUG if options[:debug]
|
161
|
+
logger.level = Logger::ERROR if options[:quiet]
|
162
|
+
|
163
|
+
# Some debugging information up front
|
164
|
+
logger.debug "Running octocatalog-diff #{VERSION} with ruby #{RUBY_VERSION}"
|
165
|
+
logger.debug "Command line arguments: #{argv_save.inspect}"
|
166
|
+
logger.debug "Running on host #{Socket.gethostname} (#{RUBY_PLATFORM})"
|
167
|
+
end
|
168
|
+
|
169
|
+
# Compile the catalog only
|
170
|
+
def self.catalog_only(logger, options)
|
171
|
+
# Indicate where we are
|
172
|
+
logger.debug "Compiling catalog --catalog-only for #{options[:node]}"
|
173
|
+
|
174
|
+
# Compile catalog
|
175
|
+
catalog_opts = options.merge(
|
176
|
+
from_catalog: '-', # Prevents a compile
|
177
|
+
to_catalog: nil, # Forces a compile
|
178
|
+
)
|
179
|
+
cat_obj = OctocatalogDiff::CatalogDiff::Cli::Catalogs.new(catalog_opts, logger)
|
180
|
+
catalogs = cat_obj.catalogs
|
181
|
+
|
182
|
+
# If the catalog compilation failed, an exception would have been thrown. So if
|
183
|
+
# we get here, the catalog succeeded. Dump the catalog to the appropriate place
|
184
|
+
# and exit successfully.
|
185
|
+
if options[:output_file]
|
186
|
+
File.open(options[:output_file], 'w') { |f| f.write(catalogs[:to].catalog_json) }
|
187
|
+
logger.info "Wrote catalog to #{options[:output_file]}"
|
188
|
+
else
|
189
|
+
puts catalogs[:to].catalog_json
|
190
|
+
end
|
191
|
+
return [catalogs[:from], catalogs[:to]] if options[:RETURN_DIFFS] # For integration testing
|
192
|
+
EXITCODE_SUCCESS_NO_DIFFS
|
193
|
+
end
|
194
|
+
|
195
|
+
# --bootstrap-then-exit command
|
196
|
+
def self.bootstrap_then_exit(logger, catalogs_obj)
|
197
|
+
catalogs_obj.bootstrap_then_exit
|
198
|
+
return EXITCODE_SUCCESS_NO_DIFFS
|
199
|
+
rescue OctocatalogDiff::CatalogDiff::Cli::Catalogs::BootstrapError => exc
|
200
|
+
logger.fatal("--bootstrap-then-exit error: bootstrap failed (#{exc})")
|
201
|
+
return EXITCODE_FAILURE
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'open3'
|
3
|
+
require 'yaml'
|
4
|
+
require_relative '../../catalog-util/bootstrap' # For BootstrapError
|
5
|
+
require_relative '../../catalog'
|
6
|
+
require_relative '../../util/parallel'
|
7
|
+
|
8
|
+
module OctocatalogDiff
|
9
|
+
module CatalogDiff
|
10
|
+
class Cli
|
11
|
+
# Helper class to construct catalogs, performing all necessary steps such as
|
12
|
+
# bootstrapping directories, installing facts, and running puppet.
|
13
|
+
class Catalogs
|
14
|
+
# Exceptions that are anticipated can be caught in the calling class and tested for explicitly in spec tests.
|
15
|
+
class BootstrapError < RuntimeError; end
|
16
|
+
class CatalogError < RuntimeError; end
|
17
|
+
|
18
|
+
# Constructor
|
19
|
+
# @param options [Hash] Options
|
20
|
+
# @param logger [Logger] Logger object
|
21
|
+
def initialize(options, logger)
|
22
|
+
@options = options
|
23
|
+
@logger = logger
|
24
|
+
@catalogs = nil
|
25
|
+
raise '@logger must not be nil' if @logger.nil?
|
26
|
+
end
|
27
|
+
|
28
|
+
# Compile catalogs. This handles building both the old and new catalog (in parallel) and returns
|
29
|
+
# only when both catalogs have been built.
|
30
|
+
# @return [Hash] { :from => [OctocatalogDiff::Catalog], :to => [OctocatalogDiff::Catalog] }
|
31
|
+
def catalogs
|
32
|
+
@catalogs ||= build_catalog_parallelizer
|
33
|
+
end
|
34
|
+
|
35
|
+
# Handles the "bootstrap then exit" option, which bootstraps directories but
|
36
|
+
# exits without compiling catalogs.
|
37
|
+
def bootstrap_then_exit
|
38
|
+
@logger.debug('Begin bootstrap_then_exit')
|
39
|
+
OctocatalogDiff::CatalogUtil::Bootstrap.bootstrap_directory_parallelizer(@options, @logger)
|
40
|
+
@logger.debug('Success bootstrap_then_exit')
|
41
|
+
@logger.info('Successfully completed --bootstrap-then-exit action')
|
42
|
+
rescue OctocatalogDiff::CatalogUtil::Bootstrap::BootstrapError => exc
|
43
|
+
@logger.error("Bootstrap exception: #{exc}")
|
44
|
+
raise BootstrapError, "Bootstrap exception: #{exc}"
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# Parallelizes bootstrapping of directories and building catalogs.
|
50
|
+
# @return [Hash] { :from => OctocatalogDiff::Catalog, :to => OctocatalogDiff::Catalog }
|
51
|
+
def build_catalog_parallelizer
|
52
|
+
# Construct parallel tasks. The array supplied to OctocatalogDiff::Util::Parallel is the task portion
|
53
|
+
# of each of the tuples in catalog_tasks.
|
54
|
+
catalog_tasks = build_catalog_tasks
|
55
|
+
|
56
|
+
# Update any tasks for catalogs that do not need to be compiled. This is the case when --catalog-only
|
57
|
+
# is specified and only one catalog is to be built. This will change matching catalog tasks to the 'noop' type.
|
58
|
+
catalog_tasks.map! do |x|
|
59
|
+
if @options["#{x[0]}_catalog".to_sym] == '-'
|
60
|
+
x[1].args[:backend] = :noop
|
61
|
+
elsif @options["#{x[0]}_catalog".to_sym].is_a?(String)
|
62
|
+
x[1].args[:json] = File.read(@options["#{x[0]}_catalog".to_sym])
|
63
|
+
x[1].args[:backend] = :json
|
64
|
+
end
|
65
|
+
x
|
66
|
+
end
|
67
|
+
|
68
|
+
# Initialize the objects for each parallel task. Initializing the object is very fast and does not actually
|
69
|
+
# build the catalog.
|
70
|
+
result = {}
|
71
|
+
catalog_tasks.each do |x|
|
72
|
+
result[x[0]] = OctocatalogDiff::Catalog.new(x[1].args)
|
73
|
+
@logger.debug "Initialized #{result[x[0]].builder} for #{x[0]}-catalog"
|
74
|
+
end
|
75
|
+
|
76
|
+
# Disable --compare-file-text if either (or both) of the chosen backends do not support it
|
77
|
+
if @options.fetch(:compare_file_text, false)
|
78
|
+
result.each do |_key, val|
|
79
|
+
next unless val.convert_file_resources == false
|
80
|
+
@logger.debug "Disabling --compare-file-text; not supported by #{val.builder}"
|
81
|
+
@options[:compare_file_text] = false
|
82
|
+
catalog_tasks.map! do |x|
|
83
|
+
x[1].args[:compare_file_text] = false
|
84
|
+
x
|
85
|
+
end
|
86
|
+
break
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Inject the starting object into the catalog tasks
|
91
|
+
catalog_tasks.map! do |x|
|
92
|
+
x[1].args[:object] = result[x[0]]
|
93
|
+
x
|
94
|
+
end
|
95
|
+
|
96
|
+
# Execute the parallelized catalog builds
|
97
|
+
passed_catalog_tasks = catalog_tasks.map { |x| x[1] }
|
98
|
+
parallel_catalogs = OctocatalogDiff::Util::Parallel.run_tasks(passed_catalog_tasks, @logger, @options[:parallel])
|
99
|
+
|
100
|
+
# If the catalogs array is empty at this point, there is an unexpected size mismatch. This should
|
101
|
+
# never happen, but test for it anyway.
|
102
|
+
unless parallel_catalogs.size == catalog_tasks.size
|
103
|
+
# :nocov:
|
104
|
+
raise "BUG: mismatch catalog_result (#{parallel_catalogs.size} vs #{catalog_tasks.size})"
|
105
|
+
# :nocov:
|
106
|
+
end
|
107
|
+
|
108
|
+
# Construct result hash. Will eventually be in the format
|
109
|
+
# { :from => OctocatalogDiff::Catalog, :to => OctocatalogDiff::Catalog }
|
110
|
+
|
111
|
+
# Analyze the results from parallel run.
|
112
|
+
catalog_tasks.each do |x|
|
113
|
+
# The `parallel_catalog_obj` is a OctocatalogDiff::Util::Parallel::Result. Get the first element from
|
114
|
+
# the parallel_catalogs output.
|
115
|
+
parallel_catalog_obj = parallel_catalogs.shift
|
116
|
+
|
117
|
+
# Add the result to the 'result' hash
|
118
|
+
add_parallel_result(result, parallel_catalog_obj, x)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Things have succeeded if the :to and :from catalogs exist at this point. If not, things have
|
122
|
+
# failed, and an exception should be thrown.
|
123
|
+
raise CatalogError, 'One or more catalogs failed to compile.' unless result.key?(:to) && result.key?(:from)
|
124
|
+
result
|
125
|
+
end
|
126
|
+
|
127
|
+
# Get catalog compilation tasks.
|
128
|
+
# @return [Array<[key, task]>] Catalog tasks
|
129
|
+
def build_catalog_tasks
|
130
|
+
[:from, :to].map do |key|
|
131
|
+
# These are arguments to OctocatalogDiff::Util::Parallel::Task. In most cases the arguments
|
132
|
+
# of OctocatalogDiff::Util::Parallel::Task are taken directly from options, but there are
|
133
|
+
# some defaults or otherwise-named options that must be set here.
|
134
|
+
args = @options.merge(
|
135
|
+
tag: key.to_s,
|
136
|
+
branch: @options["#{key}_env".to_sym],
|
137
|
+
bootstrapped_dir: @options["bootstrapped_#{key}_dir".to_sym],
|
138
|
+
basedir: @options[:basedir],
|
139
|
+
compare_file_text: @options.fetch(:compare_file_text, true),
|
140
|
+
retry_failed_catalog: @options.fetch(:retry_failed_catalog, 0),
|
141
|
+
parser: @options["parser_#{key}".to_sym]
|
142
|
+
)
|
143
|
+
|
144
|
+
# If any options are in the form of 'to_SOMETHING' or 'from_SOMETHING', this sets the option to
|
145
|
+
# 'SOMETHING' for the catalog if it matches this key. For example, when compiling the 'to' catalog
|
146
|
+
# when an option of :to_some_arg => 'foo', this sets :some_arg => foo, and deletes :to_some_arg and
|
147
|
+
# :from_some_arg.
|
148
|
+
@options.keys.select { |x| x.to_s =~ /^(to|from)_/ }.each do |opt_key|
|
149
|
+
args[opt_key.to_s.sub(/^(to|from)_/, '').to_sym] = @options[opt_key] if opt_key.to_s.start_with?(key.to_s)
|
150
|
+
args.delete(opt_key)
|
151
|
+
end
|
152
|
+
|
153
|
+
# The task is a OctocatalogDiff::Util::Parallel::Task object that contains the method to execute,
|
154
|
+
# validator method, text description, and arguments to provide when calling the method.
|
155
|
+
task = OctocatalogDiff::Util::Parallel::Task.new(
|
156
|
+
method: method(:build_catalog),
|
157
|
+
validator: method(:catalog_validator),
|
158
|
+
description: "build_catalog for #{@options["#{key}_env".to_sym]}",
|
159
|
+
args: args
|
160
|
+
)
|
161
|
+
|
162
|
+
# The format of `catalog_tasks` will be a tuple, where the first element is the key
|
163
|
+
# (e.g. :to or :from) and the second element is the OctocatalogDiff::Util::Parallel::Task object.
|
164
|
+
[key, task]
|
165
|
+
end.compact
|
166
|
+
end
|
167
|
+
|
168
|
+
# Given a result from the 'parallel' run and a corresponding (key,task) tuple, add valid
|
169
|
+
# catalogs to the 'result' hash and throw errors for invalid catalogs.
|
170
|
+
# @param result [Hash] Result hash for build_catalog_parallelizer (may be modified)
|
171
|
+
# @param parallel_catalog_obj [OctocatalogDiff::Util::Parallel::Result] Parallel catalog result
|
172
|
+
# @param key_task_tuple [Array<key, task>] Key, task tuple
|
173
|
+
def add_parallel_result(result, parallel_catalog_obj, key_task_tuple)
|
174
|
+
# Expand the tuple into variables
|
175
|
+
key, task = key_task_tuple
|
176
|
+
|
177
|
+
# For reporting purposes, get the branch name.
|
178
|
+
branch = task.args[:branch]
|
179
|
+
|
180
|
+
# Check the result of the parallel run on this object.
|
181
|
+
if parallel_catalog_obj.status.nil?
|
182
|
+
# The compile was killed because another task failed.
|
183
|
+
@logger.warn "Catalog compile for #{branch} was aborted due to another failure"
|
184
|
+
|
185
|
+
elsif parallel_catalog_obj.output.is_a?(OctocatalogDiff::Catalog)
|
186
|
+
# The result is a catalog, but we do not know if it was successfully compiled
|
187
|
+
# until we test the validity.
|
188
|
+
catalog = parallel_catalog_obj.output
|
189
|
+
if catalog.valid?
|
190
|
+
# The catalog was successfully compiled.
|
191
|
+
result[key] = parallel_catalog_obj.output
|
192
|
+
else
|
193
|
+
# The catalog failed, but a catalog object was returned so that better error reporting
|
194
|
+
# can take place. In this error reporting, we will replace 'Error:' with '[Puppet Error]'
|
195
|
+
# and remove the compilation directory (which is a tmpdir) to reveal only the relative
|
196
|
+
# path to the files involved.
|
197
|
+
dir = catalog.compilation_dir || ''
|
198
|
+
dir_regex = Regexp.new(Regexp.escape(dir) + '/environments/production/')
|
199
|
+
error_display = catalog.error_message.split("\n").map do |line|
|
200
|
+
line.sub(/^Error:/, '[Puppet Error]').gsub(dir_regex, '')
|
201
|
+
end.join("\n")
|
202
|
+
raise CatalogError, "Catalog for #{branch} failed to compile due to errors:\n#{error_display}"
|
203
|
+
end
|
204
|
+
else
|
205
|
+
# Something unhandled went wrong, and an exception was thrown. Reveal a generic message.
|
206
|
+
msg = parallel_catalog_obj.exception.message
|
207
|
+
message = "Catalog for '#{key}' (#{branch}) failed to compile with #{parallel_catalog_obj.exception.class}: #{msg}"
|
208
|
+
message += "\n" + parallel_catalog_obj.exception.backtrace.map { |x| " #{x}" }.join("\n") if @options[:debug]
|
209
|
+
raise CatalogError, message
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# Performs the steps necessary to build a catalog.
|
214
|
+
# @param opts [Hash] Options hash
|
215
|
+
# @return [Hash] { :rc => exit code, :catalog => Catalog as JSON string }
|
216
|
+
def build_catalog(opts, logger = @logger)
|
217
|
+
logger.debug("Setting up Puppet catalog build for #{opts[:branch]}")
|
218
|
+
catalog = opts[:object]
|
219
|
+
logger.debug("Catalog for #{opts[:branch]} will be built with #{catalog.builder}")
|
220
|
+
time_start = Time.now
|
221
|
+
catalog.build(logger)
|
222
|
+
time_it_took = Time.now - time_start
|
223
|
+
retries_str = " retries = #{catalog.retries}" if catalog.retries.is_a?(Fixnum)
|
224
|
+
time_str = "in #{time_it_took} seconds#{retries_str}"
|
225
|
+
status_str = catalog.valid? ? 'successfully built' : 'failed'
|
226
|
+
logger.debug "Catalog for #{opts[:branch]} #{status_str} with #{catalog.builder} #{time_str}"
|
227
|
+
catalog
|
228
|
+
end
|
229
|
+
|
230
|
+
# Validate a catalog in the parallel execution
|
231
|
+
# @param catalog [OctocatalogDiff::Catalog] Catalog object
|
232
|
+
# @return [Boolean] true if catalog is valid, false otherwise
|
233
|
+
def catalog_validator(catalog = nil, _logger = @logger)
|
234
|
+
return false unless catalog.is_a?(OctocatalogDiff::Catalog)
|
235
|
+
catalog.valid?
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|