Skip to content

Commit 401a07a

Browse files
author
Kevin Paulisse
committed
Merge branch 'kpaulisse-arbitrary-command-line-pass' into kpaulisse-validate-references-alias
2 parents 30eb257 + 0e6205c commit 401a07a

42 files changed

Lines changed: 1324 additions & 25 deletions

File tree

Some content is hidden

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

doc/advanced-environments.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Environment setup
2+
3+
When building a catalog, the default behavior of `octocatalog-diff` is to:
4+
5+
1. Create a temporary directory
6+
2. Create a symlink from `<temporary directory>/environments/production` to the checkout of your code
7+
3. Run Puppet using `environment=production`
8+
9+
If you are using environment names to control the behavior of Puppet, this default behavior may not be suitable. In that case you can invoke the alternate behavior: preserving environments.
10+
11+
## Command line options
12+
13+
### Preserving the environments
14+
15+
When you supply the command line argument `--preserve-environments` (or set `settings[:preserve_environments] = true` in your [configuration file](/doc/configuration.md)), `octocatalog-diff` will instead do the following:
16+
17+
1. Create a temporary directory
18+
2. Create the following symlinks from `<temporary directory>` to the corresponding directories in the checkout of your code:
19+
20+
- `environments`
21+
- `manifests`
22+
- `modules`
23+
24+
3. Run Puppet using an environment you specify via the command line
25+
26+
Note that you must have set `--preserve-environments` in order for the `--environment` and/or `--create-symlinks` options (described below) to have any effect.
27+
28+
### Changing the environment
29+
30+
If you wish to use an environment name other than `production` you can use the `--environment <environment_name>` command line option. This will set the environment for both the `to` and `from` compiles.
31+
32+
```
33+
octocatalog-diff ... --preserve-environments --environment some-env-name
34+
```
35+
36+
If you need to specify different environments for the `to` and `from` compiles, you can use `--to-environment <environment_name>` and `--from-environment <environment_name>`.
37+
38+
```
39+
octocatalog-diff ... --preserve-environments --to-environment first-environment --from-environment second-environment
40+
```
41+
42+
### Controlling symlinks that are created
43+
44+
Within the temporary directory, the `environments` symlink will always be created.
45+
46+
By default, `manifests` and `modules` will also be created from the temporary directory to the corresponding directories in your Puppet code base. If you need to customize the symlinks that are created, you can use the `--create-symlinks <dir1>,<dir2>,...` to list the symlinks that you need.
47+
48+
For example, if you have some code stored in a directory called `modules` and more code stored in a directory called `site`, you could do the following to create the symlinks as desired:
49+
50+
```
51+
octocatalog-diff ... --preserve-environments --create-symlinks manifests,modules,site
52+
```
53+
54+
## Examples
55+
56+
Consider that your Puppet code base is organized as follows:
57+
58+
```
59+
- /opt/puppet
60+
- environments
61+
- old
62+
- environment.conf
63+
- manifests
64+
- site.pp
65+
- modules
66+
- module_zero
67+
- new
68+
- environment.conf
69+
- manifests
70+
- site.pp
71+
- modules
72+
- module_zero
73+
- modules
74+
- module_one
75+
- module_two
76+
- site
77+
- module_three
78+
- module_four
79+
```
80+
81+
To calculate the difference between the "old" and "new" environment, you could use:
82+
83+
```
84+
octocatalog-diff \
85+
--bootstrapped-from-dir /opt/puppet \
86+
--bootstrapped-to-dir /opt/puppet \
87+
--preserve-environments \
88+
--from-environment old \
89+
--to-environment new \
90+
--create-symlinks modules,site
91+
```
92+
93+
(Note that `--bootstrapped-from-dir` and `--bootstrapped-to-dir` are used to specify the directory path to your code, and `-t` and `-f` are not used. That's because the difference in the catalog is derived from the environment used, and not the branch from a git repository.)

doc/advanced.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ See also:
2222
- [Puppet Enterprise node classification service](/doc/advanced-pe-enc.md)
2323
- [Using `octocatalog-diff` without git](/doc/advanced-using-without-git.md)
2424
- [Catalog validation](/doc/advanced-catalog-validation.md)
25+
- [Environment setup](/doc/advanced-environment.md)
2526

2627
### Controlling output
2728

doc/optionsref.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,22 @@ Usage: octocatalog-diff [command line options]
127127
--no-ignore-tags Disable ignoring based on tags
128128
--ignore-tags STRING1[,STRING2[,...]]
129129
Specify tags to ignore
130+
--[no-]preserve-environments Enable or disable environment preservation
131+
--environment STRING Environment for catalog compilation globally
132+
--to-environment STRING Environment for catalog compilation for the to branch
133+
--from-environment STRING Environment for catalog compilation for the from branch
134+
--create-symlinks STRING1[,STRING2[,...]]
135+
Symlinks to create globally
136+
--to-create-symlinks STRING1[,STRING2[,...]]
137+
Symlinks to create for the to branch
138+
--from-create-symlinks STRING1[,STRING2[,...]]
139+
Symlinks to create for the from branch
140+
--command-line STRING1[,STRING2[,...]]
141+
Command line arguments globally
142+
--to-command-line STRING1[,STRING2[,...]]
143+
Command line arguments for the to branch
144+
--from-command-line STRING1[,STRING2[,...]]
145+
Command line arguments for the from branch
130146
--pass-env-vars VAR1[,VAR2[,...]]
131147
Environment variables to pass
132148
--[no-]suppress-absent-file-details
@@ -831,6 +847,21 @@ https://your-pe-console-server:4433/classifier-api (<a href="../lib/octocatalog-
831847
</td>
832848
</tr>
833849

850+
<tr>
851+
<td valign=top>
852+
<pre><code>--preserve-environments
853+
--no-preserve-environments </code></pre>
854+
</td>
855+
<td valign=top>
856+
Enable or disable environment preservation
857+
</td>
858+
<td valign=top>
859+
Preserve the `environments` directory from the repository when compiling the catalog. Likely
860+
requires some combination of `--to-environment`, `--from-environment`, and/or `--create-symlinks`
861+
to work correctly. (<a href="../lib/octocatalog-diff/catalog-diff/cli/options/preserve_environments.rb">preserve_environments.rb</a>)
862+
</td>
863+
</tr>
864+
834865
<tr>
835866
<td valign=top>
836867
<pre><code>--puppetdb-api-version N</code></pre>

lib/octocatalog-diff/catalog-diff/cli/catalogs.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ def add_parallel_result(result, parallel_catalog_obj, key_task_tuple)
198198
# and remove the compilation directory (which is a tmpdir) to reveal only the relative
199199
# path to the files involved.
200200
dir = catalog.compilation_dir || ''
201-
dir_regex = Regexp.new(Regexp.escape(dir) + '/environments/production/')
201+
dir_regex = Regexp.new(Regexp.escape(dir) + '/environments/[^/]+/')
202202
error_display = catalog.error_message.split("\n").map do |line|
203203
line.sub(/^Error:/, '[Puppet Error]').gsub(dir_regex, '')
204204
end.join("\n")
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# frozen_string_literal: true
2+
3+
# Provide additional command line flags to set when running Puppet to compile catalogs.
4+
# @param parser [OptionParser object] The OptionParser argument
5+
# @param options [Hash] Options hash being constructed; this is modified in this method.
6+
OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:command_line) do
7+
has_weight 510
8+
9+
def parse(parser, options)
10+
OctocatalogDiff::CatalogDiff::Cli::Options.option_globally_or_per_branch(
11+
parser: parser,
12+
options: options,
13+
cli_name: 'command-line',
14+
option_name: 'command_line',
15+
desc: 'Command line arguments',
16+
datatype: []
17+
)
18+
end
19+
end
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# frozen_string_literal: true
2+
3+
# Specify which directories from the base should be symlinked into the temporary compilation
4+
# environment. This is useful only in conjunction with `--preserve-environments`.
5+
# @param parser [OptionParser object] The OptionParser argument
6+
# @param options [Hash] Options hash being constructed; this is modified in this method.
7+
OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:create_symlinks) do
8+
has_weight 503
9+
10+
def parse(parser, options)
11+
OctocatalogDiff::CatalogDiff::Cli::Options.option_globally_or_per_branch(
12+
parser: parser,
13+
options: options,
14+
cli_name: 'create-symlinks',
15+
option_name: 'create_symlinks',
16+
desc: 'Symlinks to create',
17+
datatype: []
18+
)
19+
end
20+
end
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# frozen_string_literal: true
2+
3+
# Specify the environment to use when compiling the catalog. This is useful only in conjunction
4+
# with `--preserve-environments`.
5+
# @param parser [OptionParser object] The OptionParser argument
6+
# @param options [Hash] Options hash being constructed; this is modified in this method.
7+
OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:environment) do
8+
has_weight 502
9+
10+
def parse(parser, options)
11+
OctocatalogDiff::CatalogDiff::Cli::Options.option_globally_or_per_branch(
12+
parser: parser,
13+
options: options,
14+
cli_name: 'environment',
15+
option_name: 'environment',
16+
desc: 'Environment for catalog compilation'
17+
)
18+
end
19+
end
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# frozen_string_literal: true
2+
3+
# Preserve the `environments` directory from the repository when compiling the catalog. Likely
4+
# requires some combination of `--to-environment`, `--from-environment`, and/or `--create-symlinks`
5+
# to work correctly.
6+
# @param parser [OptionParser object] The OptionParser argument
7+
# @param options [Hash] Options hash being constructed; this is modified in this method.
8+
OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:preserve_environments) do
9+
has_weight 501
10+
11+
def parse(parser, options)
12+
parser.on('--[no-]preserve-environments', 'Enable or disable environment preservation') do |x|
13+
options[:preserve_environments] = x
14+
end
15+
end
16+
end

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

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def initialize(options = {}, logger = nil)
4848
@facts_terminus = options.fetch(:facts_terminus, 'yaml')
4949

