bolt 2.19.0 → 2.24.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/download_file.rb +123 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +6 -0
- data/bolt-modules/ctrl/lib/puppet/functions/ctrl/do_until.rb +12 -6
- data/bolt-modules/dir/lib/puppet/functions/dir/children.rb +35 -0
- data/bolt-modules/out/lib/puppet/functions/out/message.rb +1 -1
- data/exe/bolt +1 -0
- data/guides/inventory.txt +19 -0
- data/guides/project.txt +22 -0
- data/lib/bolt/analytics.rb +5 -5
- data/lib/bolt/applicator.rb +4 -3
- data/lib/bolt/bolt_option_parser.rb +100 -27
- data/lib/bolt/catalog.rb +12 -3
- data/lib/bolt/cli.rb +356 -156
- data/lib/bolt/config.rb +2 -2
- data/lib/bolt/config/options.rb +18 -4
- data/lib/bolt/executor.rb +30 -7
- data/lib/bolt/inventory/group.rb +6 -5
- data/lib/bolt/inventory/inventory.rb +4 -3
- data/lib/bolt/logger.rb +3 -4
- data/lib/bolt/module.rb +2 -1
- data/lib/bolt/outputter.rb +56 -0
- data/lib/bolt/outputter/human.rb +10 -9
- data/lib/bolt/outputter/json.rb +11 -4
- data/lib/bolt/outputter/logger.rb +2 -2
- data/lib/bolt/outputter/rainbow.rb +18 -2
- data/lib/bolt/pal.rb +13 -11
- data/lib/bolt/pal/yaml_plan/evaluator.rb +22 -1
- 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/pal/yaml_plan/transpiler.rb +11 -3
- data/lib/bolt/plugin/prompt.rb +3 -3
- data/lib/bolt/plugin/puppetdb.rb +3 -2
- data/lib/bolt/project.rb +7 -4
- data/lib/bolt/project_migrate.rb +138 -0
- 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 +31 -11
- data/lib/bolt/shell/powershell.rb +10 -4
- data/lib/bolt/transport/base.rb +24 -0
- data/lib/bolt/transport/docker.rb +8 -0
- data/lib/bolt/transport/docker/connection.rb +28 -10
- data/lib/bolt/transport/local/connection.rb +15 -2
- data/lib/bolt/transport/orch.rb +15 -3
- data/lib/bolt/transport/simple.rb +6 -0
- data/lib/bolt/transport/ssh/connection.rb +13 -5
- data/lib/bolt/transport/ssh/exec_connection.rb +24 -3
- data/lib/bolt/transport/winrm/connection.rb +125 -15
- data/lib/bolt/util.rb +27 -12
- data/lib/bolt/util/puppet_log_level.rb +4 -3
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/base_config.rb +1 -1
- data/lib/bolt_server/pe/pal.rb +1 -1
- data/lib/bolt_server/transport_app.rb +79 -2
- data/lib/bolt_spec/bolt_context.rb +7 -2
- data/lib/bolt_spec/plans.rb +16 -3
- data/lib/bolt_spec/plans/action_stubs.rb +3 -2
- 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/apply_catalog.rb +2 -2
- data/libexec/bolt_catalog +4 -3
- data/libexec/custom_facts.rb +1 -1
- data/libexec/query_resources.rb +1 -1
- data/modules/secure_env_vars/plans/init.pp +20 -0
- metadata +11 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e572a2c5aec9f127f48764b6a2fe903c91566c8aa0f3a1db33e40347bd1630b
|
4
|
+
data.tar.gz: 1445543fb941e0b8c12ec60900975a45e368a08e593ebe75c87ee946317f57b7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4cdee0a056e3c248a72ea3a4cb1872453611ca241d19ad3c98f5e0e89c550368ab19e34999e121f0e98c5e5cac353fed32eb174fb54fd149bd4558bd84e5706e
|
7
|
+
data.tar.gz: d505e8baf7c6ce5b21c20e27d7979c39c871e5bc69ea7bcf5d898ac94261850afea03028569ed60e192196d215837a2b339fef24231ea9491bc4901e93cba3dd
|
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
|
@@ -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')
|
@@ -4,30 +4,36 @@
|
|
4
4
|
Puppet::Functions.create_function(:'ctrl::do_until') do
|
5
5
|
# @param options A hash of additional options.
|
6
6
|
# @option options [Numeric] limit The number of times to repeat the block.
|
7
|
+
# @option options [Numeric] interval The number of seconds to wait before repeating the block.
|
7
8
|
# @example Run a task until it succeeds
|
8
9
|
# ctrl::do_until() || {
|
9
|
-
# run_task('test', $target, _catch_errors => true).ok()
|
10
|
+
# run_task('test', $target, '_catch_errors' => true).ok()
|
10
11
|
# }
|
11
|
-
#
|
12
12
|
# @example Run a task until it succeeds or fails 10 times
|
13
13
|
# ctrl::do_until('limit' => 10) || {
|
14
|
-
# run_task('test', $target, _catch_errors => true).ok()
|
14
|
+
# run_task('test', $target, '_catch_errors' => true).ok()
|
15
|
+
# }
|
16
|
+
# @example Run a task and wait 10 seconds before running it again
|
17
|
+
# ctrl::do_until('interval' => 10) || {
|
18
|
+
# run_task('test', $target, '_catch_errors' => true).ok()
|
15
19
|
# }
|
16
|
-
#
|
17
20
|
dispatch :do_until do
|
18
21
|
optional_param 'Hash[String[1], Any]', :options
|
19
22
|
block_param
|
20
23
|
end
|
21
24
|
|
22
|
-
def do_until(options = {
|
25
|
+
def do_until(options = {})
|
23
26
|
# Send Analytics Report
|
24
27
|
Puppet.lookup(:bolt_executor) {}&.report_function_call(self.class.name)
|
25
28
|
|
26
|
-
limit = options['limit']
|
29
|
+
limit = options['limit'] || 0
|
30
|
+
interval = options['interval']
|
31
|
+
|
27
32
|
i = 0
|
28
33
|
until (x = yield)
|
29
34
|
i += 1
|
30
35
|
break if limit != 0 && i >= limit
|
36
|
+
Kernel.sleep(interval) if interval
|
31
37
|
end
|
32
38
|
x
|
33
39
|
end
|
@@ -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/exe/bolt
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
TOPIC
|
2
|
+
inventory
|
3
|
+
|
4
|
+
DESCRIPTION
|
5
|
+
The inventory describes the targets that you run Bolt commands on, along
|
6
|
+
with any data and configuration for the targets. Targets in an inventory can
|
7
|
+
belong to one or more groups, allowing you to share data and configuration
|
8
|
+
across multiple targets and to specify multiple targets for your Bolt
|
9
|
+
commands without the need to list each target individually.
|
10
|
+
|
11
|
+
In most cases, Bolt loads the inventory from an inventory file in your Bolt
|
12
|
+
project. The inventory file is a YAML file named 'inventory.yaml'. Because
|
13
|
+
Bolt loads the inventory file from a Bolt project, you must have an existing
|
14
|
+
project configuration file named 'bolt-project.yaml' alongside the inventory
|
15
|
+
file.
|
16
|
+
|
17
|
+
DOCUMENTATION
|
18
|
+
https://pup.pt/bolt-inventory
|
19
|
+
https://pup.pt/bolt-inventory-reference
|
data/guides/project.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
TOPIC
|
2
|
+
project
|
3
|
+
|
4
|
+
DESCRIPTION
|
5
|
+
A Bolt project is a directory that serves as the launching point for Bolt
|
6
|
+
and allows you to create a shareable orchestration application. Projects
|
7
|
+
typically include a project configuration file, an inventory file, and any
|
8
|
+
content you use in your project workflow, such as tasks and plans.
|
9
|
+
|
10
|
+
When you run Bolt, it runs in the context of a project. If the directory you
|
11
|
+
run Bolt from is not a project, Bolt attempts to find a project by
|
12
|
+
traversing the parent directories. If Bolt is unable to find a project, it
|
13
|
+
runs from the default project, located at '~/.puppetlabs/bolt'.
|
14
|
+
|
15
|
+
A directory is only considered a Bolt project when it has a project
|
16
|
+
configuration file named 'bolt-project.yaml'. Bolt doesn't load project data
|
17
|
+
and content, including inventory files, unless the data and content are part
|
18
|
+
of a project.
|
19
|
+
|
20
|
+
DOCUMENTATION
|
21
|
+
https://pup.pt/bolt-projects
|
22
|
+
https://pup.pt/bolt-project-reference
|
data/lib/bolt/analytics.rb
CHANGED
@@ -72,7 +72,7 @@ module Bolt
|
|
72
72
|
|
73
73
|
def self.load_config(filename, logger)
|
74
74
|
if File.exist?(filename)
|
75
|
-
|
75
|
+
Bolt::Util.read_optional_yaml_hash(filename, 'analytics')
|
76
76
|
else
|
77
77
|
unless ENV['BOLT_DISABLE_ANALYTICS']
|
78
78
|
logger.warn <<~ANALYTICS
|
@@ -161,9 +161,9 @@ module Bolt
|
|
161
161
|
# Handle analytics submission in the background to avoid blocking the
|
162
162
|
# app or polluting the log with errors
|
163
163
|
Concurrent::Future.execute(executor: @executor) do
|
164
|
-
@logger.
|
164
|
+
@logger.trace "Submitting analytics: #{JSON.pretty_generate(params)}"
|
165
165
|
@http.post(TRACKING_URL, params)
|
166
|
-
@logger.
|
166
|
+
@logger.trace "Completed analytics submission"
|
167
167
|
end
|
168
168
|
end
|
169
169
|
|
@@ -215,13 +215,13 @@ module Bolt
|
|
215
215
|
end
|
216
216
|
|
217
217
|
def screen_view(screen, **_kwargs)
|
218
|
-
@logger.
|
218
|
+
@logger.trace "Skipping submission of '#{screen}' screenview because analytics is disabled"
|
219
219
|
end
|
220
220
|
|
221
221
|
def report_bundled_content(mode, name); end
|
222
222
|
|
223
223
|
def event(category, action, **_kwargs)
|
224
|
-
@logger.
|
224
|
+
@logger.trace "Skipping submission of '#{category} #{action}' event because analytics is disabled"
|
225
225
|
end
|
226
226
|
|
227
227
|
def finish; end
|
data/lib/bolt/applicator.rb
CHANGED
@@ -27,7 +27,7 @@ module Bolt
|
|
27
27
|
@hiera_config = hiera_config ? validate_hiera_config(hiera_config) : nil
|
28
28
|
@apply_settings = apply_settings || {}
|
29
29
|
|
30
|
-
@pool = Concurrent::ThreadPoolExecutor.new(max_threads: max_compiles)
|
30
|
+
@pool = Concurrent::ThreadPoolExecutor.new(name: 'apply', max_threads: max_compiles)
|
31
31
|
@logger = Logging.logger[self]
|
32
32
|
end
|
33
33
|
|
@@ -217,6 +217,7 @@ module Bolt
|
|
217
217
|
r = @executor.log_action(description, targets) do
|
218
218
|
futures = targets.map do |target|
|
219
219
|
Concurrent::Future.execute(executor: @pool) do
|
220
|
+
Thread.current[:name] ||= Thread.current.name
|
220
221
|
@executor.with_node_logging("Compiling manifest block", [target]) do
|
221
222
|
compile(target, scope)
|
222
223
|
end
|
@@ -300,7 +301,7 @@ module Bolt
|
|
300
301
|
|
301
302
|
files.each do |file|
|
302
303
|
tar_path = Pathname.new(file).relative_path_from(parent)
|
303
|
-
@logger.
|
304
|
+
@logger.trace("Packing plugin #{file} to #{tar_path}")
|
304
305
|
stat = File.stat(file)
|
305
306
|
content = File.binread(file)
|
306
307
|
output.tar.add_file_simple(
|
@@ -314,7 +315,7 @@ module Bolt
|
|
314
315
|
end
|
315
316
|
|
316
317
|
duration = Time.now - start_time
|
317
|
-
@logger.
|
318
|
+
@logger.trace("Packed plugins in #{duration * 1000} ms")
|
318
319
|
|
319
320
|
output.close
|
320
321
|
Base64.encode64(sio.string)
|
@@ -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 }
|
@@ -58,11 +61,17 @@ module Bolt
|
|
58
61
|
{ flags: OPTIONS[:global],
|
59
62
|
banner: GROUP_HELP }
|
60
63
|
end
|
64
|
+
when 'guide'
|
65
|
+
{ flags: OPTIONS[:global] + %w[format],
|
66
|
+
banner: GUIDE_HELP }
|
61
67
|
when 'plan'
|
62
68
|
case action
|
63
69
|
when 'convert'
|
64
70
|
{ flags: OPTIONS[:global] + OPTIONS[:global_config_setters],
|
65
71
|
banner: PLAN_CONVERT_HELP }
|
72
|
+
when 'new'
|
73
|
+
{ flags: OPTIONS[:global] + %w[configfile project],
|
74
|
+
banner: PLAN_NEW_HELP }
|
66
75
|
when 'run'
|
67
76
|
{ flags: ACTION_OPTS + %w[params compile-concurrency tmpdir hiera-config],
|
68
77
|
banner: PLAN_RUN_HELP }
|
@@ -79,7 +88,7 @@ module Bolt
|
|
79
88
|
{ flags: OPTIONS[:global] + %w[modules],
|
80
89
|
banner: PROJECT_INIT_HELP }
|
81
90
|
when 'migrate'
|
82
|
-
{ flags: OPTIONS[:global] + %w[inventoryfile
|
91
|
+
{ flags: OPTIONS[:global] + %w[inventoryfile project configfile],
|
83
92
|
banner: PROJECT_MIGRATE_HELP }
|
84
93
|
else
|
85
94
|
{ flags: OPTIONS[:global],
|
@@ -103,7 +112,7 @@ module Bolt
|
|
103
112
|
when 'script'
|
104
113
|
case action
|
105
114
|
when 'run'
|
106
|
-
{ flags: ACTION_OPTS + %w[tmpdir],
|
115
|
+
{ flags: ACTION_OPTS + %w[tmpdir env-var],
|
107
116
|
banner: SCRIPT_RUN_HELP }
|
108
117
|
else
|
109
118
|
{ flags: OPTIONS[:global],
|
@@ -156,15 +165,19 @@ module Bolt
|
|
156
165
|
SUBCOMMANDS
|
157
166
|
apply Apply Puppet manifest code
|
158
167
|
command Run a command remotely
|
159
|
-
file
|
168
|
+
file Copy files between the controller and targets
|
160
169
|
group Show the list of groups in the inventory
|
170
|
+
guide View guides for Bolt concepts and features
|
161
171
|
inventory Show the list of targets an action would run on
|
162
|
-
plan Convert, show, and run Bolt plans
|
172
|
+
plan Convert, create, show, and run Bolt plans
|
163
173
|
project Create and migrate Bolt projects
|
164
174
|
puppetfile Install and list modules and generate type references
|
165
175
|
script Upload a local script and run it remotely
|
166
176
|
secret Create encryption keys and encrypt and decrypt values
|
167
177
|
task Show and run Bolt tasks
|
178
|
+
|
179
|
+
GUIDES
|
180
|
+
For a list of guides on Bolt's concepts and features, run 'bolt guide'.
|
168
181
|
HELP
|
169
182
|
|
170
183
|
APPLY_HELP = <<~HELP
|
@@ -218,10 +231,30 @@ module Bolt
|
|
218
231
|
bolt file <action> [options]
|
219
232
|
|
220
233
|
DESCRIPTION
|
221
|
-
|
234
|
+
Copy files and directories between the controller and targets
|
222
235
|
|
223
236
|
ACTIONS
|
224
|
-
|
237
|
+
download Download a file or directory to the controller
|
238
|
+
upload Upload a local file or directory from the controller
|
239
|
+
HELP
|
240
|
+
|
241
|
+
FILE_DOWNLOAD_HELP = <<~HELP
|
242
|
+
NAME
|
243
|
+
download
|
244
|
+
|
245
|
+
USAGE
|
246
|
+
bolt file download <src> <dest> [options]
|
247
|
+
|
248
|
+
DESCRIPTION
|
249
|
+
Download a file or directory from one or more targets.
|
250
|
+
|
251
|
+
Downloaded files and directories are saved to the a subdirectory
|
252
|
+
matching the target's name under the destination directory. The
|
253
|
+
destination directory is expanded relative to the downloads
|
254
|
+
subdirectory of the project directory.
|
255
|
+
|
256
|
+
EXAMPLES
|
257
|
+
bolt file download /etc/ssh_config ssh_config -t all
|
225
258
|
HELP
|
226
259
|
|
227
260
|
FILE_UPLOAD_HELP = <<~HELP
|
@@ -263,6 +296,26 @@ module Bolt
|
|
263
296
|
Show the list of groups in the inventory.
|
264
297
|
HELP
|
265
298
|
|
299
|
+
GUIDE_HELP = <<~HELP
|
300
|
+
NAME
|
301
|
+
guide
|
302
|
+
|
303
|
+
USAGE
|
304
|
+
bolt guide [topic] [options]
|
305
|
+
|
306
|
+
DESCRIPTION
|
307
|
+
View guides for Bolt's concepts and features.
|
308
|
+
|
309
|
+
Omitting a topic will display a list of available guides,
|
310
|
+
while providing a topic will display the relevant guide.
|
311
|
+
|
312
|
+
EXAMPLES
|
313
|
+
View a list of available guides
|
314
|
+
bolt guide
|
315
|
+
View the 'project' guide page
|
316
|
+
bolt guide project
|
317
|
+
HELP
|
318
|
+
|
266
319
|
INVENTORY_HELP = <<~HELP
|
267
320
|
NAME
|
268
321
|
inventory
|
@@ -296,10 +349,11 @@ module Bolt
|
|
296
349
|
bolt plan <action> [parameters] [options]
|
297
350
|
|
298
351
|
DESCRIPTION
|
299
|
-
Convert, show, and run Bolt plans.
|
352
|
+
Convert, create, show, and run Bolt plans.
|
300
353
|
|
301
354
|
ACTIONS
|
302
355
|
convert Convert a YAML plan to a Bolt plan
|
356
|
+
new Create a new plan in the current project
|
303
357
|
run Run a plan on the specified targets
|
304
358
|
show Show available plans and plan documentation
|
305
359
|
HELP
|
@@ -322,6 +376,20 @@ module Bolt
|
|
322
376
|
bolt plan convert path/to/plan/myplan.yaml
|
323
377
|
HELP
|
324
378
|
|
379
|
+
PLAN_NEW_HELP = <<~HELP
|
380
|
+
NAME
|
381
|
+
new
|
382
|
+
|
383
|
+
USAGE
|
384
|
+
bolt plan new <plan> [options]
|
385
|
+
|
386
|
+
DESCRIPTION
|
387
|
+
Create a new plan in the current project.
|
388
|
+
|
389
|
+
EXAMPLES
|
390
|
+
bolt plan new myproject::myplan
|
391
|
+
HELP
|
392
|
+
|
325
393
|
PLAN_RUN_HELP = <<~HELP
|
326
394
|
NAME
|
327
395
|
run
|
@@ -379,19 +447,18 @@ module Bolt
|
|
379
447
|
init
|
380
448
|
|
381
449
|
USAGE
|
382
|
-
bolt project init [
|
450
|
+
bolt project init [name] [options]
|
383
451
|
|
384
452
|
DESCRIPTION
|
385
|
-
Create a new Bolt project.
|
453
|
+
Create a new Bolt project in the current working directory.
|
386
454
|
|
387
|
-
Specify a
|
388
|
-
curent working directory.
|
455
|
+
Specify a name for the Bolt project. Defaults to the basename of the current working directory.
|
389
456
|
|
390
457
|
EXAMPLES
|
391
|
-
Create a new Bolt project
|
458
|
+
Create a new Bolt project using the directory as the project name.
|
392
459
|
bolt project init
|
393
|
-
Create a new Bolt project
|
394
|
-
bolt project init
|
460
|
+
Create a new Bolt project with a specified name.
|
461
|
+
bolt project init myproject
|
395
462
|
Create a new Bolt project with existing modules.
|
396
463
|
bolt project init --modules puppetlabs-apt,puppetlabs-ntp
|
397
464
|
HELP
|
@@ -404,10 +471,7 @@ module Bolt
|
|
404
471
|
bolt project migrate [options]
|
405
472
|
|
406
473
|
DESCRIPTION
|
407
|
-
Migrate a Bolt project to the latest version.
|
408
|
-
|
409
|
-
Loads a Bolt project's inventory file and migrates it to the latest version. The
|
410
|
-
inventory file is modified in place and will not preserve comments or formatting.
|
474
|
+
Migrate a Bolt project to use current best practices and the latest version of configuration files.
|
411
475
|
HELP
|
412
476
|
|
413
477
|
PUPPETFILE_HELP = <<~HELP
|
@@ -653,9 +717,9 @@ module Bolt
|
|
653
717
|
@options[:password] = password
|
654
718
|
end
|
655
719
|
define('--password-prompt', 'Prompt for user to input password') do |_password|
|
656
|
-
|
657
|
-
@options[:password] =
|
658
|
-
|
720
|
+
$stderr.print "Please enter your password: "
|
721
|
+
@options[:password] = $stdin.noecho(&:gets).chomp
|
722
|
+
$stderr.puts
|
659
723
|
end
|
660
724
|
define('--private-key KEY', 'Path to private ssh key to authenticate with') do |key|
|
661
725
|
@options[:'private-key'] = File.expand_path(key)
|
@@ -679,9 +743,9 @@ module Bolt
|
|
679
743
|
@options[:'sudo-password'] = password
|
680
744
|
end
|
681
745
|
define('--sudo-password-prompt', 'Prompt for user to input escalation password') do |_password|
|
682
|
-
|
683
|
-
@options[:'sudo-password'] =
|
684
|
-
|
746
|
+
$stderr.print "Please enter your privilege escalation password: "
|
747
|
+
@options[:'sudo-password'] = $stdin.noecho(&:gets).chomp
|
748
|
+
$stderr.puts
|
685
749
|
end
|
686
750
|
define('--sudo-executable EXEC', "Specify an executable for running as another user.",
|
687
751
|
"This option is experimental.") do |exec|
|
@@ -738,6 +802,15 @@ module Bolt
|
|
738
802
|
@options[:'save-rerun'] = save
|
739
803
|
end
|
740
804
|
|
805
|
+
separator "\nREMOTE ENVIRONMENT OPTIONS"
|
806
|
+
define('--env-var ENVIRONMENT_VARIABLES', 'Environment variables to set on the target') do |envvar|
|
807
|
+
unless envvar.include?('=')
|
808
|
+
raise Bolt::CLIError, "Environment variables must be specified using 'myenvvar=key' format"
|
809
|
+
end
|
810
|
+
@options[:env_vars] ||= {}
|
811
|
+
@options[:env_vars].store(*envvar.split('=', 2))
|
812
|
+
end
|
813
|
+
|
741
814
|
separator "\nTRANSPORT OPTIONS"
|
742
815
|
define('--transport TRANSPORT', TRANSPORTS.keys.map(&:to_s),
|
743
816
|
"Specify a default transport: #{TRANSPORTS.keys.join(', ')}") do |t|
|
@@ -814,7 +887,7 @@ module Bolt
|
|
814
887
|
end
|
815
888
|
define('--log-level LEVEL',
|
816
889
|
"Set the log level for the console. Available options are",
|
817
|
-
"debug, info,
|
890
|
+
"trace, debug, info, warn, error, fatal, any.") do |level|
|
818
891
|
@options[:log] = { 'console' => { 'level' => level } }
|
819
892
|
end
|
820
893
|
define('--plugin PLUGIN', 'Select the plugin to use') do |plug|
|
@@ -855,7 +928,7 @@ module Bolt
|
|
855
928
|
file = value.sub(/^@/, '')
|
856
929
|
read_arg_file(file)
|
857
930
|
elsif value == '-'
|
858
|
-
|
931
|
+
$stdin.read
|
859
932
|
else
|
860
933
|
value
|
861
934
|
end
|