bolt 2.12.0 → 2.17.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 +3 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +7 -2
- data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +7 -4
- 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/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 +20 -13
- data/lib/bolt/catalog.rb +81 -68
- data/lib/bolt/cli.rb +16 -8
- data/lib/bolt/config.rb +150 -138
- data/lib/bolt/config/options.rb +473 -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 +454 -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/logger.rb +3 -1
- data/lib/bolt/outputter.rb +3 -0
- data/lib/bolt/outputter/rainbow.rb +84 -0
- data/lib/bolt/pal.rb +24 -9
- data/lib/bolt/project.rb +64 -55
- data/lib/bolt/resource_instance.rb +10 -3
- data/lib/bolt/shell/bash.rb +30 -42
- data/lib/bolt/shell/powershell.rb +13 -8
- data/lib/bolt/shell/powershell/snippets.rb +8 -0
- data/lib/bolt/transport/docker.rb +9 -5
- data/lib/bolt/transport/local/connection.rb +2 -1
- data/lib/bolt/transport/orch.rb +8 -0
- 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 +22 -18
@@ -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/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,10 +10,10 @@ 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
|
-
global: %w[help version debug] }.freeze
|
16
|
+
global: %w[help version debug log-level] }.freeze
|
17
17
|
|
18
18
|
ACTION_OPTS = OPTIONS.values.flatten.freeze
|
19
19
|
|
@@ -422,7 +422,7 @@ module Bolt
|
|
422
422
|
|
423
423
|
ACTIONS
|
424
424
|
generate-types Generate type references to register in plans
|
425
|
-
install Install modules from a Puppetfile into a
|
425
|
+
install Install modules from a Puppetfile into a project
|
426
426
|
show-modules List modules available to the Bolt project
|
427
427
|
HELP
|
428
428
|
|
@@ -445,7 +445,7 @@ module Bolt
|
|
445
445
|
bolt puppetfile install [options]
|
446
446
|
|
447
447
|
DESCRIPTION
|
448
|
-
Install modules from a Puppetfile into a
|
448
|
+
Install modules from a Puppetfile into a project
|
449
449
|
HELP
|
450
450
|
|
451
451
|
PUPPETFILE_SHOWMODULES_HELP = <<~HELP
|
@@ -709,29 +709,29 @@ module Bolt
|
|
709
709
|
File.expand_path(moduledir)
|
710
710
|
end
|
711
711
|
end
|
712
|
-
define('--boltdir
|
713
|
-
'Specify what
|
712
|
+
define('--project PATH', '--boltdir PATH',
|
713
|
+
'Specify what project to load config from (default: autodiscovered from current working dir)') do |path|
|
714
714
|
@options[:boltdir] = path
|
715
715
|
end
|
716
|
-
define('--configfile
|
716
|
+
define('--configfile PATH',
|
717
717
|
'Specify where to load config from (default: ~/.puppetlabs/bolt/bolt.yaml).',
|
718
|
-
'Directory containing bolt.yaml will be used as the
|
718
|
+
'Directory containing bolt.yaml will be used as the project directory.') do |path|
|
719
719
|
@options[:configfile] = path
|
720
720
|
end
|
721
|
-
define('--hiera-config
|
721
|
+
define('--hiera-config PATH',
|
722
722
|
'Specify where to load Hiera config from (default: ~/.puppetlabs/bolt/hiera.yaml)') do |path|
|
723
723
|
@options[:'hiera-config'] = File.expand_path(path)
|
724
724
|
end
|
725
|
-
define('-i', '--inventoryfile
|
725
|
+
define('-i', '--inventoryfile PATH',
|
726
726
|
'Specify where to load inventory from (default: ~/.puppetlabs/bolt/inventory.yaml)') do |path|
|
727
727
|
if ENV.include?(Bolt::Inventory::ENVIRONMENT_VAR)
|
728
728
|
raise Bolt::CLIError, "Cannot pass inventory file when #{Bolt::Inventory::ENVIRONMENT_VAR} is set"
|
729
729
|
end
|
730
730
|
@options[:inventoryfile] = Pathname.new(File.expand_path(path))
|
731
731
|
end
|
732
|
-
define('--puppetfile
|
732
|
+
define('--puppetfile PATH',
|
733
733
|
'Specify a Puppetfile to use when installing modules. (default: ~/.puppetlabs/bolt/Puppetfile)',
|
734
|
-
'Modules are installed in the current
|
734
|
+
'Modules are installed in the current project.') do |path|
|
735
735
|
@options[:puppetfile_path] = Pathname.new(File.expand_path(path))
|
736
736
|
end
|
737
737
|
define('--[no-]save-rerun', 'Whether to update the rerun file after this command.') do |save|
|
@@ -803,8 +803,15 @@ module Bolt
|
|
803
803
|
end
|
804
804
|
define('--debug', 'Display debug logging') do |_|
|
805
805
|
@options[:debug] = true
|
806
|
+
# We don't actually set '--log-level debug' here, but once the options are evaluated by
|
807
|
+
# the config class the end result is the same.
|
808
|
+
@warnings << { msg: "Command line option '--debug' is deprecated, set '--log-level debug' instead." }
|
809
|
+
end
|
810
|
+
define('--log-level LEVEL',
|
811
|
+
"Set the log level for the console. Available options are",
|
812
|
+
"debug, info, notice, warn, error, fatal, any.") do |level|
|
813
|
+
@options[:log] = { 'console' => { 'level' => level } }
|
806
814
|
end
|
807
|
-
|
808
815
|
define('--plugin PLUGIN', 'Select the plugin to use') do |plug|
|
809
816
|
@options[:plugin] = plug
|
810
817
|
end
|
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
|