5050
create_structure
51-
install_directory_symlink(logger, options[:basedir])
51+
create_symlinks(logger)
5252

5353
# These configurations are optional. Don't call the methods if parameters are nil.
5454
unless options[:puppetdb_url].nil?
@@ -64,12 +64,36 @@ def initialize(options = {}, logger = nil)
6464

6565
# Create common structure
6666
def create_structure
67-
%w(environments facts var var/ssl var/yaml var/yaml/facts).each do |dir|
67+
%w(facts var var/ssl var/yaml var/yaml/facts).each do |dir|
6868
Dir.mkdir(File.join(@tempdir, dir))
6969
FileUtils.chmod 0o755, File.join(@tempdir, dir)
7070
end
7171
end
7272

73+
# Create symlinks.
74+
#
75+
# If the `--preserve-environments` option is used, the `environments` directory, plus `modules` and
76+
# `manifests` symlinks are created. Otherwise, `environments/production` is pointed at the base
77+
# directory.
78+
#
79+
# @param logger [Logger] Logger object
80+
def create_symlinks(logger = nil)
81+
if @options[:preserve_environments]
82+
install_directory_symlink(logger, File.join(@options[:basedir], 'environments'), 'environments')
83+
@options.fetch(:create_symlinks, %w(modules manifests)).each do |x|
84+
install_directory_symlink(logger, File.join(@options[:basedir], x), x)
85+
end
86+
else
87+
if @options[:environment]
88+
logger.warn '--environment is ignored unless --preserve-environments is used' unless logger.nil?
89+
end
90+
if @options[:create_symlinks]
91+
logger.warn '--create-symlinks is ignored unless --preserve-environments is used' unless logger.nil?
92+
end
93+
install_directory_symlink(logger, @options[:basedir])
94+
end
95+
end
96+
7397
# Install puppetdb.conf file in temporary directory
7498
# @param server_urls [String] String for server_urls in puppetdb.conf
7599
# @param server_url_timeout [Fixnum] Value for server_url_timeout in puppetdb.conf
@@ -150,14 +174,20 @@ def install_fact_file(logger, options)
150174

