bolt 1.47.0 → 1.48.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 +2 -2
- data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +29 -46
- data/bolt-modules/boltlib/lib/puppet/functions/get_resources.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +2 -2
- data/lib/bolt/applicator.rb +15 -10
- data/lib/bolt/bolt_option_parser.rb +2 -2
- data/lib/bolt/cli.rb +13 -2
- data/lib/bolt/config.rb +83 -14
- data/lib/bolt/outputter/human.rb +6 -6
- data/lib/bolt/outputter/json.rb +7 -7
- data/lib/bolt/pal.rb +7 -4
- data/lib/bolt/plugin.rb +3 -3
- data/lib/bolt/plugin/env_var.rb +30 -0
- data/lib/bolt/plugin/prompt.rb +1 -2
- data/lib/bolt/task.rb +50 -19
- data/lib/bolt/task/puppet_server.rb +6 -9
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/transport_app.rb +2 -1
- data/libexec/apply_catalog.rb +3 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 006dcb3a880fefec3005eebb9f31126c3dc164c45d90010f5e7d5b6d984556e2
|
4
|
+
data.tar.gz: eaf4f944a88fba6aa4f1a0bb6fabe227246fa1ca90a63516a60d8db656f05176
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3fc3a8337bed7f52c5b091a94b388de07514d3dcc0840d1523b1417769e244dfa1840b8a77616170589343ceb451e726121752eb4927db271cda526ad7eb0b0e
|
7
|
+
data.tar.gz: 617985134dd23308316303222af69da7ca08bf1840b5fb7301a0dc9b609ba0cc1430877b3bf02c7aaa1f2173c1ca20a76dc36594332f0b8f979aa65b5620f449
|
data/Puppetfile
CHANGED
@@ -6,8 +6,8 @@ moduledir File.join(File.dirname(__FILE__), 'modules')
|
|
6
6
|
|
7
7
|
# Core modules used by 'apply'
|
8
8
|
mod 'puppetlabs-service', '1.1.0'
|
9
|
-
mod 'puppetlabs-
|
10
|
-
mod 'puppetlabs-
|
9
|
+
mod 'puppetlabs-puppet_agent', '3.0.1'
|
10
|
+
mod 'puppetlabs-facts', '1.0.0'
|
11
11
|
|
12
12
|
# Core types and providers for Puppet 6
|
13
13
|
mod 'puppetlabs-augeas_core', '1.0.5'
|
@@ -7,13 +7,9 @@ require 'bolt/task'
|
|
7
7
|
# installed using either the configured plugin or the `task` plugin with the
|
8
8
|
# `puppet_agent::install` task.
|
9
9
|
#
|
10
|
-
# Agent
|
10
|
+
# Agent installation will be skipped if the target includes the 'puppet-agent' feature, either as a
|
11
11
|
# property of its transport (PCP) or by explicitly setting it as a feature in Bolt's inventory.
|
12
12
|
#
|
13
|
-
# If Bolt does not detect an agent on the target using the 'puppet_agent::version' task,
|
14
|
-
# it will install the agent using either the configured plugin or the
|
15
|
-
# task plugin.
|
16
|
-
#
|
17
13
|
# **NOTE:** Not available in apply block
|
18
14
|
Puppet::Functions.create_function(:apply_prep) do
|
19
15
|
# @param targets A pattern or array of patterns identifying a set of targets.
|
@@ -41,7 +37,7 @@ Puppet::Functions.create_function(:apply_prep) do
|
|
41
37
|
raise Bolt::ValidationError, "Invalid parameters for #{errors.join("\n")}"
|
42
38
|
end
|
43
39
|
|
44
|
-
Bolt::Task.
|
40
|
+
Bolt::Task.from_task_signature(tasksig)
|
45
41
|
end
|
46
42
|
|
47
43
|
# rubocop:disable Naming/AccessorMethodName
|
@@ -79,53 +75,40 @@ Puppet::Functions.create_function(:apply_prep) do
|
|
79
75
|
executor.log_action('install puppet and gather facts', targets) do
|
80
76
|
executor.without_default_logging do
|
81
77
|
# Skip targets that include the puppet-agent feature, as we know an agent will be available.
|
82
|
-
agent_targets,
|
78
|
+
agent_targets, need_install_targets = targets.partition { |target| agent?(target, executor, inventory) }
|
83
79
|
agent_targets.each { |target| Puppet.debug "Puppet Agent feature declared for #{target.name}" }
|
84
|
-
unless
|
85
|
-
#
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
require 'concurrent'
|
99
|
-
pool = Concurrent::ThreadPoolExecutor.new
|
100
|
-
|
101
|
-
hooks = need_install_targets.map do |t|
|
102
|
-
begin
|
103
|
-
opts = t.plugin_hooks&.fetch('puppet_library').dup
|
104
|
-
plugin_name = opts.delete('plugin')
|
105
|
-
hook = inventory.plugins.get_hook(plugin_name, :puppet_library)
|
106
|
-
{ 'target' => t,
|
107
|
-
'hook_proc' => hook.call(opts, t, self) }
|
108
|
-
rescue StandardError => e
|
109
|
-
Bolt::Result.from_exception(t, e)
|
110
|
-
end
|
80
|
+
unless need_install_targets.empty?
|
81
|
+
# lazy-load expensive gem code
|
82
|
+
require 'concurrent'
|
83
|
+
pool = Concurrent::ThreadPoolExecutor.new
|
84
|
+
|
85
|
+
hooks = need_install_targets.map do |t|
|
86
|
+
begin
|
87
|
+
opts = t.plugin_hooks&.fetch('puppet_library').dup
|
88
|
+
plugin_name = opts.delete('plugin')
|
89
|
+
hook = inventory.plugins.get_hook(plugin_name, :puppet_library)
|
90
|
+
{ 'target' => t,
|
91
|
+
'hook_proc' => hook.call(opts, t, self) }
|
92
|
+
rescue StandardError => e
|
93
|
+
Bolt::Result.from_exception(t, e)
|
111
94
|
end
|
95
|
+
end
|
112
96
|
|
113
|
-
|
114
|
-
|
115
|
-
futures = ok_hooks.map do |hash|
|
116
|
-
Concurrent::Future.execute(executor: pool) do
|
117
|
-
hash['hook_proc'].call
|
118
|
-
end
|
119
|
-
end
|
97
|
+
hook_errors, ok_hooks = hooks.partition { |h| h.is_a?(Bolt::Result) }
|
120
98
|
|
121
|
-
|
122
|
-
|
99
|
+
futures = ok_hooks.map do |hash|
|
100
|
+
Concurrent::Future.execute(executor: pool) do
|
101
|
+
hash['hook_proc'].call
|
123
102
|
end
|
124
|
-
|
125
|
-
raise Bolt::RunFailure.new(set.error_set, 'apply_prep') unless set.ok
|
103
|
+
end
|
126
104
|
|
127
|
-
|
105
|
+
results = futures.zip(ok_hooks).map do |f, hash|
|
106
|
+
f.value || Bolt::Result.from_exception(hash['target'], f.reason)
|
128
107
|
end
|
108
|
+
set = Bolt::ResultSet.new(results + hook_errors)
|
109
|
+
raise Bolt::RunFailure.new(set.error_set, 'apply_prep') unless set.ok
|
110
|
+
|
111
|
+
need_install_targets.each { |target| set_agent_feature(target) }
|
129
112
|
end
|
130
113
|
|
131
114
|
# Gather facts, including custom facts
|
@@ -30,7 +30,7 @@ Puppet::Functions.create_function(:get_resources) do
|
|
30
30
|
tasksig = script_compiler.task_signature(name)
|
31
31
|
raise Bolt::Error.new("#{name} could not be found", 'bolt/get-resources') unless tasksig
|
32
32
|
|
33
|
-
task = Bolt::Task.
|
33
|
+
task = Bolt::Task.from_task_signature(tasksig)
|
34
34
|
results = executor.run_task(targets, task, args)
|
35
35
|
raise Bolt::RunFailure.new(results, 'run_task', task.name) unless results.ok?
|
36
36
|
results
|
@@ -72,7 +72,7 @@ Puppet::Functions.create_function(:run_task) do
|
|
72
72
|
# Don't bother loading the local task definition if all targets use the 'pcp' transport.
|
73
73
|
if !targets.empty? && targets.all? { |t| t.transport == 'pcp' }
|
74
74
|
# create a fake task
|
75
|
-
task = Bolt::Task.new(
|
75
|
+
task = Bolt::Task.new(task_name, {}, [{ 'name' => '', 'path' => '' }])
|
76
76
|
else
|
77
77
|
# TODO: use the compiler injection once PUP-8237 lands
|
78
78
|
task_signature = Puppet::Pal::ScriptCompiler.new(closure_scope.compiler).task_signature(task_name)
|
@@ -80,7 +80,7 @@ Puppet::Functions.create_function(:run_task) do
|
|
80
80
|
raise Bolt::Error.unknown_task(task_name)
|
81
81
|
end
|
82
82
|
|
83
|
-
task = Bolt::Task.
|
83
|
+
task = Bolt::Task.from_task_signature(task_signature)
|
84
84
|
|
85
85
|
# Set the default value for any params that have one and were not provided
|
86
86
|
params = task.parameter_defaults.merge(params)
|
data/lib/bolt/applicator.rb
CHANGED
@@ -1,19 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'base64'
|
4
|
+
require 'bolt/apply_result'
|
5
|
+
require 'bolt/apply_target'
|
6
|
+
require 'bolt/config'
|
7
|
+
require 'bolt/error'
|
8
|
+
require 'bolt/task'
|
9
|
+
require 'bolt/util/puppet_log_level'
|
4
10
|
require 'find'
|
5
11
|
require 'json'
|
6
12
|
require 'logging'
|
7
13
|
require 'open3'
|
8
|
-
require 'bolt/error'
|
9
|
-
require 'bolt/task'
|
10
|
-
require 'bolt/apply_result'
|
11
|
-
require 'bolt/apply_target'
|
12
|
-
require 'bolt/util/puppet_log_level'
|
13
14
|
|
14
15
|
module Bolt
|
15
16
|
class Applicator
|
16
|
-
def initialize(inventory, executor, modulepath, plugin_dirs, pdb_client, hiera_config, max_compiles)
|
17
|
+
def initialize(inventory, executor, modulepath, plugin_dirs, pdb_client, hiera_config, max_compiles, apply_settings)
|
17
18
|
# lazy-load expensive gem code
|
18
19
|
require 'concurrent'
|
19
20
|
|
@@ -23,6 +24,7 @@ module Bolt
|
|
23
24
|
@plugin_dirs = plugin_dirs
|
24
25
|
@pdb_client = pdb_client
|
25
26
|
@hiera_config = hiera_config ? validate_hiera_config(hiera_config) : nil
|
27
|
+
@apply_settings = apply_settings || {}
|
26
28
|
|
27
29
|
@pool = Concurrent::ThreadPoolExecutor.new(max_threads: max_compiles)
|
28
30
|
@logger = Logging.logger[self]
|
@@ -50,7 +52,7 @@ module Bolt
|
|
50
52
|
{ 'name' => 'custom_facts.rb' },
|
51
53
|
{ 'name' => 'custom_facts.rb', 'remote' => true }
|
52
54
|
] }
|
53
|
-
Bolt::Task.new(
|
55
|
+
Bolt::Task.new('apply_helpers::custom_facts', metadata, [file])
|
54
56
|
end
|
55
57
|
end
|
56
58
|
|
@@ -63,7 +65,7 @@ module Bolt
|
|
63
65
|
{ 'name' => 'apply_catalog.rb' },
|
64
66
|
{ 'name' => 'apply_catalog.rb', 'remote' => true }
|
65
67
|
] }
|
66
|
-
Bolt::Task.new(
|
68
|
+
Bolt::Task.new('apply_helpers::apply_catalog', metadata, [file])
|
67
69
|
end
|
68
70
|
end
|
69
71
|
|
@@ -77,7 +79,7 @@ module Bolt
|
|
77
79
|
{ 'name' => 'query_resources.rb', 'remote' => true }
|
78
80
|
] }
|
79
81
|
|
80
|
-
Bolt::Task.new(
|
82
|
+
Bolt::Task.new('apply_helpers::query_resources', metadata, [file])
|
81
83
|
end
|
82
84
|
end
|
83
85
|
|
@@ -250,7 +252,9 @@ module Bolt
|
|
250
252
|
end
|
251
253
|
# rubocop:enable Style/GlobalVars
|
252
254
|
|
253
|
-
|
255
|
+
description = options[:description] || 'apply catalog'
|
256
|
+
|
257
|
+
r = @executor.log_action(description, targets) do
|
254
258
|
futures = targets.map do |target|
|
255
259
|
Concurrent::Future.execute(executor: @pool) do
|
256
260
|
@executor.with_node_logging("Compiling manifest block", [target]) do
|
@@ -270,6 +274,7 @@ module Bolt
|
|
270
274
|
arguments = {
|
271
275
|
'catalog' => Puppet::Pops::Types::PSensitiveType::Sensitive.new(catalog),
|
272
276
|
'plugins' => Puppet::Pops::Types::PSensitiveType::Sensitive.new(plugins),
|
277
|
+
'apply_settings' => @apply_settings,
|
273
278
|
'_task' => catalog_apply_task.name,
|
274
279
|
'_noop' => options[:noop]
|
275
280
|
}
|
@@ -127,7 +127,7 @@ module Bolt
|
|
127
127
|
when 'task'
|
128
128
|
case action
|
129
129
|
when 'run'
|
130
|
-
{ flags: ACTION_OPTS + %w[params tmpdir],
|
130
|
+
{ flags: ACTION_OPTS + %w[params tmpdir noop],
|
131
131
|
banner: TASK_RUN_HELP }
|
132
132
|
when 'show'
|
133
133
|
{ flags: OPTIONS[:global] + OPTIONS[:global_config_setters],
|
@@ -627,7 +627,7 @@ module Bolt
|
|
627
627
|
"'success' nodes that succeeded in the last run.") do |rerun|
|
628
628
|
@options[:rerun] = rerun
|
629
629
|
end
|
630
|
-
define('--noop', '
|
630
|
+
define('--noop', 'See what changes Bolt will make without actually executing the changes') do |_|
|
631
631
|
@options[:noop] = true
|
632
632
|
end
|
633
633
|
define('--description DESCRIPTION',
|
data/lib/bolt/cli.rb
CHANGED
@@ -132,6 +132,9 @@ module Bolt
|
|
132
132
|
# Logger must be configured before checking path case, otherwise warnings will not display
|
133
133
|
@config.check_path_case('modulepath', @config.modulepath)
|
134
134
|
|
135
|
+
# Log the file paths for loaded config files
|
136
|
+
config_loaded
|
137
|
+
|
135
138
|
parser.warnings.each { |warning| @logger.warn(warning[:msg]) }
|
136
139
|
# After validation, initialize inventory and targets. Errors here are better to catch early.
|
137
140
|
# After this step
|
@@ -448,7 +451,7 @@ module Bolt
|
|
448
451
|
end
|
449
452
|
|
450
453
|
def show_task(task_name)
|
451
|
-
outputter.print_task_info(pal.
|
454
|
+
outputter.print_task_info(pal.get_task(task_name))
|
452
455
|
end
|
453
456
|
|
454
457
|
def list_tasks
|
@@ -665,7 +668,8 @@ module Bolt
|
|
665
668
|
config.hiera_config,
|
666
669
|
config.boltdir.resource_types,
|
667
670
|
config.compile_concurrency,
|
668
|
-
config.trusted_external
|
671
|
+
config.trusted_external,
|
672
|
+
config.apply_settings)
|
669
673
|
end
|
670
674
|
|
671
675
|
def convert_plan(plan)
|
@@ -717,5 +721,12 @@ module Bolt
|
|
717
721
|
|
718
722
|
content
|
719
723
|
end
|
724
|
+
|
725
|
+
def config_loaded
|
726
|
+
msg = <<~MSG
|
727
|
+
Loaded configuration from: '#{config.config_files.join("', '")}'
|
728
|
+
MSG
|
729
|
+
@logger.debug(msg)
|
730
|
+
end
|
720
731
|
end
|
721
732
|
end
|
data/lib/bolt/config.rb
CHANGED
@@ -34,22 +34,18 @@ module Bolt
|
|
34
34
|
class Config
|
35
35
|
attr_accessor :concurrency, :format, :trace, :log, :puppetdb, :color, :save_rerun,
|
36
36
|
:transport, :transports, :inventoryfile, :compile_concurrency, :boltdir,
|
37
|
-
:puppetfile_config, :plugins, :plugin_hooks, :future, :trusted_external
|
37
|
+
:puppetfile_config, :plugins, :plugin_hooks, :future, :trusted_external,
|
38
|
+
:apply_settings
|
38
39
|
attr_writer :modulepath
|
40
|
+
attr_reader :config_files
|
39
41
|
|
40
42
|
OPTIONS = {
|
43
|
+
"apply_settings" => "A map of Puppet settings to use when applying Puppet code",
|
41
44
|
"color" => "Whether to use colored output when printing messages to the console.",
|
42
45
|
"compile-concurrency" => "The maximum number of simultaneous manifest block compiles.",
|
43
46
|
"concurrency" => "The number of threads to use when executing on remote targets.",
|
44
47
|
"format" => "The format to use when printing results. Options are `human` and `json`.",
|
45
48
|
"hiera-config" => "The path to your Hiera config.",
|
46
|
-
"interpreters" => "A map of an extension name to the absolute path of an executable, "\
|
47
|
-
"enabling you to override the shebang defined in a task executable. The "\
|
48
|
-
"extension can optionally be specified with the `.` character (`.py` and "\
|
49
|
-
"`py` both map to a task executable `task.py`) and the extension is case "\
|
50
|
-
"sensitive. The transports that support interpreter configuration are "\
|
51
|
-
"`docker`, `local`, `ssh`, and `winrm`. When a target's name is `localhost`, "\
|
52
|
-
"Ruby tasks run with the Bolt Ruby interpreter by default.",
|
53
49
|
"inventoryfile" => "The path to a structured data inventory file used to refer to groups of "\
|
54
50
|
"targets on the command line and from plans.",
|
55
51
|
"log" => "The configuration of the logfile output. Configuration can be set for "\
|
@@ -58,6 +54,8 @@ module Bolt
|
|
58
54
|
"of directories or a string containing a list of directories separated by the "\
|
59
55
|
"OS-specific PATH separator.",
|
60
56
|
"plugin_hooks" => "Which plugins a specific hook should use.",
|
57
|
+
"plugins" => "A map of plugins and their configuration data.",
|
58
|
+
"puppetdb" => "A map containing options for configuring the Bolt PuppetDB client.",
|
61
59
|
"puppetfile" => "A map containing options for the `bolt puppetfile install` command.",
|
62
60
|
"save-rerun" => "Whether to update `.rerun.json` in the Bolt project directory. If "\
|
63
61
|
"your target names include passwords, set this value to `false` to avoid "\
|
@@ -101,23 +99,64 @@ module Bolt
|
|
101
99
|
"level" => "`warn` for console, `notice` for file"
|
102
100
|
}.freeze
|
103
101
|
|
102
|
+
APPLY_SETTINGS = {
|
103
|
+
"show_diff" => "Whether to log and report a contextual diff when files are being replaced. "\
|
104
|
+
"See [Puppet documentation](https://puppet.com/docs/puppet/latest/configuration.html#showdiff) "\
|
105
|
+
"for details"
|
106
|
+
}.freeze
|
107
|
+
|
108
|
+
DEFAULT_APPLY_SETTINGS = {
|
109
|
+
"show_diff" => false
|
110
|
+
}.freeze
|
111
|
+
|
104
112
|
def self.default
|
105
113
|
new(Bolt::Boltdir.new('.'), {})
|
106
114
|
end
|
107
115
|
|
108
116
|
def self.from_boltdir(boltdir, overrides = {})
|
109
|
-
data =
|
117
|
+
data = {
|
118
|
+
filepath: boltdir.config_file,
|
119
|
+
data: Bolt::Util.read_config_file(nil, [boltdir.config_file], 'config')
|
120
|
+
}
|
121
|
+
|
122
|
+
data = load_defaults.push(data).select { |config| config[:data]&.any? }
|
123
|
+
|
110
124
|
new(boltdir, data, overrides)
|
111
125
|
end
|
112
126
|
|
113
127
|
def self.from_file(configfile, overrides = {})
|
114
128
|
boltdir = Bolt::Boltdir.new(Pathname.new(configfile).expand_path.dirname)
|
115
|
-
|
129
|
+
|
130
|
+
data = {
|
131
|
+
filepath: boltdir.config_file,
|
132
|
+
data: Bolt::Util.read_config_file(configfile, [], 'config')
|
133
|
+
}
|
134
|
+
|
135
|
+
data = load_defaults.push(data).select { |config| config[:data]&.any? }
|
116
136
|
|
117
137
|
new(boltdir, data, overrides)
|
118
138
|
end
|
119
139
|
|
140
|
+
def self.load_defaults
|
141
|
+
# Lazy-load expensive gem code
|
142
|
+
require 'win32/dir' if Bolt::Util.windows?
|
143
|
+
|
144
|
+
system_path = if Bolt::Util.windows?
|
145
|
+
Pathname.new(File.join(Dir::COMMON_APPDATA, 'PuppetLabs', 'bolt', 'etc', 'bolt.yaml'))
|
146
|
+
else
|
147
|
+
Pathname.new(File.join('/etc', 'puppetlabs', 'bolt', 'bolt.yaml'))
|
148
|
+
end
|
149
|
+
user_path = Pathname.new(File.expand_path(File.join('~', '.puppetlabs', 'etc', 'bolt', 'bolt.yaml')))
|
150
|
+
|
151
|
+
[{ filepath: system_path, data: Bolt::Util.read_config_file(nil, [system_path], 'config') },
|
152
|
+
{ filepath: user_path, data: Bolt::Util.read_config_file(nil, [user_path], 'config') }]
|
153
|
+
end
|
154
|
+
|
120
155
|
def initialize(boltdir, config_data, overrides = {})
|
156
|
+
unless config_data.is_a?(Array)
|
157
|
+
config_data = [{ filepath: boltdir.config_file, data: config_data }]
|
158
|
+
end
|
159
|
+
|
121
160
|
@logger = Logging.logger[self]
|
122
161
|
|
123
162
|
@boltdir = boltdir
|
@@ -131,6 +170,7 @@ module Bolt
|
|
131
170
|
@puppetfile_config = {}
|
132
171
|
@plugins = {}
|
133
172
|
@plugin_hooks = {}
|
173
|
+
@apply_settings = {}
|
134
174
|
|
135
175
|
# add an entry for the default console logger
|
136
176
|
@log = { 'console' => {} }
|
@@ -141,12 +181,39 @@ module Bolt
|
|
141
181
|
@transports[key] = transport.default_options
|
142
182
|
end
|
143
183
|
|
184
|
+
@config_files = config_data.map { |config| config[:filepath] }
|
185
|
+
|
186
|
+
config_data = merge_config_data(config_data)
|
144
187
|
update_from_file(config_data)
|
188
|
+
|
145
189
|
apply_overrides(overrides)
|
146
190
|
|
147
191
|
validate
|
148
192
|
end
|
149
193
|
|
194
|
+
# Merge configuration
|
195
|
+
# Precedence from highest to lowest is: project, user-level, system-wide
|
196
|
+
def merge_config_data(config_data)
|
197
|
+
config_data.inject({}) do |acc, config|
|
198
|
+
acc.merge(config[:data]) do |key, val1, val2|
|
199
|
+
case key
|
200
|
+
# Plugin config is shallow merged for each plugin
|
201
|
+
when 'plugins'
|
202
|
+
val1.merge(val2) { |_, v1, v2| v1.merge(v2) }
|
203
|
+
# Transports are deep merged
|
204
|
+
when *TRANSPORTS.keys.map(&:to_s)
|
205
|
+
Bolt::Util.deep_merge(val1, val2)
|
206
|
+
# Hash values are shallow mergeed
|
207
|
+
when 'puppetdb', 'plugin_hooks', 'apply_settings', 'log'
|
208
|
+
val1.merge(val2)
|
209
|
+
# All other values are overwritten
|
210
|
+
else
|
211
|
+
val2
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
150
217
|
def overwrite_transport_data(transport, transports)
|
151
218
|
@transport = transport
|
152
219
|
@transports = transports
|
@@ -224,14 +291,16 @@ module Bolt
|
|
224
291
|
@trusted_external = if data.key?('trusted-external-command')
|
225
292
|
File.expand_path(data['trusted-external-command'], @boltdir.path)
|
226
293
|
end
|
294
|
+
|
295
|
+
if data.key?('apply_settings')
|
296
|
+
@apply_settings = data['apply_settings'].select { |k, _| APPLY_SETTINGS.keys.include?(k) }
|
297
|
+
end
|
298
|
+
|
227
299
|
@compile_concurrency = data['compile-concurrency'] if data.key?('compile-concurrency')
|
228
300
|
|
229
301
|
@save_rerun = data['save-rerun'] if data.key?('save-rerun')
|
230
302
|
|
231
|
-
|
232
|
-
@plugin_hooks = data['plugin_hooks'] if data.key?('plugin_hooks')
|
233
|
-
|
234
|
-
%w[concurrency format puppetdb color].each do |key|
|
303
|
+
%w[concurrency format puppetdb color plugins plugin_hooks].each do |key|
|
235
304
|
send("#{key}=", data[key]) if data.key?(key)
|
236
305
|
end
|
237
306
|
|
data/lib/bolt/outputter/human.rb
CHANGED
@@ -222,9 +222,9 @@ module Bolt
|
|
222
222
|
# Building lots of strings...
|
223
223
|
pretty_params = +""
|
224
224
|
task_info = +""
|
225
|
-
usage = +"bolt task run --targets <node-name> #{task
|
225
|
+
usage = +"bolt task run --targets <node-name> #{task.name}"
|
226
226
|
|
227
|
-
task
|
227
|
+
task.parameters&.each do |k, v|
|
228
228
|
pretty_params << "- #{k}: #{v['type'] || 'Any'}\n"
|
229
229
|
pretty_params << " Default: #{v['default'].inspect}\n" if v.key?('default')
|
230
230
|
pretty_params << " #{v['description']}\n" if v['description']
|
@@ -235,16 +235,16 @@ module Bolt
|
|
235
235
|
end
|
236
236
|
end
|
237
237
|
|
238
|
-
usage << " [--noop]" if task
|
238
|
+
usage << " [--noop]" if task.supports_noop
|
239
239
|
|
240
|
-
task_info << "\n#{task
|
241
|
-
task_info << " - #{task
|
240
|
+
task_info << "\n#{task.name}"
|
241
|
+
task_info << " - #{task.description}" if task.description
|
242
242
|
task_info << "\n\n"
|
243
243
|
task_info << "USAGE:\n#{usage}\n\n"
|
244
244
|
task_info << "PARAMETERS:\n#{pretty_params}\n" unless pretty_params.empty?
|
245
245
|
task_info << "MODULE:\n"
|
246
246
|
|
247
|
-
path = task
|
247
|
+
path = task.files.first['path'].chomp("/tasks/#{task.files.first['name']}")
|
248
248
|
task_info << if path.start_with?(Bolt::PAL::MODULES_PATH)
|
249
249
|
"built-in module"
|
250
250
|
else
|
data/lib/bolt/outputter/json.rb
CHANGED
@@ -55,13 +55,13 @@ module Bolt
|
|
55
55
|
alias print_module_list print_table
|
56
56
|
|
57
57
|
def print_task_info(task)
|
58
|
-
path = task
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
@stream.puts task.to_json
|
58
|
+
path = task.files.first['path'].chomp("/tasks/#{task.files.first['name']}")
|
59
|
+
module_dir = if path.start_with?(Bolt::PAL::MODULES_PATH)
|
60
|
+
"built-in module"
|
61
|
+
else
|
62
|
+
path
|
63
|
+
end
|
64
|
+
@stream.puts task.to_h.merge(module_dir: module_dir).to_json
|
65
65
|
end
|
66
66
|
|
67
67
|
def print_tasks(tasks, modulepath)
|
data/lib/bolt/pal.rb
CHANGED
@@ -39,7 +39,8 @@ module Bolt
|
|
39
39
|
|
40
40
|
attr_reader :modulepath
|
41
41
|
|
42
|
-
def initialize(modulepath, hiera_config, resource_types, max_compiles = Etc.nprocessors,
|
42
|
+
def initialize(modulepath, hiera_config, resource_types, max_compiles = Etc.nprocessors,
|
43
|
+
trusted_external = nil, apply_settings = {})
|
43
44
|
# Nothing works without initialized this global state. Reinitializing
|
44
45
|
# is safe and in practice only happens in tests
|
45
46
|
self.class.load_puppet
|
@@ -48,6 +49,7 @@ module Bolt
|
|
48
49
|
@modulepath = [BOLTLIB_PATH, *modulepath, MODULES_PATH]
|
49
50
|
@hiera_config = hiera_config
|
50
51
|
@trusted_external = trusted_external
|
52
|
+
@apply_settings = apply_settings
|
51
53
|
@max_compiles = max_compiles
|
52
54
|
@resource_types = resource_types
|
53
55
|
|
@@ -175,7 +177,8 @@ module Bolt
|
|
175
177
|
@original_modulepath,
|
176
178
|
pdb_client,
|
177
179
|
@hiera_config,
|
178
|
-
@max_compiles
|
180
|
+
@max_compiles,
|
181
|
+
@apply_settings
|
179
182
|
)
|
180
183
|
}
|
181
184
|
Puppet.override(opts, &block)
|
@@ -280,14 +283,14 @@ module Bolt
|
|
280
283
|
end
|
281
284
|
end
|
282
285
|
|
283
|
-
def
|
286
|
+
def get_task(task_name)
|
284
287
|
task = task_signature(task_name)
|
285
288
|
|
286
289
|
if task.nil?
|
287
290
|
raise Bolt::Error.unknown_task(task_name)
|
288
291
|
end
|
289
292
|
|
290
|
-
task
|
293
|
+
Bolt::Task.from_task_signature(task)
|
291
294
|
end
|
292
295
|
|
293
296
|
def list_plans
|
data/lib/bolt/plugin.rb
CHANGED
@@ -83,7 +83,7 @@ module Bolt
|
|
83
83
|
raise Bolt::Error.unknown_task(task_name) unless tasksig
|
84
84
|
|
85
85
|
Bolt::Task::Run.validate_params(tasksig, params) if params
|
86
|
-
Bolt::Task.
|
86
|
+
Bolt::Task.from_task_signature(tasksig)
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
@@ -142,8 +142,8 @@ module Bolt
|
|
142
142
|
plugins
|
143
143
|
end
|
144
144
|
|
145
|
-
RUBY_PLUGINS = %w[task pkcs7 prompt].freeze
|
146
|
-
BUILTIN_PLUGINS = %w[task terraform pkcs7 prompt vault aws_inventory puppetdb azure_inventory yaml].freeze
|
145
|
+
RUBY_PLUGINS = %w[task pkcs7 prompt env_var].freeze
|
146
|
+
BUILTIN_PLUGINS = %w[task terraform pkcs7 prompt vault aws_inventory puppetdb azure_inventory yaml env_var].freeze
|
147
147
|
DEFAULT_PLUGIN_HOOKS = { 'puppet_library' => { 'plugin' => 'puppet_agent', 'stop_service' => true } }.freeze
|
148
148
|
|
149
149
|
attr_reader :pal, :plugin_context
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bolt
|
4
|
+
class Plugin
|
5
|
+
class EnvVar
|
6
|
+
def initialize(*_args); end
|
7
|
+
|
8
|
+
def name
|
9
|
+
'env_var'
|
10
|
+
end
|
11
|
+
|
12
|
+
def hooks
|
13
|
+
%i[resolve_reference validate_resolve_reference]
|
14
|
+
end
|
15
|
+
|
16
|
+
def validate_resolve_reference(opts)
|
17
|
+
unless opts['var']
|
18
|
+
raise Bolt::ValidationError, "env_var plugin requires that the 'var' is specified"
|
19
|
+
end
|
20
|
+
unless ENV[opts['var']]
|
21
|
+
raise Bolt::ValidationError, "env_var plugin requires that the var '#{opts['var']}' be set"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def resolve_reference(opts)
|
26
|
+
ENV[opts['var']]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/bolt/plugin/prompt.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'concurrent/delay'
|
4
3
|
module Bolt
|
5
4
|
class Plugin
|
6
5
|
class Prompt
|
@@ -11,7 +10,7 @@ module Bolt
|
|
11
10
|
end
|
12
11
|
|
13
12
|
def hooks
|
14
|
-
[
|
13
|
+
%i[resolve_reference validate_resolve_reference]
|
15
14
|
end
|
16
15
|
|
17
16
|
def validate_resolve_reference(opts)
|
data/lib/bolt/task.rb
CHANGED
@@ -8,30 +8,33 @@ module Bolt
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
def initialize(task, remote: false)
|
26
|
-
super(nil, nil, [], {})
|
27
|
-
|
11
|
+
class Task
|
12
|
+
METADATA_KEYS = %w[description extensions files implementations
|
13
|
+
input_method parameters private puppet_task_version
|
14
|
+
remote supports_noop].freeze
|
15
|
+
|
16
|
+
attr_reader :name, :files, :metadata, :remote
|
17
|
+
|
18
|
+
# name [String] name of the task
|
19
|
+
# files [Array<Hash>] where each entry includes `name` and `path`
|
20
|
+
# metadata [Hash] task metadata
|
21
|
+
def initialize(name, metadata = {}, files = [], remote = false)
|
22
|
+
@name = name
|
23
|
+
@metadata = metadata
|
24
|
+
@files = files
|
28
25
|
@remote = remote
|
26
|
+
@logger = Logging.logger[self]
|
27
|
+
|
28
|
+
validate_metadata
|
29
|
+
end
|
29
30
|
|
30
|
-
|
31
|
+
def self.from_task_signature(task_sig)
|
32
|
+
hash = task_sig.task_hash
|
33
|
+
new(hash['name'], hash.fetch('metadata', {}), hash.fetch('files', []))
|
31
34
|
end
|
32
35
|
|
33
36
|
def remote_instance
|
34
|
-
self.class.new(
|
37
|
+
self.class.new(@name, @metadata, @files, true)
|
35
38
|
end
|
36
39
|
|
37
40
|
def description
|
@@ -118,5 +121,33 @@ module Bolt
|
|
118
121
|
|
119
122
|
impl
|
120
123
|
end
|
124
|
+
|
125
|
+
def eql?(other)
|
126
|
+
self.class == other.class &&
|
127
|
+
@name == other.name &&
|
128
|
+
@metadata == other.metadata &&
|
129
|
+
@files == other.files &&
|
130
|
+
@remote == other.remote
|
131
|
+
end
|
132
|
+
|
133
|
+
alias == :eql?
|
134
|
+
|
135
|
+
def to_h
|
136
|
+
{
|
137
|
+
name: @name,
|
138
|
+
files: @files,
|
139
|
+
metadata: @metadata
|
140
|
+
}
|
141
|
+
end
|
142
|
+
|
143
|
+
def validate_metadata
|
144
|
+
unknown_keys = metadata.keys - METADATA_KEYS
|
145
|
+
|
146
|
+
if unknown_keys.any?
|
147
|
+
msg = "Metadata for task '#{@name}' contains unknown keys: #{unknown_keys.join(', ')}."
|
148
|
+
msg += " This could be a typo in the task metadata or may result in incorrect behavior."
|
149
|
+
@logger.warn(msg)
|
150
|
+
end
|
151
|
+
end
|
121
152
|
end
|
122
153
|
end
|
@@ -4,21 +4,18 @@ module Bolt
|
|
4
4
|
class Task
|
5
5
|
class PuppetServer < Bolt::Task
|
6
6
|
def remote_instance
|
7
|
-
self.class.new(
|
8
|
-
@file_cache,
|
9
|
-
remote: true)
|
7
|
+
self.class.new(@name, @metadata, @files, @file_cache, true)
|
10
8
|
end
|
11
9
|
|
12
|
-
def initialize(
|
13
|
-
super(
|
10
|
+
def initialize(name, metadata, files, file_cache, remote = false)
|
11
|
+
super(name, metadata, files, remote)
|
14
12
|
@file_cache = file_cache
|
15
|
-
update_file_data
|
13
|
+
update_file_data
|
16
14
|
end
|
17
15
|
|
18
16
|
# puppetserver file entries have 'filename' rather then 'name'
|
19
|
-
def update_file_data
|
20
|
-
|
21
|
-
task_data
|
17
|
+
def update_file_data
|
18
|
+
@files.each { |f| f['name'] = f['filename'] }
|
22
19
|
end
|
23
20
|
|
24
21
|
def file_path(file_name)
|
data/lib/bolt/version.rb
CHANGED
@@ -101,7 +101,8 @@ module BoltServer
|
|
101
101
|
error = validate_schema(@schemas["action-run_task"], body)
|
102
102
|
return [], error unless error.nil?
|
103
103
|
|
104
|
-
|
104
|
+
task_data = body['task']
|
105
|
+
task = Bolt::Task::PuppetServer.new(task_data['name'], task_data['metadata'], task_data['files'], @file_cache)
|
105
106
|
parameters = body['parameters'] || {}
|
106
107
|
[@executor.run_task(target, task, parameters), nil]
|
107
108
|
end
|
data/libexec/apply_catalog.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bolt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.48.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Puppet
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-02-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -420,6 +420,7 @@ files:
|
|
420
420
|
- lib/bolt/pal/yaml_plan/transpiler.rb
|
421
421
|
- lib/bolt/plan_result.rb
|
422
422
|
- lib/bolt/plugin.rb
|
423
|
+
- lib/bolt/plugin/env_var.rb
|
423
424
|
- lib/bolt/plugin/module.rb
|
424
425
|
- lib/bolt/plugin/pkcs7.rb
|
425
426
|
- lib/bolt/plugin/prompt.rb
|