bolt 2.17.0 → 2.22.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 +3 -1
- data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +20 -9
- data/bolt-modules/boltlib/lib/puppet/functions/download_file.rb +123 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +6 -0
- data/bolt-modules/dir/lib/puppet/functions/dir/children.rb +35 -0
- data/lib/bolt/applicator.rb +19 -14
- data/lib/bolt/apply_result.rb +1 -1
- data/lib/bolt/bolt_option_parser.rb +68 -13
- data/lib/bolt/catalog.rb +12 -3
- data/lib/bolt/cli.rb +232 -47
- data/lib/bolt/config.rb +34 -13
- data/lib/bolt/config/options.rb +16 -1
- data/lib/bolt/config/transport/options.rb +16 -10
- data/lib/bolt/config/transport/ssh.rb +24 -10
- data/lib/bolt/executor.rb +21 -0
- data/lib/bolt/inventory/group.rb +3 -2
- data/lib/bolt/inventory/inventory.rb +4 -3
- data/lib/bolt/logger.rb +21 -0
- data/lib/bolt/module.rb +2 -1
- data/lib/bolt/outputter/rainbow.rb +9 -2
- data/lib/bolt/pal.rb +8 -2
- data/lib/bolt/pal/yaml_plan/evaluator.rb +23 -2
- data/lib/bolt/pal/yaml_plan/step.rb +24 -2
- data/lib/bolt/pal/yaml_plan/step/download.rb +38 -0
- data/lib/bolt/pal/yaml_plan/step/message.rb +30 -0
- data/lib/bolt/pal/yaml_plan/step/upload.rb +3 -3
- data/lib/bolt/plugin/module.rb +2 -4
- data/lib/bolt/plugin/puppetdb.rb +3 -2
- data/lib/bolt/project.rb +25 -11
- data/lib/bolt/puppetdb/client.rb +2 -0
- data/lib/bolt/puppetdb/config.rb +16 -0
- data/lib/bolt/result.rb +7 -0
- data/lib/bolt/shell/bash.rb +24 -4
- data/lib/bolt/shell/powershell.rb +10 -4
- data/lib/bolt/shell/powershell/snippets.rb +15 -6
- data/lib/bolt/transport/base.rb +24 -0
- data/lib/bolt/transport/docker.rb +8 -0
- data/lib/bolt/transport/docker/connection.rb +20 -2
- data/lib/bolt/transport/local/connection.rb +14 -1
- data/lib/bolt/transport/orch.rb +12 -0
- data/lib/bolt/transport/simple.rb +6 -0
- data/lib/bolt/transport/ssh.rb +7 -1
- data/lib/bolt/transport/ssh/connection.rb +9 -1
- data/lib/bolt/transport/ssh/exec_connection.rb +23 -2
- data/lib/bolt/transport/winrm/connection.rb +118 -8
- data/lib/bolt/util.rb +26 -11
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/transport_app.rb +3 -2
- data/lib/bolt_spec/bolt_context.rb +7 -2
- data/lib/bolt_spec/plans.rb +15 -2
- data/lib/bolt_spec/plans/action_stubs.rb +2 -1
- data/lib/bolt_spec/plans/action_stubs/download_stub.rb +66 -0
- data/lib/bolt_spec/plans/mock_executor.rb +14 -1
- data/lib/bolt_spec/run.rb +22 -0
- data/libexec/bolt_catalog +3 -2
- data/modules/secure_env_vars/plans/init.pp +20 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 60e995704052fee2778474c532df844e51ca0888017e28c883866e6b61a9678f
|
4
|
+
data.tar.gz: 8133b33137d67ba8880270f4ed20aa8346e13b2aa7ae2b0c390e3fbbba660172
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a057aebe5bd7ce01a8369f3c7a05371f0dab79143cd465f6bd2f0a0ad23fe897fcff6624d03f07ead07b86c888512166232182c294cd1188fcd8fb45b55f463d
|
7
|
+
data.tar.gz: 4c30348d86636398f25568dcd77af25e6eb8e54af5c9ce44125a110b8089c15415a4a051aa8aac066f7404f9ca7faf253dd69e350780ef8d24e34f385c1dd8de
|
data/Puppetfile
CHANGED
@@ -5,7 +5,7 @@ forge "http://forge.puppetlabs.com"
|
|
5
5
|
moduledir File.join(File.dirname(__FILE__), 'modules')
|
6
6
|
|
7
7
|
# Core modules used by 'apply'
|
8
|
-
mod 'puppetlabs-service', '1.
|
8
|
+
mod 'puppetlabs-service', '1.3.0'
|
9
9
|
mod 'puppetlabs-puppet_agent', '3.2.0'
|
10
10
|
mod 'puppetlabs-facts', '1.0.0'
|
11
11
|
|
@@ -28,6 +28,7 @@ mod 'puppetlabs-python_task_helper', '0.4.3'
|
|
28
28
|
mod 'puppetlabs-reboot', '3.0.0'
|
29
29
|
mod 'puppetlabs-ruby_task_helper', '0.5.1'
|
30
30
|
mod 'puppetlabs-ruby_plugin_helper', '0.1.0'
|
31
|
+
mod 'puppetlabs-stdlib', '6.3.0'
|
31
32
|
|
32
33
|
# Plugin modules
|
33
34
|
mod 'puppetlabs-aws_inventory', '0.5.0'
|
@@ -42,3 +43,4 @@ mod 'puppetlabs-yaml', '0.2.0'
|
|
42
43
|
mod 'canary', local: true
|
43
44
|
mod 'aggregate', local: true
|
44
45
|
mod 'puppetdb_fact', local: true
|
46
|
+
mod 'secure_env_vars', local: true
|
@@ -13,10 +13,13 @@ require 'bolt/task'
|
|
13
13
|
# > **Note:** Not available in apply block
|
14
14
|
Puppet::Functions.create_function(:apply_prep) do
|
15
15
|
# @param targets A pattern or array of patterns identifying a set of targets.
|
16
|
+
# @param options Options hash.
|
17
|
+
# @option options [Array] _required_modules An array of modules to sync to the target.
|
16
18
|
# @example Prepare targets by name.
|
17
19
|
# apply_prep('target1,target2')
|
18
20
|
dispatch :apply_prep do
|
19
21
|
param 'Boltlib::TargetSpec', :targets
|
22
|
+
optional_param 'Hash[String, Data]', :options
|
20
23
|
end
|
21
24
|
|
22
25
|
def script_compiler
|
@@ -60,18 +63,34 @@ Puppet::Functions.create_function(:apply_prep) do
|
|
60
63
|
@executor ||= Puppet.lookup(:bolt_executor)
|
61
64
|
end
|
62
65
|
|
63
|
-
def apply_prep(target_spec)
|
66
|
+
def apply_prep(target_spec, options = {})
|
64
67
|
unless Puppet[:tasks]
|
65
68
|
raise Puppet::ParseErrorWithIssue
|
66
69
|
.from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, action: 'apply_prep')
|
67
70
|
end
|
68
71
|
|
72
|
+
options = options.transform_keys { |k| k.sub(/^_/, '').to_sym }
|
73
|
+
|
69
74
|
applicator = Puppet.lookup(:apply_executor)
|
70
75
|
|
71
76
|
executor.report_function_call(self.class.name)
|
72
77
|
|
73
78
|
targets = inventory.get_targets(target_spec)
|
74
79
|
|
80
|
+
required_modules = options[:required_modules].nil? ? nil : Array(options[:required_modules])
|
81
|
+
if required_modules&.any?
|
82
|
+
Puppet.debug("Syncing only required modules: #{required_modules.join(',')}.")
|
83
|
+
end
|
84
|
+
|
85
|
+
# Gather facts, including custom facts
|
86
|
+
plugins = applicator.build_plugin_tarball do |mod|
|
87
|
+
next unless required_modules.nil? || required_modules.include?(mod.name)
|
88
|
+
search_dirs = []
|
89
|
+
search_dirs << mod.plugins if mod.plugins?
|
90
|
+
search_dirs << mod.pluginfacts if mod.pluginfacts?
|
91
|
+
search_dirs
|
92
|
+
end
|
93
|
+
|
75
94
|
executor.log_action('install puppet and gather facts', targets) do
|
76
95
|
executor.without_default_logging do
|
77
96
|
# Skip targets that include the puppet-agent feature, as we know an agent will be available.
|
@@ -109,14 +128,6 @@ Puppet::Functions.create_function(:apply_prep) do
|
|
109
128
|
need_install_targets.each { |target| set_agent_feature(target) }
|
110
129
|
end
|
111
130
|
|
112
|
-
# Gather facts, including custom facts
|
113
|
-
plugins = applicator.build_plugin_tarball do |mod|
|
114
|
-
search_dirs = []
|
115
|
-
search_dirs << mod.plugins if mod.plugins?
|
116
|
-
search_dirs << mod.pluginfacts if mod.pluginfacts?
|
117
|
-
search_dirs
|
118
|
-
end
|
119
|
-
|
120
131
|
task = applicator.custom_facts_task
|
121
132
|
arguments = { 'plugins' => Puppet::Pops::Types::PSensitiveType::Sensitive.new(plugins) }
|
122
133
|
results = executor.run_task(targets, task, arguments)
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
require 'bolt/error'
|
5
|
+
|
6
|
+
# Downloads the given file or directory from the given set of targets and saves it to a directory
|
7
|
+
# matching the target's name under the given destination directory. Returns the result from each
|
8
|
+
# download. This does nothing if the list of targets is empty.
|
9
|
+
#
|
10
|
+
# > **Note:** Existing content in the destination directory is deleted before downloading from
|
11
|
+
# > the targets.
|
12
|
+
#
|
13
|
+
# > **Note:** Not available in apply block
|
14
|
+
Puppet::Functions.create_function(:download_file, Puppet::Functions::InternalFunction) do
|
15
|
+
# Download a file or directory.
|
16
|
+
# @param source The absolute path to the file or directory on the target(s).
|
17
|
+
# @param destination The relative path to the destination directory on the local system. Expands
|
18
|
+
# relative to `<project>/downloads/`.
|
19
|
+
# @param targets A pattern identifying zero or more targets. See {get_targets} for accepted patterns.
|
20
|
+
# @param options A hash of additional options.
|
21
|
+
# @option options [Boolean] _catch_errors Whether to catch raised errors.
|
22
|
+
# @option options [String] _run_as User to run as using privilege escalation.
|
23
|
+
# @return A list of results, one entry per target, with the path to the downloaded file under the
|
24
|
+
# `path` key.
|
25
|
+
# @example Download a file from multiple Linux targets to a destination directory
|
26
|
+
# download_file('/etc/ssh/ssh_config', '~/Downloads', $targets)
|
27
|
+
# @example Download a directory from multiple Linux targets to a project downloads directory
|
28
|
+
# download_file('/etc/ssh', 'ssh', $targets)
|
29
|
+
# @example Download a file from multiple Linux targets and compare its contents to a local file
|
30
|
+
# $results = download_file($source, $destination, $targets)
|
31
|
+
#
|
32
|
+
# $local_content = file::read($source)
|
33
|
+
#
|
34
|
+
# $mismatched_files = $results.filter |$result| {
|
35
|
+
# $remote_content = file::read($result['path'])
|
36
|
+
# $remote_content == $local_content
|
37
|
+
# }
|
38
|
+
dispatch :download_file do
|
39
|
+
param 'String[1]', :source
|
40
|
+
param 'String[1]', :destination
|
41
|
+
param 'Boltlib::TargetSpec', :targets
|
42
|
+
optional_param 'Hash[String[1], Any]', :options
|
43
|
+
return_type 'ResultSet'
|
44
|
+
end
|
45
|
+
|
46
|
+
# Download a file or directory, logging the provided description.
|
47
|
+
# @param source The absolute path to the file or directory on the target(s).
|
48
|
+
# @param destination The relative path to the destination directory on the local system. Expands
|
49
|
+
# relative to `<project>/downloads/`.
|
50
|
+
# @param targets A pattern identifying zero or more targets. See {get_targets} for accepted patterns.
|
51
|
+
# @param description A description to be output when calling this function.
|
52
|
+
# @param options A hash of additional options.
|
53
|
+
# @option options [Boolean] _catch_errors Whether to catch raised errors.
|
54
|
+
# @option options [String] _run_as User to run as using privilege escalation.
|
55
|
+
# @return A list of results, one entry per target, with the path to the downloaded file under the
|
56
|
+
# `path` key.
|
57
|
+
# @example Download a file from multiple Linux targets to a destination directory
|
58
|
+
# download_file('/etc/ssh/ssh_config', '~/Downloads', $targets, 'Downloading remote SSH config')
|
59
|
+
dispatch :download_file_with_description do
|
60
|
+
param 'String[1]', :source
|
61
|
+
param 'String[1]', :destination
|
62
|
+
param 'Boltlib::TargetSpec', :targets
|
63
|
+
param 'String', :description
|
64
|
+
optional_param 'Hash[String[1], Any]', :options
|
65
|
+
return_type 'ResultSet'
|
66
|
+
end
|
67
|
+
|
68
|
+
def download_file(source, destination, targets, options = {})
|
69
|
+
download_file_with_description(source, destination, targets, nil, options)
|
70
|
+
end
|
71
|
+
|
72
|
+
def download_file_with_description(source, destination, targets, description = nil, options = {})
|
73
|
+
unless Puppet[:tasks]
|
74
|
+
raise Puppet::ParseErrorWithIssue
|
75
|
+
.from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, action: 'download_file')
|
76
|
+
end
|
77
|
+
|
78
|
+
options = options.select { |opt| opt.start_with?('_') }.transform_keys { |k| k.sub(/^_/, '').to_sym }
|
79
|
+
options[:description] = description if description
|
80
|
+
|
81
|
+
executor = Puppet.lookup(:bolt_executor)
|
82
|
+
inventory = Puppet.lookup(:bolt_inventory)
|
83
|
+
|
84
|
+
if (destination = destination.strip).empty?
|
85
|
+
raise Bolt::ValidationError, "Destination cannot be an empty string"
|
86
|
+
end
|
87
|
+
|
88
|
+
if (destination = Pathname.new(destination)).absolute?
|
89
|
+
raise Bolt::ValidationError, "Destination must be a relative path, received absolute path #{destination}"
|
90
|
+
end
|
91
|
+
|
92
|
+
# Prevent path traversal so downloads can't be saved outside of the project downloads directory
|
93
|
+
if (destination.each_filename.to_a & %w[. ..]).any?
|
94
|
+
raise Bolt::ValidationError, "Destination must not include path traversal, received #{destination}"
|
95
|
+
end
|
96
|
+
|
97
|
+
# Paths expand relative to the default downloads directory for the project
|
98
|
+
# e.g. ~/.puppetlabs/bolt/downloads/
|
99
|
+
destination = Puppet.lookup(:bolt_project_data).downloads + destination
|
100
|
+
|
101
|
+
# If the destination directory already exists, delete any existing contents
|
102
|
+
if Dir.exist?(destination)
|
103
|
+
FileUtils.rm_r(Dir.glob(destination + '*'), secure: true)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Send Analytics Report
|
107
|
+
executor.report_function_call(self.class.name)
|
108
|
+
|
109
|
+
# Ensure that that given targets are all Target instances
|
110
|
+
targets = inventory.get_targets(targets)
|
111
|
+
if targets.empty?
|
112
|
+
call_function('debug', "Simulating file download of '#{source}' - no targets given - no action taken")
|
113
|
+
r = Bolt::ResultSet.new([])
|
114
|
+
else
|
115
|
+
r = executor.download_file(targets, source, destination, options)
|
116
|
+
end
|
117
|
+
|
118
|
+
if !r.ok && !options[:catch_errors]
|
119
|
+
raise Bolt::RunFailure.new(r, 'download_file', source)
|
120
|
+
end
|
121
|
+
r
|
122
|
+
end
|
123
|
+
end
|
@@ -11,6 +11,9 @@ Puppet::Functions.create_function(:run_plan, Puppet::Functions::InternalFunction
|
|
11
11
|
# @param args A hash of arguments to the plan. Can also include additional options.
|
12
12
|
# @option args [Boolean] _catch_errors Whether to catch raised errors.
|
13
13
|
# @option args [String] _run_as User to run as using privilege escalation.
|
14
|
+
# This option sets the [run-as user](privilege_escalation.md) for all
|
15
|
+
# targets whenever Bolt connects to a target. This is set for all functions
|
16
|
+
# in the called plan, including `run_plan()`.
|
14
17
|
# @return [PlanResult] The result of running the plan. Undef if plan does not explicitly return results.
|
15
18
|
# @example Run a plan
|
16
19
|
# run_plan('canary', 'command' => 'false', 'targets' => $targets, '_catch_errors' => true)
|
@@ -31,6 +34,9 @@ Puppet::Functions.create_function(:run_plan, Puppet::Functions::InternalFunction
|
|
31
34
|
# @param args A hash of arguments to the plan. Can also include additional options.
|
32
35
|
# @option args [Boolean] _catch_errors Whether to catch raised errors.
|
33
36
|
# @option args [String] _run_as User to run as using privilege escalation.
|
37
|
+
# This option sets the [run-as user](privilege_escalation.md) for all
|
38
|
+
# targets whenever Bolt connects to a target. This is set for all functions
|
39
|
+
# in the called plan, including `run_plan()`.
|
34
40
|
# @return [PlanResult] The result of running the plan. Undef if plan does not explicitly return results.
|
35
41
|
# @example Run a plan
|
36
42
|
# run_plan('canary', $targets, 'command' => 'false')
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
# Returns an array containing all of the filenames except for "." and ".." in the given directory.
|
6
|
+
Puppet::Functions.create_function(:'dir::children', Puppet::Functions::InternalFunction) do
|
7
|
+
# @param dirname Absolute path or Puppet module name.
|
8
|
+
# @return Array of files in the given directory.
|
9
|
+
# @example List filenames from an absolute path.
|
10
|
+
# dir::children('/home/user/subdir/')
|
11
|
+
# @example List filenames from a Puppet file path.
|
12
|
+
# dir::children('puppet_agent')
|
13
|
+
dispatch :children do
|
14
|
+
scope_param
|
15
|
+
required_param 'String', :dirname
|
16
|
+
return_type 'Array'
|
17
|
+
end
|
18
|
+
|
19
|
+
def children(scope, dirname)
|
20
|
+
# Send Analytics Report
|
21
|
+
Puppet.lookup(:bolt_executor) {}&.report_function_call(self.class.name)
|
22
|
+
modname, subpath = dirname.split(File::SEPARATOR, 2)
|
23
|
+
mod_path = scope.compiler.environment.module(modname)&.path
|
24
|
+
|
25
|
+
full_mod_path = File.join(mod_path, subpath || '') if mod_path
|
26
|
+
|
27
|
+
# Expand relative to the project directory if path is relative
|
28
|
+
project = Puppet.lookup(:bolt_project_data)
|
29
|
+
pathname = Pathname.new(dirname)
|
30
|
+
full_dir = pathname.absolute? ? dirname : File.expand_path(File.join(project.path, dirname))
|
31
|
+
|
32
|
+
# Sort for testability
|
33
|
+
Dir.children(full_mod_path || full_dir).sort
|
34
|
+
end
|
35
|
+
end
|
data/lib/bolt/applicator.rb
CHANGED
@@ -18,7 +18,6 @@ module Bolt
|
|
18
18
|
pdb_client, hiera_config, max_compiles, apply_settings)
|
19
19
|
# lazy-load expensive gem code
|
20
20
|
require 'concurrent'
|
21
|
-
|
22
21
|
@inventory = inventory
|
23
22
|
@executor = executor
|
24
23
|
@modulepath = modulepath || []
|
@@ -30,17 +29,6 @@ module Bolt
|
|
30
29
|
|
31
30
|
@pool = Concurrent::ThreadPoolExecutor.new(max_threads: max_compiles)
|
32
31
|
@logger = Logging.logger[self]
|
33
|
-
@plugin_tarball = Concurrent::Delay.new do
|
34
|
-
build_plugin_tarball do |mod|
|
35
|
-
search_dirs = []
|
36
|
-
search_dirs << mod.plugins if mod.plugins?
|
37
|
-
search_dirs << mod.pluginfacts if mod.pluginfacts?
|
38
|
-
search_dirs << mod.files if mod.files?
|
39
|
-
type_files = "#{mod.path}/types"
|
40
|
-
search_dirs << type_files if File.exist?(type_files)
|
41
|
-
search_dirs
|
42
|
-
end
|
43
|
-
end
|
44
32
|
end
|
45
33
|
|
46
34
|
private def libexec
|
@@ -188,7 +176,6 @@ module Bolt
|
|
188
176
|
|
189
177
|
def apply_ast(raw_ast, targets, options, plan_vars = {})
|
190
178
|
ast = Puppet::Pops::Serialization::ToDataConverter.convert(raw_ast, rich_data: true, symbol_to_string: true)
|
191
|
-
|
192
179
|
# Serialize as pcore for *Result* objects
|
193
180
|
plan_vars = Puppet::Pops::Serialization::ToDataConverter.convert(plan_vars,
|
194
181
|
rich_data: true,
|
@@ -207,9 +194,26 @@ module Bolt
|
|
207
194
|
# This data isn't available on the target config hash
|
208
195
|
config: @inventory.transport_data_get
|
209
196
|
}
|
210
|
-
|
211
197
|
description = options[:description] || 'apply catalog'
|
212
198
|
|
199
|
+
required_modules = options[:required_modules].nil? ? nil : Array(options[:required_modules])
|
200
|
+
if required_modules&.any?
|
201
|
+
@logger.debug("Syncing only required modules: #{required_modules.join(',')}.")
|
202
|
+
end
|
203
|
+
|
204
|
+
@plugin_tarball = Concurrent::Delay.new do
|
205
|
+
build_plugin_tarball do |mod|
|
206
|
+
next unless required_modules.nil? || required_modules.include?(mod.name)
|
207
|
+
search_dirs = []
|
208
|
+
search_dirs << mod.plugins if mod.plugins?
|
209
|
+
search_dirs << mod.pluginfacts if mod.pluginfacts?
|
210
|
+
search_dirs << mod.files if mod.files?
|
211
|
+
type_files = "#{mod.path}/types"
|
212
|
+
search_dirs << type_files if File.exist?(type_files)
|
213
|
+
search_dirs
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
213
217
|
r = @executor.log_action(description, targets) do
|
214
218
|
futures = targets.map do |target|
|
215
219
|
Concurrent::Future.execute(executor: @pool) do
|
@@ -236,6 +240,7 @@ module Bolt
|
|
236
240
|
result
|
237
241
|
end
|
238
242
|
else
|
243
|
+
|
239
244
|
arguments = {
|
240
245
|
'catalog' => Puppet::Pops::Types::PSensitiveType::Sensitive.new(catalog),
|
241
246
|
'plugins' => Puppet::Pops::Types::PSensitiveType::Sensitive.new(plugins),
|
data/lib/bolt/apply_result.rb
CHANGED
@@ -20,7 +20,7 @@ module Bolt
|
|
20
20
|
error_hash['msg'] =~ /The term 'ruby.exe' is not recognized as the name of a cmdlet/)
|
21
21
|
# Windows does not have Ruby present
|
22
22
|
{
|
23
|
-
'msg' => "Puppet
|
23
|
+
'msg' => "Puppet was not found on the target or in $env:ProgramFiles, please install it to enable 'apply'",
|
24
24
|
'kind' => 'bolt/apply-error'
|
25
25
|
}
|
26
26
|
elsif exit_code == 1 && error_hash['msg'] =~ /cannot load such file -- puppet \(LoadError\)/
|
@@ -11,7 +11,7 @@ module Bolt
|
|
11
11
|
escalation: %w[run-as sudo-password sudo-password-prompt sudo-executable],
|
12
12
|
run_context: %w[concurrency inventoryfile save-rerun cleanup],
|
13
13
|
global_config_setters: %w[modulepath project configfile],
|
14
|
-
transports: %w[transport connect-timeout tty ssh-command copy-command],
|
14
|
+
transports: %w[transport connect-timeout tty native-ssh ssh-command copy-command],
|
15
15
|
display: %w[format color verbose trace],
|
16
16
|
global: %w[help version debug log-level] }.freeze
|
17
17
|
|
@@ -25,7 +25,7 @@ module Bolt
|
|
25
25
|
when 'command'
|
26
26
|
case action
|
27
27
|
when 'run'
|
28
|
-
{ flags: ACTION_OPTS,
|
28
|
+
{ flags: ACTION_OPTS + %w[env-var],
|
29
29
|
banner: COMMAND_RUN_HELP }
|
30
30
|
else
|
31
31
|
{ flags: OPTIONS[:global],
|
@@ -36,6 +36,9 @@ module Bolt
|
|
36
36
|
when 'upload'
|
37
37
|
{ flags: ACTION_OPTS + %w[tmpdir],
|
38
38
|
banner: FILE_UPLOAD_HELP }
|
39
|
+
when 'download'
|
40
|
+
{ flags: ACTION_OPTS,
|
41
|
+
banner: FILE_DOWNLOAD_HELP }
|
39
42
|
else
|
40
43
|
{ flags: OPTIONS[:global],
|
41
44
|
banner: FILE_HELP }
|
@@ -63,6 +66,9 @@ module Bolt
|
|
63
66
|
when 'convert'
|
64
67
|
{ flags: OPTIONS[:global] + OPTIONS[:global_config_setters],
|
65
68
|
banner: PLAN_CONVERT_HELP }
|
69
|
+
when 'new'
|
70
|
+
{ flags: OPTIONS[:global] + %w[configfile project],
|
71
|
+
banner: PLAN_NEW_HELP }
|
66
72
|
when 'run'
|
67
73
|
{ flags: ACTION_OPTS + %w[params compile-concurrency tmpdir hiera-config],
|
68
74
|
banner: PLAN_RUN_HELP }
|
@@ -103,7 +109,7 @@ module Bolt
|
|
103
109
|
when 'script'
|
104
110
|
case action
|
105
111
|
when 'run'
|
106
|
-
{ flags: ACTION_OPTS + %w[tmpdir],
|
112
|
+
{ flags: ACTION_OPTS + %w[tmpdir env-var],
|
107
113
|
banner: SCRIPT_RUN_HELP }
|
108
114
|
else
|
109
115
|
{ flags: OPTIONS[:global],
|
@@ -156,10 +162,10 @@ module Bolt
|
|
156
162
|
SUBCOMMANDS
|
157
163
|
apply Apply Puppet manifest code
|
158
164
|
command Run a command remotely
|
159
|
-
file
|
165
|
+
file Copy files between the controller and targets
|
160
166
|
group Show the list of groups in the inventory
|
161
167
|
inventory Show the list of targets an action would run on
|
162
|
-
plan Convert, show, and run Bolt plans
|
168
|
+
plan Convert, create, show, and run Bolt plans
|
163
169
|
project Create and migrate Bolt projects
|
164
170
|
puppetfile Install and list modules and generate type references
|
165
171
|
script Upload a local script and run it remotely
|
@@ -218,10 +224,30 @@ module Bolt
|
|
218
224
|
bolt file <action> [options]
|
219
225
|
|
220
226
|
DESCRIPTION
|
221
|
-
|
227
|
+
Copy files and directories between the controller and targets
|
222
228
|
|
223
229
|
ACTIONS
|
224
|
-
|
230
|
+
download Download a file or directory to the controller
|
231
|
+
upload Upload a local file or directory from the controller
|
232
|
+
HELP
|
233
|
+
|
234
|
+
FILE_DOWNLOAD_HELP = <<~HELP
|
235
|
+
NAME
|
236
|
+
download
|
237
|
+
|
238
|
+
USAGE
|
239
|
+
bolt file download <src> <dest> [options]
|
240
|
+
|
241
|
+
DESCRIPTION
|
242
|
+
Download a file or directory from one or more targets.
|
243
|
+
|
244
|
+
Downloaded files and directories are saved to the a subdirectory
|
245
|
+
matching the target's name under the destination directory. The
|
246
|
+
destination directory is expanded relative to the downloads
|
247
|
+
subdirectory of the project directory.
|
248
|
+
|
249
|
+
EXAMPLES
|
250
|
+
bolt file download /etc/ssh_config ssh_config -t all
|
225
251
|
HELP
|
226
252
|
|
227
253
|
FILE_UPLOAD_HELP = <<~HELP
|
@@ -296,10 +322,11 @@ module Bolt
|
|
296
322
|
bolt plan <action> [parameters] [options]
|
297
323
|
|
298
324
|
DESCRIPTION
|
299
|
-
Convert, show, and run Bolt plans.
|
325
|
+
Convert, create, show, and run Bolt plans.
|
300
326
|
|
301
327
|
ACTIONS
|
302
328
|
convert Convert a YAML plan to a Bolt plan
|
329
|
+
new Create a new plan in the current project
|
303
330
|
run Run a plan on the specified targets
|
304
331
|
show Show available plans and plan documentation
|
305
332
|
HELP
|
@@ -322,6 +349,20 @@ module Bolt
|
|
322
349
|
bolt plan convert path/to/plan/myplan.yaml
|
323
350
|
HELP
|
324
351
|
|
352
|
+
PLAN_NEW_HELP = <<~HELP
|
353
|
+
NAME
|
354
|
+
new
|
355
|
+
|
356
|
+
USAGE
|
357
|
+
bolt plan new <plan> [options]
|
358
|
+
|
359
|
+
DESCRIPTION
|
360
|
+
Create a new plan in the current project.
|
361
|
+
|
362
|
+
EXAMPLES
|
363
|
+
bolt plan new myproject::myplan
|
364
|
+
HELP
|
365
|
+
|
325
366
|
PLAN_RUN_HELP = <<~HELP
|
326
367
|
NAME
|
327
368
|
run
|
@@ -594,13 +635,13 @@ module Bolt
|
|
594
635
|
bolt task show canary
|
595
636
|
HELP
|
596
637
|
|
597
|
-
attr_reader :
|
638
|
+
attr_reader :deprecations
|
598
639
|
|
599
640
|
def initialize(options)
|
600
641
|
super()
|
601
642
|
|
602
643
|
@options = options
|
603
|
-
@
|
644
|
+
@deprecations = []
|
604
645
|
|
605
646
|
separator "\nINVENTORY OPTIONS"
|
606
647
|
define('-t', '--targets TARGETS',
|
@@ -738,16 +779,29 @@ module Bolt
|
|
738
779
|
@options[:'save-rerun'] = save
|
739
780
|
end
|
740
781
|
|
782
|
+
separator "\nREMOTE ENVIRONMENT OPTIONS"
|
783
|
+
define('--env-var ENVIRONMENT_VARIABLES', 'Environment variables to set on the target') do |envvar|
|
784
|
+
unless envvar.include?('=')
|
785
|
+
raise Bolt::CLIError, "Environment variables must be specified using 'myenvvar=key' format"
|
786
|
+
end
|
787
|
+
@options[:env_vars] ||= {}
|
788
|
+
@options[:env_vars].store(*envvar.split('=', 2))
|
789
|
+
end
|
790
|
+
|
741
791
|
separator "\nTRANSPORT OPTIONS"
|
742
792
|
define('--transport TRANSPORT', TRANSPORTS.keys.map(&:to_s),
|
743
793
|
"Specify a default transport: #{TRANSPORTS.keys.join(', ')}") do |t|
|
744
794
|
@options[:transport] = t
|
745
795
|
end
|
746
|
-
define('--ssh
|
796
|
+
define('--[no-]native-ssh', 'Whether to shell out to native SSH or use the net-ssh Ruby library.',
|
797
|
+
'This option is experimental') do |bool|
|
798
|
+
@options[:'native-ssh'] = bool
|
799
|
+
end
|
800
|
+
define('--ssh-command EXEC', "Executable to use instead of the net-ssh Ruby library. ",
|
747
801
|
"This option is experimental.") do |exec|
|
748
802
|
@options[:'ssh-command'] = exec
|
749
803
|
end
|
750
|
-
define('--copy-command EXEC', "Command to copy files to remote hosts if using
|
804
|
+
define('--copy-command EXEC', "Command to copy files to remote hosts if using native SSH. ",
|
751
805
|
"This option is experimental.") do |exec|
|
752
806
|
@options[:'copy-command'] = exec
|
753
807
|
end
|
@@ -805,7 +859,8 @@ module Bolt
|
|
805
859
|
@options[:debug] = true
|
806
860
|
# We don't actually set '--log-level debug' here, but once the options are evaluated by
|
807
861
|
# the config class the end result is the same.
|
808
|
-
|
862
|
+
msg = "Command line option '--debug' is deprecated, set '--log-level debug' instead."
|
863
|
+
@deprecations << { type: 'Using --debug instead of --log-level debug', msg: msg }
|
809
864
|
end
|
810
865
|
define('--log-level LEVEL',
|
811
866
|
"Set the log level for the console. Available options are",
|