151175
# Install symbolic link to puppet environment
152176
# @param dir [String] Directory to link to
153-
def install_directory_symlink(logger, dir)
177+
# @param target [String] Where the symlink is created, relative to tempdir
178+
def install_directory_symlink(logger, dir, target = 'environments/production')
154179
raise ArgumentError, "Called install_directory_symlink with #{dir.class} argument" unless dir.is_a?(String)
155180
raise Errno::ENOENT, "Specified directory #{dir} doesn't exist" unless File.directory?(dir)
181+
symlink_target = File.join(@tempdir, target)
182+
183+
if target =~ %r{/}
184+
parent_dir = File.dirname(symlink_target)
185+
FileUtils.mkdir_p parent_dir
186+
end
156187

157-
environment_symlink = File.join(@tempdir, 'environments', 'production')
158-
FileUtils.rm_f environment_symlink if File.exist?(environment_symlink)
159-
FileUtils.symlink dir, environment_symlink
160-
logger.debug("Symlinked #{environment_symlink} -> #{dir}")
188+
FileUtils.rm_f symlink_target if File.exist?(symlink_target)
189+
FileUtils.symlink dir, symlink_target
190+
logger.debug("Symlinked #{symlink_target} -> #{dir}")
161191
end
162192

163193
# Install ENC

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

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,14 @@ def puppet_command
7373
--no-ca
7474
--color=false
7575
--config_version="/bin/echo catalogscript"
76-
--environment=production
7776
)
7877

