bolt 2.11.1 → 2.16.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of bolt might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Puppetfile +1 -1
- data/bolt-modules/boltlib/lib/puppet/datatypes/resourceinstance.rb +3 -2
- data/bolt-modules/boltlib/lib/puppet/functions/add_facts.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/add_to_group.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/catch_errors.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/facts.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/fail_plan.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/get_resources.rb +2 -1
- data/bolt-modules/boltlib/lib/puppet/functions/get_target.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/get_targets.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_fact.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/remove_from_group.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/resolve_references.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/resource.rb +53 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +67 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +6 -3
- data/bolt-modules/boltlib/lib/puppet/functions/run_task_with.rb +8 -2
- data/bolt-modules/boltlib/lib/puppet/functions/set_config.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/set_feature.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/set_resources.rb +66 -43
- data/bolt-modules/boltlib/lib/puppet/functions/set_var.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/vars.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/wait_until_available.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/without_default_logging.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/write_file.rb +1 -0
- data/bolt-modules/ctrl/lib/puppet/functions/ctrl/do_until.rb +2 -0
- data/bolt-modules/ctrl/lib/puppet/functions/ctrl/sleep.rb +2 -0
- data/bolt-modules/file/lib/puppet/functions/file/exists.rb +2 -1
- data/bolt-modules/file/lib/puppet/functions/file/join.rb +2 -0
- data/bolt-modules/file/lib/puppet/functions/file/read.rb +3 -1
- data/bolt-modules/file/lib/puppet/functions/file/readable.rb +3 -1
- data/bolt-modules/file/lib/puppet/functions/file/write.rb +2 -0
- data/bolt-modules/out/lib/puppet/functions/out/message.rb +2 -0
- data/bolt-modules/prompt/lib/puppet/functions/prompt.rb +1 -0
- data/bolt-modules/system/lib/puppet/functions/system/env.rb +2 -0
- data/lib/bolt/analytics.rb +21 -2
- data/lib/bolt/applicator.rb +20 -7
- data/lib/bolt/apply_inventory.rb +4 -0
- data/lib/bolt/apply_target.rb +4 -0
- data/lib/bolt/bolt_option_parser.rb +11 -10
- data/lib/bolt/catalog.rb +81 -68
- data/lib/bolt/cli.rb +18 -8
- data/lib/bolt/config.rb +152 -120
- data/lib/bolt/config/options.rb +321 -0
- data/lib/bolt/config/transport/base.rb +16 -16
- data/lib/bolt/config/transport/docker.rb +9 -23
- data/lib/bolt/config/transport/local.rb +6 -44
- data/lib/bolt/config/transport/options.rb +305 -0
- data/lib/bolt/config/transport/orch.rb +9 -18
- data/lib/bolt/config/transport/remote.rb +3 -6
- data/lib/bolt/config/transport/ssh.rb +59 -114
- data/lib/bolt/config/transport/winrm.rb +18 -47
- data/lib/bolt/executor.rb +14 -1
- data/lib/bolt/inventory/group.rb +1 -1
- data/lib/bolt/inventory/inventory.rb +4 -14
- data/lib/bolt/inventory/target.rb +22 -5
- data/lib/bolt/outputter.rb +3 -0
- data/lib/bolt/outputter/rainbow.rb +80 -0
- data/lib/bolt/pal.rb +6 -1
- data/lib/bolt/project.rb +66 -46
- data/lib/bolt/resource_instance.rb +10 -3
- data/lib/bolt/shell/bash.rb +9 -9
- data/lib/bolt/shell/powershell.rb +2 -1
- data/lib/bolt/shell/powershell/snippets.rb +8 -0
- data/lib/bolt/transport/docker.rb +1 -1
- data/lib/bolt/transport/local/connection.rb +2 -1
- data/lib/bolt/transport/ssh/connection.rb +35 -0
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_spec/bolt_context.rb +1 -1
- data/lib/bolt_spec/run.rb +1 -1
- metadata +23 -5
@@ -67,6 +67,7 @@ Puppet::Functions.create_function(:upload_file, Puppet::Functions::InternalFunct
|
|
67
67
|
executor = Puppet.lookup(:bolt_executor)
|
68
68
|
inventory = Puppet.lookup(:bolt_inventory)
|
69
69
|
|
70
|
+
# Send Analytics Report
|
70
71
|
executor.report_function_call(self.class.name)
|
71
72
|
|
72
73
|
found = Puppet::Parser::Files.find_file(source, scope.compiler.environment)
|
@@ -21,6 +21,7 @@ Puppet::Functions.create_function(:vars) do
|
|
21
21
|
inventory = Puppet.lookup(:bolt_inventory)
|
22
22
|
# Bolt executor not expected when invoked from apply block
|
23
23
|
executor = Puppet.lookup(:bolt_executor) { nil }
|
24
|
+
# Send Analytics Report
|
24
25
|
executor&.report_function_call(self.class.name)
|
25
26
|
|
26
27
|
inventory.vars(target)
|
@@ -33,6 +33,7 @@ Puppet::Functions.create_function(:wait_until_available) do
|
|
33
33
|
executor = Puppet.lookup(:bolt_executor)
|
34
34
|
inventory = Puppet.lookup(:bolt_inventory)
|
35
35
|
|
36
|
+
# Send Analytics Report
|
36
37
|
executor.report_function_call(self.class.name)
|
37
38
|
|
38
39
|
# Ensure that given targets are all Target instances
|
@@ -20,7 +20,9 @@ Puppet::Functions.create_function(:'ctrl::do_until') do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def do_until(options = { 'limit' => 0 })
|
23
|
+
# Send Analytics Report
|
23
24
|
Puppet.lookup(:bolt_executor) {}&.report_function_call(self.class.name)
|
25
|
+
|
24
26
|
limit = options['limit']
|
25
27
|
i = 0
|
26
28
|
until (x = yield)
|
@@ -9,7 +9,7 @@ Puppet::Functions.create_function(:'file::exists', Puppet::Functions::InternalFu
|
|
9
9
|
# @example Check a file on disk
|
10
10
|
# file::exists('/tmp/i_dumped_this_here')
|
11
11
|
# @example check a file from the modulepath
|
12
|
-
# file::exists('example/
|
12
|
+
# file::exists('example/VERSION')
|
13
13
|
dispatch :exists do
|
14
14
|
scope_param
|
15
15
|
required_param 'String', :filename
|
@@ -17,6 +17,7 @@ Puppet::Functions.create_function(:'file::exists', Puppet::Functions::InternalFu
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def exists(scope, filename)
|
20
|
+
# Send Analytics Report
|
20
21
|
Puppet.lookup(:bolt_executor) {}&.report_function_call(self.class.name)
|
21
22
|
found = Puppet::Parser::Files.find_file(filename, scope.compiler.environment)
|
22
23
|
found ? Puppet::FileSystem.exist?(found) : false
|
@@ -8,7 +8,7 @@ Puppet::Functions.create_function(:'file::read', Puppet::Functions::InternalFunc
|
|
8
8
|
# @example Read a file from disk
|
9
9
|
# file::read('/tmp/i_dumped_this_here')
|
10
10
|
# @example Read a file from the modulepath
|
11
|
-
# file::read('example/
|
11
|
+
# file::read('example/VERSION')
|
12
12
|
dispatch :read do
|
13
13
|
scope_param
|
14
14
|
required_param 'String', :filename
|
@@ -16,7 +16,9 @@ Puppet::Functions.create_function(:'file::read', Puppet::Functions::InternalFunc
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def read(scope, filename)
|
19
|
+
# Send Analytics Report
|
19
20
|
Puppet.lookup(:bolt_executor) {}&.report_function_call(self.class.name)
|
21
|
+
|
20
22
|
found = Puppet::Parser::Files.find_file(filename, scope.compiler.environment)
|
21
23
|
unless found && Puppet::FileSystem.exist?(found)
|
22
24
|
raise Puppet::ParseErrorWithIssue.from_issue_and_stack(
|
@@ -9,7 +9,7 @@ Puppet::Functions.create_function(:'file::readable', Puppet::Functions::Internal
|
|
9
9
|
# @example Check a file on disk
|
10
10
|
# file::readable('/tmp/i_dumped_this_here')
|
11
11
|
# @example check a file from the modulepath
|
12
|
-
# file::readable('example/
|
12
|
+
# file::readable('example/VERSION')
|
13
13
|
dispatch :readable do
|
14
14
|
scope_param
|
15
15
|
required_param 'String', :filename
|
@@ -17,7 +17,9 @@ Puppet::Functions.create_function(:'file::readable', Puppet::Functions::Internal
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def readable(scope, filename)
|
20
|
+
# Send Analytics Report
|
20
21
|
Puppet.lookup(:bolt_executor) {}&.report_function_call(self.class.name)
|
22
|
+
|
21
23
|
found = Puppet::Parser::Files.find_file(filename, scope.compiler.environment)
|
22
24
|
found ? File.readable?(found) : false
|
23
25
|
end
|
@@ -23,7 +23,9 @@ Puppet::Functions.create_function(:'out::message') do
|
|
23
23
|
end
|
24
24
|
|
25
25
|
executor = Puppet.lookup(:bolt_executor)
|
26
|
+
# Send Analytics Report
|
26
27
|
executor.report_function_call(self.class.name)
|
28
|
+
|
27
29
|
executor.publish_event(type: :message, message: message)
|
28
30
|
|
29
31
|
nil
|
@@ -30,6 +30,7 @@ Puppet::Functions.create_function(:prompt) do
|
|
30
30
|
options = options.transform_keys(&:to_sym)
|
31
31
|
|
32
32
|
executor = Puppet.lookup(:bolt_executor)
|
33
|
+
# Send analytics report
|
33
34
|
executor.report_function_call(self.class.name)
|
34
35
|
|
35
36
|
response = executor.prompt(prompt, options)
|
data/lib/bolt/analytics.rb
CHANGED
@@ -29,7 +29,7 @@ module Bolt
|
|
29
29
|
def self.build_client
|
30
30
|
logger = Logging.logger[self]
|
31
31
|
begin
|
32
|
-
config_file =
|
32
|
+
config_file = config_path(logger)
|
33
33
|
config = load_config(config_file, logger)
|
34
34
|
rescue ArgumentError
|
35
35
|
config = { 'disabled' => true }
|
@@ -51,6 +51,25 @@ module Bolt
|
|
51
51
|
NoopClient.new
|
52
52
|
end
|
53
53
|
|
54
|
+
def self.config_path(logger)
|
55
|
+
path = File.expand_path(File.join('~', '.puppetlabs', 'etc', 'bolt', 'analytics.yaml'))
|
56
|
+
old_path = File.expand_path(File.join('~', '.puppetlabs', 'bolt', 'analytics.yaml'))
|
57
|
+
|
58
|
+
if File.exist?(path)
|
59
|
+
if File.exist?(old_path)
|
60
|
+
message = "Detected analytics configuration files at '#{old_path}' and '#{path}'. Loading "\
|
61
|
+
"analytics configuration from '#{path}'."
|
62
|
+
logger.warn(message)
|
63
|
+
end
|
64
|
+
|
65
|
+
path
|
66
|
+
elsif File.exist?(old_path)
|
67
|
+
old_path
|
68
|
+
else
|
69
|
+
path
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
54
73
|
def self.load_config(filename, logger)
|
55
74
|
if File.exist?(filename)
|
56
75
|
YAML.load_file(filename)
|
@@ -59,7 +78,7 @@ module Bolt
|
|
59
78
|
logger.warn <<~ANALYTICS
|
60
79
|
Bolt collects data about how you use it. You can opt out of providing this data.
|
61
80
|
|
62
|
-
To disable analytics data collection, add this line to ~/.puppetlabs/bolt/analytics.yaml :
|
81
|
+
To disable analytics data collection, add this line to ~/.puppetlabs/etc/bolt/analytics.yaml :
|
63
82
|
disabled: true
|
64
83
|
|
65
84
|
Read more about what data Bolt collects and why here:
|
data/lib/bolt/applicator.rb
CHANGED
@@ -14,14 +14,16 @@ require 'open3'
|
|
14
14
|
|
15
15
|
module Bolt
|
16
16
|
class Applicator
|
17
|
-
def initialize(inventory, executor, modulepath, plugin_dirs,
|
17
|
+
def initialize(inventory, executor, modulepath, plugin_dirs, project,
|
18
|
+
pdb_client, hiera_config, max_compiles, apply_settings)
|
18
19
|
# lazy-load expensive gem code
|
19
20
|
require 'concurrent'
|
20
21
|
|
21
22
|
@inventory = inventory
|
22
23
|
@executor = executor
|
23
|
-
@modulepath = modulepath
|
24
|
+
@modulepath = modulepath || []
|
24
25
|
@plugin_dirs = plugin_dirs
|
26
|
+
@project = project
|
25
27
|
@pdb_client = pdb_client
|
26
28
|
@hiera_config = hiera_config ? validate_hiera_config(hiera_config) : nil
|
27
29
|
@apply_settings = apply_settings || {}
|
@@ -104,6 +106,16 @@ module Bolt
|
|
104
106
|
out, err, stat = Open3.capture3('ruby', bolt_catalog_exe, 'compile', stdin_data: catalog_input.to_json)
|
105
107
|
ENV['PATH'] = old_path
|
106
108
|
|
109
|
+
# If bolt_catalog does not return valid JSON, we should print stderr to
|
110
|
+
# see what happened
|
111
|
+
print_logs = stat.success?
|
112
|
+
result = begin
|
113
|
+
JSON.parse(out)
|
114
|
+
rescue JSON::ParserError
|
115
|
+
print_logs = true
|
116
|
+
{ 'message' => "Something's gone terribly wrong! STDERR is logged." }
|
117
|
+
end
|
118
|
+
|
107
119
|
# Any messages logged by Puppet will be on stderr as JSON hashes, so we
|
108
120
|
# parse those and store them here. Any message on stderr that is not
|
109
121
|
# properly JSON formatted is assumed to be an error message. If
|
@@ -117,17 +129,15 @@ module Bolt
|
|
117
129
|
{ 'level' => 'err', 'message' => line }
|
118
130
|
end
|
119
131
|
|
120
|
-
|
121
|
-
if stat.success?
|
132
|
+
if print_logs
|
122
133
|
logs.each do |log|
|
123
134
|
bolt_level = Bolt::Util::PuppetLogLevel::MAPPING[log['level'].to_sym]
|
124
135
|
message = log['message'].chomp
|
125
136
|
@logger.send(bolt_level, "#{target.name}: #{message}")
|
126
137
|
end
|
127
|
-
result
|
128
|
-
else
|
129
|
-
raise ApplyError.new(target.name, result['message'])
|
130
138
|
end
|
139
|
+
raise ApplyError.new(target.name, result['message']) unless stat.success?
|
140
|
+
result
|
131
141
|
end
|
132
142
|
|
133
143
|
def validate_hiera_config(hiera_config)
|
@@ -144,6 +154,7 @@ module Bolt
|
|
144
154
|
|
145
155
|
def apply(args, apply_body, scope)
|
146
156
|
raise(ArgumentError, 'apply requires a TargetSpec') if args.empty?
|
157
|
+
raise(ArgumentError, 'apply requires at least one statement in the apply block') if apply_body.nil?
|
147
158
|
type0 = Puppet.lookup(:pal_script_compiler).type('TargetSpec')
|
148
159
|
Puppet::Pal.assert_type(type0, args[0], 'apply targets')
|
149
160
|
|
@@ -185,9 +196,11 @@ module Bolt
|
|
185
196
|
type_by_reference: true,
|
186
197
|
local_reference: true)
|
187
198
|
|
199
|
+
bolt_project = @project if @project&.name
|
188
200
|
scope = {
|
189
201
|
code_ast: ast,
|
190
202
|
modulepath: @modulepath,
|
203
|
+
project: bolt_project.to_h,
|
191
204
|
pdb_config: @pdb_client.config.to_hash,
|
192
205
|
hiera_config: @hiera_config,
|
193
206
|
plan_vars: plan_vars,
|
data/lib/bolt/apply_inventory.rb
CHANGED
data/lib/bolt/apply_target.rb
CHANGED
@@ -10,7 +10,7 @@ module Bolt
|
|
10
10
|
authentication: %w[user password password-prompt private-key host-key-check ssl ssl-verify],
|
11
11
|
escalation: %w[run-as sudo-password sudo-password-prompt sudo-executable],
|
12
12
|
run_context: %w[concurrency inventoryfile save-rerun cleanup],
|
13
|
-
global_config_setters: %w[modulepath
|
13
|
+
global_config_setters: %w[modulepath project configfile],
|
14
14
|
transports: %w[transport connect-timeout tty ssh-command copy-command],
|
15
15
|
display: %w[format color verbose trace],
|
16
16
|
global: %w[help version debug] }.freeze
|
@@ -20,7 +20,7 @@ module Bolt
|
|
20
20
|
def get_help_text(subcommand, action = nil)
|
21
21
|
case subcommand
|
22
22
|
when 'apply'
|
23
|
-
{ flags: ACTION_OPTS + %w[noop execute compile-concurrency],
|
23
|
+
{ flags: ACTION_OPTS + %w[noop execute compile-concurrency hiera-config],
|
24
24
|
banner: APPLY_HELP }
|
25
25
|
when 'command'
|
26
26
|
case action
|
@@ -172,13 +172,14 @@ module Bolt
|
|
172
172
|
apply
|
173
173
|
|
174
174
|
USAGE
|
175
|
-
bolt apply
|
175
|
+
bolt apply [manifest.pp] [options]
|
176
176
|
|
177
177
|
DESCRIPTION
|
178
178
|
Apply Puppet manifest code on the specified targets.
|
179
179
|
|
180
180
|
EXAMPLES
|
181
|
-
bolt apply manifest.pp
|
181
|
+
bolt apply manifest.pp -t target
|
182
|
+
bolt apply -e "file { '/etc/puppetlabs': ensure => present }" -t target
|
182
183
|
HELP
|
183
184
|
|
184
185
|
COMMAND_HELP = <<~HELP
|
@@ -421,7 +422,7 @@ module Bolt
|
|
421
422
|
|
422
423
|
ACTIONS
|
423
424
|
generate-types Generate type references to register in plans
|
424
|
-
install Install modules from a Puppetfile into a
|
425
|
+
install Install modules from a Puppetfile into a project
|
425
426
|
show-modules List modules available to the Bolt project
|
426
427
|
HELP
|
427
428
|
|
@@ -444,7 +445,7 @@ module Bolt
|
|
444
445
|
bolt puppetfile install [options]
|
445
446
|
|
446
447
|
DESCRIPTION
|
447
|
-
Install modules from a Puppetfile into a
|
448
|
+
Install modules from a Puppetfile into a project
|
448
449
|
HELP
|
449
450
|
|
450
451
|
PUPPETFILE_SHOWMODULES_HELP = <<~HELP
|
@@ -708,13 +709,13 @@ module Bolt
|
|
708
709
|
File.expand_path(moduledir)
|
709
710
|
end
|
710
711
|
end
|
711
|
-
define('--boltdir FILEPATH',
|
712
|
-
'Specify what
|
712
|
+
define('--project FILEPATH', '--boltdir FILEPATH',
|
713
|
+
'Specify what project to load config from (default: autodiscovered from current working dir)') do |path|
|
713
714
|
@options[:boltdir] = path
|
714
715
|
end
|
715
716
|
define('--configfile FILEPATH',
|
716
717
|
'Specify where to load config from (default: ~/.puppetlabs/bolt/bolt.yaml).',
|
717
|
-
'Directory containing bolt.yaml will be used as the
|
718
|
+
'Directory containing bolt.yaml will be used as the project directory.') do |path|
|
718
719
|
@options[:configfile] = path
|
719
720
|
end
|
720
721
|
define('--hiera-config FILEPATH',
|
@@ -730,7 +731,7 @@ module Bolt
|
|
730
731
|
end
|
731
732
|
define('--puppetfile FILEPATH',
|
732
733
|
'Specify a Puppetfile to use when installing modules. (default: ~/.puppetlabs/bolt/Puppetfile)',
|
733
|
-
'Modules are installed in the current
|
734
|
+
'Modules are installed in the current project.') do |path|
|
734
735
|
@options[:puppetfile_path] = Pathname.new(File.expand_path(path))
|
735
736
|
end
|
736
737
|
define('--[no-]save-rerun', 'Whether to update the rerun file after this command.') do |save|
|
data/lib/bolt/catalog.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'bolt/apply_inventory'
|
3
4
|
require 'bolt/apply_target'
|
4
5
|
require 'bolt/config'
|
5
6
|
require 'bolt/error'
|
6
7
|
require 'bolt/inventory'
|
7
|
-
require 'bolt/apply_inventory'
|
8
8
|
require 'bolt/pal'
|
9
9
|
require 'bolt/puppetdb'
|
10
10
|
require 'bolt/util'
|
@@ -19,7 +19,7 @@ module Bolt
|
|
19
19
|
@log_level = log_level
|
20
20
|
end
|
21
21
|
|
22
|
-
def with_puppet_settings(
|
22
|
+
def with_puppet_settings(overrides = {})
|
23
23
|
Dir.mktmpdir('bolt') do |dir|
|
24
24
|
cli = []
|
25
25
|
Puppet::Settings::REQUIRED_APP_SETTINGS.each do |setting|
|
@@ -31,7 +31,9 @@ module Bolt
|
|
31
31
|
Puppet.settings.override_default(:vendormoduledir, '')
|
32
32
|
|
33
33
|
Puppet.initialize_settings(cli)
|
34
|
-
|
34
|
+
overrides.each do |setting, value|
|
35
|
+
Puppet.settings[setting] = value
|
36
|
+
end
|
35
37
|
|
36
38
|
# Use a special logdest that serializes all log messages and their level to stderr.
|
37
39
|
Puppet::Util::Log.newdestination(:stderr)
|
@@ -54,80 +56,51 @@ module Bolt
|
|
54
56
|
end
|
55
57
|
|
56
58
|
def compile_catalog(request)
|
57
|
-
pal_main = request['code_ast'] || request['code_string']
|
58
|
-
target = request['target']
|
59
59
|
pdb_client = Bolt::PuppetDB::Client.new(Bolt::PuppetDB::Config.new(request['pdb_config']))
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
60
|
+
project = request['project'] || {}
|
61
|
+
bolt_project = Struct.new(:name, :path).new(project['name'], project['path']) unless project.empty?
|
62
|
+
inv = Bolt::ApplyInventory.new(request['config'])
|
63
|
+
puppet_overrides = {
|
64
|
+
bolt_pdb_client: pdb_client,
|
65
|
+
bolt_inventory: inv,
|
66
|
+
bolt_project: bolt_project
|
67
|
+
}
|
68
|
+
|
69
|
+
# Facts will be set by the catalog compiler, so we need to ensure
|
70
|
+
# that any plan or target variables with the same name are not
|
71
|
+
# passed into the apply block to avoid a redefinition error.
|
72
|
+
# Filter out plan and target vars separately and raise a Puppet
|
73
|
+
# warning if there are any collisions for either. Puppet warning
|
74
|
+
# is the only way to log a message that will make it back to Bolt
|
75
|
+
# to be printed.
|
76
|
+
target = request['target']
|
77
|
+
plan_vars = shadow_vars('plan', request['plan_vars'], target['facts'])
|
78
|
+
target_vars = shadow_vars('target', target['variables'], target['facts'])
|
79
|
+
topscope_vars = target_vars.merge(plan_vars)
|
80
|
+
env_conf = { modulepath: request['modulepath'],
|
81
|
+
facts: target['facts'],
|
82
|
+
variables: topscope_vars }
|
83
|
+
|
84
|
+
puppet_settings = {
|
85
|
+
node_name_value: target['name'],
|
86
|
+
hiera_config: request['hiera_config']
|
87
|
+
}
|
88
|
+
|
89
|
+
with_puppet_settings(puppet_settings) do
|
67
90
|
Puppet::Pal.in_tmp_environment('bolt_catalog', env_conf) do |pal|
|
68
|
-
|
69
|
-
Puppet.override(bolt_pdb_client: pdb_client,
|
70
|
-
bolt_inventory: inv) do
|
91
|
+
Puppet.override(puppet_overrides) do
|
71
92
|
Puppet.lookup(:pal_current_node).trusted_data = target['trusted']
|
72
93
|
pal.with_catalog_compiler do |compiler|
|
73
|
-
|
74
|
-
# loaders are initialized for loading
|
75
|
-
plan_vars = Puppet::Pops::Serialization::FromDataConverter.convert(request['plan_vars'])
|
76
|
-
|
77
|
-
# Facts will be set by the catalog compiler, so we need to ensure
|
78
|
-
# that any plan or target variables with the same name are not
|
79
|
-
# passed into the apply block to avoid a redefinition error.
|
80
|
-
# Filter out plan and target vars separately and raise a Puppet
|
81
|
-
# warning if there are any collisions for either. Puppet warning
|
82
|
-
# is the only way to log a message that will make it back to Bolt
|
83
|
-
# to be printed.
|
84
|
-
pv_collisions, pv_filtered = plan_vars.partition do |k, _|
|
85
|
-
target['facts'].keys.include?(k)
|
86
|
-
end.map(&:to_h)
|
87
|
-
unless pv_collisions.empty?
|
88
|
-
print_pv = pv_collisions.keys.map { |k| "$#{k}" }.join(', ')
|
89
|
-
plural = pv_collisions.keys.length == 1 ? '' : 's'
|
90
|
-
Puppet.warning("Plan variable#{plural} #{print_pv} will be overridden by fact#{plural} " \
|
91
|
-
"of the same name in the apply block")
|
92
|
-
end
|
93
|
-
|
94
|
-
tv_collisions, tv_filtered = target['variables'].partition do |k, _|
|
95
|
-
target['facts'].keys.include?(k)
|
96
|
-
end.map(&:to_h)
|
97
|
-
unless tv_collisions.empty?
|
98
|
-
print_tv = tv_collisions.keys.map { |k| "$#{k}" }.join(', ')
|
99
|
-
plural = tv_collisions.keys.length == 1 ? '' : 's'
|
100
|
-
Puppet.warning("Target variable#{plural} #{print_tv} " \
|
101
|
-
"will be overridden by fact#{plural} of the same name in the apply block")
|
102
|
-
end
|
103
|
-
|
104
|
-
pal.send(:add_variables, compiler.send(:topscope), tv_filtered.merge(pv_filtered))
|
105
|
-
|
94
|
+
options = request['puppet_config'] || {}
|
106
95
|
# Configure language strictness in the CatalogCompiler. We want Bolt to be able
|
107
96
|
# to compile most Puppet 4+ manifests, so we default to allowing deprecated functions.
|
108
97
|
Puppet[:strict] = options['strict'] || :warning
|
109
98
|
Puppet[:strict_variables] = options['strict_variables'] || false
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
# plan. In that case, we need to discover the definitions (which
|
114
|
-
# would ordinarily be stored on the Program) and construct a Program object.
|
115
|
-
unless ast.is_a?(Puppet::Pops::Model::Program)
|
116
|
-
# Node definitions must be at the top level of the apply block.
|
117
|
-
# That means the apply body either a) consists of just a
|
118
|
-
# NodeDefinition, b) consists of a BlockExpression which may
|
119
|
-
# contain NodeDefinitions, or c) doesn't contain NodeDefinitions.
|
120
|
-
definitions = if ast.is_a?(Puppet::Pops::Model::BlockExpression)
|
121
|
-
ast.statements.select { |st| st.is_a?(Puppet::Pops::Model::NodeDefinition) }
|
122
|
-
elsif ast.is_a?(Puppet::Pops::Model::NodeDefinition)
|
123
|
-
[ast]
|
124
|
-
else
|
125
|
-
[]
|
126
|
-
end
|
127
|
-
ast = Puppet::Pops::Model::Factory.PROGRAM(ast, definitions, ast.locator).model
|
128
|
-
end
|
99
|
+
|
100
|
+
pal_main = request['code_ast'] || request['code_string']
|
101
|
+
ast = build_program(pal_main)
|
129
102
|
compiler.evaluate(ast)
|
130
|
-
compiler.
|
103
|
+
compiler.evaluate_ast_node
|
131
104
|
compiler.compile_additions
|
132
105
|
compiler.with_json_encoding(&:encode)
|
133
106
|
end
|
@@ -135,5 +108,45 @@ module Bolt
|
|
135
108
|
end
|
136
109
|
end
|
137
110
|
end
|
111
|
+
|
112
|
+
# Warn and remove variables that will be shadowed by facts of the same
|
113
|
+
# name, which are set in scope earlier.
|
114
|
+
def shadow_vars(type, vars, facts)
|
115
|
+
collisions, valid = vars.partition do |k, _|
|
116
|
+
facts.include?(k)
|
117
|
+
end
|
118
|
+
if collisions.any?
|
119
|
+
names = collisions.map { |k, _| "$#{k}" }.join(', ')
|
120
|
+
plural = collisions.length == 1 ? '' : 's'
|
121
|
+
Puppet.warning("#{type.capitalize} variable#{plural} #{names} will be overridden by fact#{plural} " \
|
122
|
+
"of the same name in the apply block")
|
123
|
+
end
|
124
|
+
valid.to_h
|
125
|
+
end
|
126
|
+
|
127
|
+
def build_program(code)
|
128
|
+
ast = Puppet::Pops::Serialization::FromDataConverter.convert(code)
|
129
|
+
|
130
|
+
# This will be a Program when running via `bolt apply`, but will
|
131
|
+
# only be a subset of the AST when compiling an apply block in a
|
132
|
+
# plan. In that case, we need to discover the definitions (which
|
133
|
+
# would ordinarily be stored on the Program) and construct a Program object.
|
134
|
+
if ast.is_a?(Puppet::Pops::Model::Program)
|
135
|
+
ast
|
136
|
+
else
|
137
|
+
# Node definitions must be at the top level of the apply block.
|
138
|
+
# That means the apply body either a) consists of just a
|
139
|
+
# NodeDefinition, b) consists of a BlockExpression which may
|
140
|
+
# contain NodeDefinitions, or c) doesn't contain NodeDefinitions.
|
141
|
+
definitions = if ast.is_a?(Puppet::Pops::Model::BlockExpression)
|
142
|
+
ast.statements.select { |st| st.is_a?(Puppet::Pops::Model::NodeDefinition) }
|
143
|
+
elsif ast.is_a?(Puppet::Pops::Model::NodeDefinition)
|
144
|
+
[ast]
|
145
|
+
else
|
146
|
+
[]
|
147
|
+
end
|
148
|
+
Puppet::Pops::Model::Factory.PROGRAM(ast, definitions, ast.locator).model
|
149
|
+
end
|
150
|
+
end
|
138
151
|
end
|
139
152
|
end
|