78+
# Add environment - only make this variable if preserve_environments is used.
79+
# If preserve_environments is not used, the hard-coded 'production' here matches
80+
# up with the symlink created under the temporary directory structure.
81+
environ = @options[:preserve_environments] ? @options.fetch(:environment, 'production') : 'production'
82+
cmdline << "--environment=#{Shellwords.escape(environ)}"
83+
7984
# For people who aren't running hiera, a hiera-config will not be generated when @options[:hiera_config]
8085
# is nil. For everyone else, the hiera config was generated/copied/munged in the 'builddir' class
8186
# and was installed into the compile directory and named hiera.yaml.
@@ -90,9 +95,51 @@ def puppet_command
9095
cmdline << "--ssldir=#{Shellwords.escape(File.join(@compilation_dir, 'var', 'ssl'))}"
9196
cmdline << "--confdir=#{Shellwords.escape(@compilation_dir)}"
9297

98+
# Other parameters provided by the user
99+
override_and_append_commandline_with_user_supplied_arguments(cmdline)
100+
93101
# Return full command
94102
cmdline.join(' ')
95103
end
104+
105+
private
106+
107+
# Private: Mutate the command line with arguments that were passed directly from the
108+
# user. This appends new arguments and overwrites existing arguments.
109+
# @param cmdline [Array] Existing command line - mutated by this method
110+
def override_and_append_commandline_with_user_supplied_arguments(cmdline)
111+
return unless @options[:command_line].is_a?(Array)
112+
113+
@options[:command_line].each do |opt|
114+
# Validate format: Accept '--key=value' or '--key' only.
115+
unless opt =~ /\A--([^=\s]+)(=.+)?\z/
116+
raise ArgumentError, "Command line option '#{opt}' does not match format '--SOME_OPTION=SOME_VALUE'"
117+
end
118+
key = Shellwords.escape(Regexp.last_match(1))
119+
val = Regexp.last_match(2)
120+
val.sub!(/\A=/, '') if val.is_a?(String)
121+
122+
# Determine if command line already contains this setting. If yes, the setting provided
123+
# here should override. If no, then append to the commandline.
124+
new_setting = val.nil? ? "--#{key}" : "--#{key}=#{Shellwords.escape(val)}"
125+
ind = key_position(cmdline, key)
126+
if ind.nil?
127+
cmdline << new_setting
128+
else
129+
cmdline[ind] = new_setting
130+
end
131+
end
132+
end
133+
134+
# Private: Determine if the key (given by --key) is already defined in the
135+
# command line. Returns nil if it is not already defined, otherwise returns
136+
# the index.
137+
# @param cmdline [Array] Existing command line
138+
# @param key [String] Key to look up
139+
# @return [Fixnum] Index of where key is defined (nil if undefined)
140+
def key_position(cmdline, key)
141+
cmdline.index { |x| x == "--#{key}" || x =~ /\A--#{key}=/ }
142+
end
96143
end
97144
end
98145
end

0 commit comments

Comments
 (0)