bolt 3.0.0 → 3.5.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 +13 -11
- data/bolt-modules/boltlib/lib/puppet/datatypes/containerresult.rb +24 -0
- data/bolt-modules/boltlib/lib/puppet/functions/add_facts.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +20 -2
- data/bolt-modules/boltlib/lib/puppet/functions/run_container.rb +162 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +2 -2
- data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +44 -5
- data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +1 -1
- data/bolt-modules/boltlib/types/planresult.pp +1 -0
- data/bolt-modules/file/lib/puppet/functions/file/read.rb +3 -2
- data/bolt-modules/prompt/lib/puppet/functions/prompt.rb +20 -2
- data/bolt-modules/prompt/lib/puppet/functions/prompt/menu.rb +103 -0
- data/lib/bolt/apply_result.rb +1 -1
- data/lib/bolt/bolt_option_parser.rb +6 -3
- data/lib/bolt/cli.rb +96 -16
- data/lib/bolt/config.rb +4 -0
- data/lib/bolt/config/options.rb +21 -3
- data/lib/bolt/config/transport/lxd.rb +23 -0
- data/lib/bolt/config/transport/options.rb +8 -1
- data/lib/bolt/container_result.rb +105 -0
- data/lib/bolt/error.rb +15 -0
- data/lib/bolt/executor.rb +22 -7
- data/lib/bolt/inventory/options.rb +9 -0
- data/lib/bolt/inventory/target.rb +16 -0
- data/lib/bolt/logger.rb +8 -0
- data/lib/bolt/module_installer.rb +2 -2
- data/lib/bolt/module_installer/puppetfile.rb +2 -2
- data/lib/bolt/module_installer/specs/forge_spec.rb +2 -2
- data/lib/bolt/module_installer/specs/git_spec.rb +2 -2
- data/lib/bolt/node/output.rb +14 -4
- data/lib/bolt/outputter/human.rb +106 -23
- data/lib/bolt/outputter/logger.rb +17 -0
- data/lib/bolt/pal.rb +25 -4
- data/lib/bolt/pal/yaml_plan.rb +1 -2
- data/lib/bolt/pal/yaml_plan/evaluator.rb +5 -141
- data/lib/bolt/pal/yaml_plan/step.rb +91 -31
- data/lib/bolt/pal/yaml_plan/step/command.rb +21 -13
- data/lib/bolt/pal/yaml_plan/step/download.rb +15 -16
- data/lib/bolt/pal/yaml_plan/step/eval.rb +11 -11
- data/lib/bolt/pal/yaml_plan/step/message.rb +13 -4
- data/lib/bolt/pal/yaml_plan/step/plan.rb +19 -15
- data/lib/bolt/pal/yaml_plan/step/resources.rb +82 -21
- data/lib/bolt/pal/yaml_plan/step/script.rb +36 -17
- data/lib/bolt/pal/yaml_plan/step/task.rb +19 -16
- data/lib/bolt/pal/yaml_plan/step/upload.rb +16 -17
- data/lib/bolt/pal/yaml_plan/transpiler.rb +3 -3
- data/lib/bolt/plan_creator.rb +1 -1
- data/lib/bolt/project_manager.rb +1 -1
- data/lib/bolt/project_manager/module_migrator.rb +1 -1
- data/lib/bolt/result.rb +11 -15
- data/lib/bolt/shell.rb +16 -0
- data/lib/bolt/shell/bash.rb +61 -31
- data/lib/bolt/shell/bash/tmpdir.rb +2 -2
- data/lib/bolt/shell/powershell.rb +34 -12
- data/lib/bolt/shell/powershell/snippets.rb +30 -3
- data/lib/bolt/task.rb +1 -1
- data/lib/bolt/transport/base.rb +0 -9
- data/lib/bolt/transport/docker.rb +1 -125
- data/lib/bolt/transport/docker/connection.rb +77 -167
- data/lib/bolt/transport/lxd.rb +26 -0
- data/lib/bolt/transport/lxd/connection.rb +99 -0
- data/lib/bolt/transport/orch.rb +13 -5
- data/lib/bolt/transport/ssh/connection.rb +1 -1
- data/lib/bolt/transport/winrm/connection.rb +1 -1
- data/lib/bolt/util.rb +31 -0
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/transport_app.rb +61 -33
- data/lib/bolt_spec/bolt_context.rb +9 -4
- data/lib/bolt_spec/plans.rb +1 -109
- data/lib/bolt_spec/plans/action_stubs.rb +1 -1
- data/lib/bolt_spec/plans/action_stubs/command_stub.rb +8 -1
- data/lib/bolt_spec/plans/action_stubs/script_stub.rb +8 -1
- data/lib/bolt_spec/plans/mock_executor.rb +90 -7
- data/modules/puppet_connect/plans/test_input_data.pp +65 -7
- metadata +9 -2
@@ -11,12 +11,24 @@ Puppet::Functions.create_function(:prompt) do
|
|
11
11
|
# @option options [Boolean] sensitive Disable echo back and mark the response as sensitive.
|
12
12
|
# The returned value will be wrapped by the `Sensitive` data type. To access the raw
|
13
13
|
# value, use the `unwrap` function (i.e. `$sensitive_value.unwrap`).
|
14
|
+
# @option options [String] default The default value to return if the user does not provide
|
15
|
+
# input or if stdin is not a tty.
|
14
16
|
# @return The response to the prompt.
|
15
17
|
# @example Prompt the user if plan execution should continue
|
16
18
|
# $response = prompt('Continue executing plan? [Y\N]')
|
17
19
|
# @example Prompt the user for sensitive information
|
18
20
|
# $password = prompt('Enter your password', 'sensitive' => true)
|
19
21
|
# out::message("Password is: ${password.unwrap}")
|
22
|
+
# @example Prompt the user and provide a default value
|
23
|
+
# $user = prompt('Enter your login username', 'default' => 'root')
|
24
|
+
# @example Prompt the user for sensitive information, returning a sensitive default if one is not provided
|
25
|
+
# $token = prompt('Enter token', 'default' => lookup('default_token'), 'sensitive' => true)
|
26
|
+
# out::message("Token is: ${token.unwrap}")
|
27
|
+
# @example Prompt the user and fail with a custom message if no input was provided
|
28
|
+
# $response = prompt('Enter your name', 'default' => '')
|
29
|
+
# if $response.empty {
|
30
|
+
# fail_plan('Must provide your name')
|
31
|
+
# }
|
20
32
|
dispatch :prompt do
|
21
33
|
param 'String', :prompt
|
22
34
|
optional_param 'Hash[String[1], Any]', :options
|
@@ -30,14 +42,20 @@ Puppet::Functions.create_function(:prompt) do
|
|
30
42
|
action: 'prompt')
|
31
43
|
end
|
32
44
|
|
33
|
-
options
|
34
|
-
|
45
|
+
options = options.transform_keys(&:to_sym)
|
35
46
|
executor = Puppet.lookup(:bolt_executor)
|
47
|
+
|
36
48
|
# Send analytics report
|
37
49
|
executor.report_function_call(self.class.name)
|
38
50
|
|
51
|
+
# Require default to be a string value
|
52
|
+
if options.key?(:default) && !options[:default].is_a?(String)
|
53
|
+
raise Bolt::ValidationError, "Option 'default' must be a string"
|
54
|
+
end
|
55
|
+
|
39
56
|
response = executor.prompt(prompt, options)
|
40
57
|
|
58
|
+
# If sensitive, wrap it
|
41
59
|
if options[:sensitive]
|
42
60
|
Puppet::Pops::Types::PSensitiveType::Sensitive.new(response)
|
43
61
|
else
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bolt/error'
|
4
|
+
|
5
|
+
# Display a menu prompt and wait for a response. Continues to prompt
|
6
|
+
# until an option from the menu is selected.
|
7
|
+
#
|
8
|
+
# > **Note:** Not available in apply block
|
9
|
+
Puppet::Functions.create_function(:'prompt::menu') do
|
10
|
+
# Select from a list of options.
|
11
|
+
# @param prompt The prompt to display.
|
12
|
+
# @param menu A list of options to choose from.
|
13
|
+
# @param options A hash of additional options.
|
14
|
+
# @option options [String] default The default option to return if the user does not provide
|
15
|
+
# input or if standard in (stdin) is not a tty. Must be an option present in the menu.
|
16
|
+
# @return The selected option.
|
17
|
+
# @example Prompt the user to select from a list of options
|
18
|
+
# $selection = prompt::menu('Select a fruit', ['apple', 'banana', 'carrot'])
|
19
|
+
# @example Prompt the user to select from a list of options with a default value
|
20
|
+
# $selection = prompt::menu('Select environment', ['development', 'production'], 'default' => 'development')
|
21
|
+
dispatch :prompt_menu_array do
|
22
|
+
param 'String', :prompt
|
23
|
+
param 'Array[Variant[Target, Data]]', :menu
|
24
|
+
optional_param 'Hash[String[1], Variant[Target, Data]]', :options
|
25
|
+
return_type 'Variant[Target, Data]'
|
26
|
+
end
|
27
|
+
|
28
|
+
# Select from a list of options with custom inputs.
|
29
|
+
# @param prompt The prompt to display.
|
30
|
+
# @param menu A hash of options to choose from, where keys are the input used to select a value.
|
31
|
+
# @param options A hash of additional options.
|
32
|
+
# @option options [String] default The default option to return if the user does not provide
|
33
|
+
# input or if standard in (stdin) is not a tty. Must be an option present in the menu.
|
34
|
+
# @return The selected option.
|
35
|
+
# @example Prompt the user to select from a list of options with custom inputs
|
36
|
+
# $menu = { 'y' => 'yes', 'n' => 'no' }
|
37
|
+
# $selection = prompt::menu('Install Puppet?', $menu)
|
38
|
+
dispatch :prompt_menu do
|
39
|
+
param 'String', :prompt
|
40
|
+
param 'Hash[String[1], Variant[Target, Data]]', :menu
|
41
|
+
optional_param 'Hash[String[1], Variant[Target, Data]]', :options
|
42
|
+
return_type 'Variant[TargetSpec, Data]'
|
43
|
+
end
|
44
|
+
|
45
|
+
def prompt_menu_array(prompt, menu, options = {})
|
46
|
+
menu_hash = menu.map.with_index { |value, index| [(index + 1).to_s, value] }.to_h
|
47
|
+
prompt_menu(prompt, menu_hash, options)
|
48
|
+
end
|
49
|
+
|
50
|
+
def prompt_menu(prompt, menu, options = {})
|
51
|
+
unless Puppet[:tasks]
|
52
|
+
raise Puppet::ParseErrorWithIssue
|
53
|
+
.from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING,
|
54
|
+
action: 'prompt::menu')
|
55
|
+
end
|
56
|
+
|
57
|
+
options = options.transform_keys(&:to_sym)
|
58
|
+
executor = Puppet.lookup(:bolt_executor)
|
59
|
+
|
60
|
+
# Send analytics report
|
61
|
+
executor.report_function_call(self.class.name)
|
62
|
+
|
63
|
+
# Error if there are no options
|
64
|
+
if menu.empty?
|
65
|
+
raise Bolt::ValidationError, "Menu cannot be empty"
|
66
|
+
end
|
67
|
+
|
68
|
+
# Error if the default value is not on the menu
|
69
|
+
if options.key?(:default) && !menu.value?(options[:default])
|
70
|
+
raise Bolt::ValidationError, "Default value '#{options[:default]}' is not one of the provided menu options"
|
71
|
+
end
|
72
|
+
|
73
|
+
# The first prompt should include the menu
|
74
|
+
to_prompt = format_menu(menu) + prompt
|
75
|
+
|
76
|
+
# Request input from the user until they provide a valid option
|
77
|
+
loop do
|
78
|
+
selection = executor.prompt(to_prompt, options)
|
79
|
+
|
80
|
+
return menu[selection] if menu.key?(selection)
|
81
|
+
return selection if options.key?(:default) && options[:default] == selection
|
82
|
+
|
83
|
+
# Only reprint the prompt, not the menu
|
84
|
+
to_prompt = "Invalid option, try again. #{prompt}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Builds the menu string. Aligns all the values by padding input keys.
|
89
|
+
#
|
90
|
+
private def format_menu(menu)
|
91
|
+
# Find the longest input and add 2 for wrapping parenthesis
|
92
|
+
key_length = menu.keys.max_by(&:length).length + 2
|
93
|
+
|
94
|
+
menu_string = +''
|
95
|
+
|
96
|
+
menu.each do |key, value|
|
97
|
+
key = "(#{key})".ljust(key_length)
|
98
|
+
menu_string << "#{key} #{value}\n"
|
99
|
+
end
|
100
|
+
|
101
|
+
menu_string
|
102
|
+
end
|
103
|
+
end
|
data/lib/bolt/apply_result.rb
CHANGED
@@ -54,7 +54,7 @@ module Bolt
|
|
54
54
|
unless missing_keys.empty?
|
55
55
|
if result['_output']
|
56
56
|
# rubocop:disable Layout/LineLength
|
57
|
-
msg = "Report result contains an '_output' key. Catalog application
|
57
|
+
msg = "Report result contains an '_output' key. Catalog application might have printed extraneous output to stdout: #{result['_output']}"
|
58
58
|
# rubocop:enable Layout/LineLength
|
59
59
|
else
|
60
60
|
msg = "Report did not contain all expected keys missing: #{missing_keys.join(', ')}"
|
@@ -13,7 +13,7 @@ module Bolt
|
|
13
13
|
run_context: %w[concurrency inventoryfile save-rerun cleanup],
|
14
14
|
global_config_setters: PROJECT_PATHS + %w[modulepath],
|
15
15
|
transports: %w[transport connect-timeout tty native-ssh ssh-command copy-command],
|
16
|
-
display: %w[format color verbose trace],
|
16
|
+
display: %w[format color verbose trace stream],
|
17
17
|
global: %w[help version log-level clear-cache] }.freeze
|
18
18
|
|
19
19
|
ACTION_OPTS = OPTIONS.values.flatten.freeze
|
@@ -454,7 +454,7 @@ module Bolt
|
|
454
454
|
DESCRIPTION
|
455
455
|
Convert a YAML plan to a Puppet language plan and print the converted plan to stdout.
|
456
456
|
|
457
|
-
Converting a YAML plan
|
457
|
+
Converting a YAML plan might result in a plan that is syntactically
|
458
458
|
correct but has different behavior. Always verify a converted plan's
|
459
459
|
functionality. Note that the converted plan is not written to a file.
|
460
460
|
|
@@ -707,7 +707,7 @@ module Bolt
|
|
707
707
|
"Or read a target list from an input file '@<file>' or stdin '-'.",
|
708
708
|
'Example: --targets localhost,target_group,ssh://nix.com:23,winrm://windows.puppet.com',
|
709
709
|
'URI format is [protocol://]host[:port]',
|
710
|
-
"SSH is the default protocol;
|
710
|
+
"SSH is the default protocol; can be #{TRANSPORTS.keys.join(', ')}",
|
711
711
|
'For Windows targets, specify the winrm:// protocol if it has not be configured',
|
712
712
|
'For SSH, port defaults to `22`',
|
713
713
|
'For WinRM, port defaults to `5985` or `5986` based on the --[no-]ssl setting') do |targets|
|
@@ -888,6 +888,9 @@ module Bolt
|
|
888
888
|
define('-v', '--[no-]verbose', 'Display verbose logging') do |value|
|
889
889
|
@options[:verbose] = value
|
890
890
|
end
|
891
|
+
define('--stream', 'Stream output from scripts and commands to the console') do |_|
|
892
|
+
@options[:stream] = true
|
893
|
+
end
|
891
894
|
define('--trace', 'Display error stack traces') do |_|
|
892
895
|
@options[:trace] = true
|
893
896
|
end
|
data/lib/bolt/cli.rb
CHANGED
@@ -96,6 +96,48 @@ module Bolt
|
|
96
96
|
finalize_setup
|
97
97
|
end
|
98
98
|
|
99
|
+
# Prints a welcome message when users first install Bolt and run `bolt`, `bolt help` or `bolt --help`
|
100
|
+
def welcome_message
|
101
|
+
bolt = <<~BOLT
|
102
|
+
`.::-`
|
103
|
+
`.-:///////-.`
|
104
|
+
`-:////:. `-:///:- /ooo. .ooo/
|
105
|
+
`.-:///::///:-` `-//: ymmm- :mmmy .---.
|
106
|
+
:///:-. `.:////. -//: ymmm- :mmmy +mmm+
|
107
|
+
://. ///. -//: ymmm--/++/- `-/++/:` :mmmy-:smmms::-
|
108
|
+
://. ://. .://: ymmmdmmmmmmdo` .smmmmmmmmh: :mmmysmmmmmmmms
|
109
|
+
://. ://:///:-. ymmmh/--/hmmmy -mmmd/-.:hmmm+:mmmy.-smmms--.
|
110
|
+
://:.` .-////:-` ymmm- ymmm:hmmm- `dmmm/mmmy +mmm+
|
111
|
+
`-:///:-..:///:-.` ymmm- ommm/dmmm` hmmm+mmmy +mmm+
|
112
|
+
`.-:////:-` ymmm+ /mmmm.ommms` /mmmh:mmmy +mmmo
|
113
|
+
`-.` ymmmmmhhmmmmd: ommmmhydmmmy`:mmmy -mmmmdhd
|
114
|
+
oyyy+shddhs/` .+shddhy+- -yyyo .ohddhs
|
115
|
+
|
116
|
+
|
117
|
+
BOLT
|
118
|
+
example_cmd = if Bolt::Util.windows?
|
119
|
+
"Invoke-BoltCommand -Command 'hostname' -Targets localhost"
|
120
|
+
else
|
121
|
+
"bolt command run 'hostname' --target localhost"
|
122
|
+
end
|
123
|
+
prev_cmd = String.new("bolt")
|
124
|
+
prev_cmd << " #{@argv[0]}" unless @argv.empty?
|
125
|
+
|
126
|
+
message = <<~MSG
|
127
|
+
🎉 Welcome to Bolt #{VERSION}
|
128
|
+
😌 We're here to help bring order to the chaos
|
129
|
+
📖 Find our documentation at https://bolt.guide
|
130
|
+
🙋 Ask a question in #bolt on https://slack.puppet.com/
|
131
|
+
🔩 Contribute at https://github.com/puppetlabs/bolt/
|
132
|
+
💡 Not sure where to start? Try "#{example_cmd}"
|
133
|
+
|
134
|
+
We only print this message once. Run "#{prev_cmd}" again for help text.
|
135
|
+
MSG
|
136
|
+
|
137
|
+
$stdout.print "\033[36m#{bolt}\033[0m"
|
138
|
+
$stdout.print message
|
139
|
+
end
|
140
|
+
|
99
141
|
# Parses the command and validates options. All errors that are raised here
|
100
142
|
# are not handled by the outputter, as it relies on config being loaded.
|
101
143
|
def parse_command
|
@@ -107,6 +149,16 @@ module Bolt
|
|
107
149
|
# help text
|
108
150
|
options[:subcommand] = nil unless COMMANDS.include?(options[:subcommand])
|
109
151
|
|
152
|
+
if Bolt::Util.first_run?
|
153
|
+
FileUtils.mkdir_p(Bolt::Util.first_runs_free.dirname)
|
154
|
+
FileUtils.touch(Bolt::Util.first_runs_free)
|
155
|
+
|
156
|
+
if options[:subcommand].nil? && $stdout.isatty
|
157
|
+
welcome_message
|
158
|
+
raise Bolt::CLIExit
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
110
162
|
# Update the parser for the subcommand (or lack thereof)
|
111
163
|
parser.update
|
112
164
|
puts parser.help
|
@@ -175,6 +227,7 @@ module Bolt
|
|
175
227
|
# Completes the setup process by configuring Bolt and log messages
|
176
228
|
def finalize_setup
|
177
229
|
Bolt::Logger.configure(config.log, config.color, config.disable_warnings)
|
230
|
+
Bolt::Logger.stream = config.stream
|
178
231
|
Bolt::Logger.analytics = analytics
|
179
232
|
Bolt::Logger.flush_queue
|
180
233
|
|
@@ -212,7 +265,7 @@ module Bolt
|
|
212
265
|
target_opts = options.keys.select { |opt| %i[query rerun targets].include?(opt) }
|
213
266
|
target_string = "'--targets', '--rerun', or '--query'"
|
214
267
|
if target_opts.length > 1
|
215
|
-
raise Bolt::CLIError, "Only one targeting option #{target_string}
|
268
|
+
raise Bolt::CLIError, "Only one targeting option #{target_string} can be specified"
|
216
269
|
elsif target_opts.empty? && options[:subcommand] != 'plan'
|
217
270
|
raise Bolt::CLIError, "Command requires a targeting option: #{target_string}"
|
218
271
|
end
|
@@ -249,11 +302,14 @@ module Bolt
|
|
249
302
|
end
|
250
303
|
end
|
251
304
|
|
252
|
-
if %w[task plan].include?(options[:subcommand]) && options[:action] == 'run'
|
305
|
+
if %w[task plan script].include?(options[:subcommand]) && options[:action] == 'run'
|
253
306
|
if options[:object].nil?
|
254
307
|
raise Bolt::CLIError, "Must specify a #{options[:subcommand]} to run"
|
255
308
|
end
|
256
|
-
|
309
|
+
end
|
310
|
+
|
311
|
+
# This may mean that we parsed a parameter as the object
|
312
|
+
if %w[task plan].include?(options[:subcommand]) && options[:action] == 'run'
|
257
313
|
unless options[:object] =~ /\A([a-z][a-z0-9_]*)?(::[a-z][a-z0-9_]*)*\Z/
|
258
314
|
raise Bolt::CLIError,
|
259
315
|
"Invalid #{options[:subcommand]} '#{options[:object]}'"
|
@@ -301,13 +357,13 @@ module Bolt
|
|
301
357
|
if options[:noop] &&
|
302
358
|
!(options[:subcommand] == 'task' && options[:action] == 'run') && options[:subcommand] != 'apply'
|
303
359
|
raise Bolt::CLIError,
|
304
|
-
"Option '--noop'
|
360
|
+
"Option '--noop' can only be specified when running a task or applying manifest code"
|
305
361
|
end
|
306
362
|
|
307
363
|
if options[:env_vars]
|
308
364
|
unless %w[command script].include?(options[:subcommand]) && options[:action] == 'run'
|
309
365
|
raise Bolt::CLIError,
|
310
|
-
"Option '--env-var'
|
366
|
+
"Option '--env-var' can only be specified when running a command or script"
|
311
367
|
end
|
312
368
|
end
|
313
369
|
end
|
@@ -354,7 +410,7 @@ module Bolt
|
|
354
410
|
if inventory_source && conflicting_options.any?
|
355
411
|
Bolt::Logger.warn(
|
356
412
|
"cli_overrides",
|
357
|
-
"CLI arguments #{conflicting_options.to_a}
|
413
|
+
"CLI arguments #{conflicting_options.to_a} might be overridden by Inventory: #{inventory_source}"
|
358
414
|
)
|
359
415
|
end
|
360
416
|
end
|
@@ -432,7 +488,7 @@ module Bolt
|
|
432
488
|
return 0
|
433
489
|
end
|
434
490
|
|
435
|
-
message = 'There
|
491
|
+
message = 'There might be processes left executing on some nodes.'
|
436
492
|
|
437
493
|
if %w[task plan].include?(options[:subcommand]) && options[:task_options] && !options[:params_parsed] && pal
|
438
494
|
options[:task_options] = pal.parse_params(options[:subcommand], options[:object], options[:task_options])
|
@@ -501,9 +557,8 @@ module Bolt
|
|
501
557
|
when 'command'
|
502
558
|
executor.run_command(targets, options[:object], executor_opts)
|
503
559
|
when 'script'
|
504
|
-
|
505
|
-
|
506
|
-
executor.run_script(targets, script, options[:leftovers], executor_opts)
|
560
|
+
script_path = find_file(options[:object])
|
561
|
+
executor.run_script(targets, script_path, options[:leftovers], executor_opts)
|
507
562
|
when 'task'
|
508
563
|
pal.run_task(options[:object],
|
509
564
|
targets,
|
@@ -610,7 +665,7 @@ module Bolt
|
|
610
665
|
if plan_arguments['nodes'] || plan_arguments['targets']
|
611
666
|
key = plan_arguments.include?('nodes') ? 'nodes' : 'targets'
|
612
667
|
raise Bolt::CLIError,
|
613
|
-
"A plan's '#{key}' parameter
|
668
|
+
"A plan's '#{key}' parameter can be specified using the --#{key} option, but in that " \
|
614
669
|
"case it must not be specified as a separate #{key}=<value> parameter nor included " \
|
615
670
|
"in the JSON data passed in the --params option"
|
616
671
|
end
|
@@ -709,9 +764,11 @@ module Bolt
|
|
709
764
|
def install_project_modules(project, config, force, resolve)
|
710
765
|
assert_project_file(project)
|
711
766
|
|
712
|
-
|
713
|
-
outputter.print_message
|
714
|
-
|
767
|
+
if project.modules.empty? && resolve != false
|
768
|
+
outputter.print_message(
|
769
|
+
"Project configuration file #{project.project_file} does not "\
|
770
|
+
"specify any module dependencies. Nothing to do."
|
771
|
+
)
|
715
772
|
return 0
|
716
773
|
end
|
717
774
|
|
@@ -838,6 +895,28 @@ module Bolt
|
|
838
895
|
Bolt::Util.validate_file(type, path, allow_dir)
|
839
896
|
end
|
840
897
|
|
898
|
+
# Returns the path to a file. If the path is an absolute or relative to
|
899
|
+
# a file, and the file exists, returns the path as-is. Otherwise, checks if
|
900
|
+
# the path is a Puppet file path and looks for the file in a module's files
|
901
|
+
# directory.
|
902
|
+
#
|
903
|
+
def find_file(path)
|
904
|
+
unless File.exist?(path) || Pathname.new(path).absolute?
|
905
|
+
modulepath = Bolt::Config::Modulepath.new(config.modulepath)
|
906
|
+
modules = Bolt::Module.discover(modulepath.full_modulepath, config.project)
|
907
|
+
mod, file = path.split(File::SEPARATOR, 2)
|
908
|
+
|
909
|
+
if modules[mod]
|
910
|
+
@logger.debug("Did not find file at #{File.expand_path(path)}, checking in module '#{mod}'")
|
911
|
+
path = File.join(modules[mod].path, 'files', file)
|
912
|
+
end
|
913
|
+
end
|
914
|
+
|
915
|
+
Bolt::Util.validate_file('script', path)
|
916
|
+
|
917
|
+
path
|
918
|
+
end
|
919
|
+
|
841
920
|
def rerun
|
842
921
|
@rerun ||= Bolt::Rerun.new(config.rerunfile, config.save_rerun)
|
843
922
|
end
|
@@ -866,7 +945,7 @@ module Bolt
|
|
866
945
|
# If the bundled content directory is empty, Bolt is likely installed as a gem.
|
867
946
|
if ENV['BOLT_GEM'].nil? && incomplete_install?
|
868
947
|
msg = <<~MSG.chomp
|
869
|
-
Bolt
|
948
|
+
Bolt might be installed as a gem. To use Bolt reliably and with all of its
|
870
949
|
dependencies, uninstall the 'bolt' gem and install Bolt as a package:
|
871
950
|
https://puppet.com/docs/bolt/latest/bolt_installing.html
|
872
951
|
|
@@ -897,7 +976,8 @@ module Bolt
|
|
897
976
|
# Gem installs include the aggregate, canary, and puppetdb_fact modules, while
|
898
977
|
# package installs include modules listed in the Bolt repo Puppetfile
|
899
978
|
def incomplete_install?
|
900
|
-
|
979
|
+
builtin_module_list = %w[aggregate canary puppetdb_fact secure_env_vars puppet_connect]
|
980
|
+
(Dir.children(Bolt::Config::Modulepath::MODULES_PATH) - builtin_module_list).empty?
|
901
981
|
end
|
902
982
|
|
903
983
|
# Mimicks the output from Outputter::Human#fatal_error. This should be used to print
|
data/lib/bolt/config.rb
CHANGED
data/lib/bolt/config/options.rb
CHANGED
@@ -4,6 +4,7 @@ require 'bolt/config/transport/ssh'
|
|
4
4
|
require 'bolt/config/transport/winrm'
|
5
5
|
require 'bolt/config/transport/orch'
|
6
6
|
require 'bolt/config/transport/local'
|
7
|
+
require 'bolt/config/transport/lxd'
|
7
8
|
require 'bolt/config/transport/docker'
|
8
9
|
require 'bolt/config/transport/remote'
|
9
10
|
|
@@ -17,6 +18,7 @@ module Bolt
|
|
17
18
|
'winrm' => Bolt::Config::Transport::WinRM,
|
18
19
|
'pcp' => Bolt::Config::Transport::Orch,
|
19
20
|
'local' => Bolt::Config::Transport::Local,
|
21
|
+
'lxd' => Bolt::Config::Transport::LXD,
|
20
22
|
'docker' => Bolt::Config::Transport::Docker,
|
21
23
|
'remote' => Bolt::Config::Transport::Remote
|
22
24
|
}.freeze
|
@@ -423,7 +425,14 @@ module Bolt
|
|
423
425
|
_example: false,
|
424
426
|
_default: true
|
425
427
|
},
|
426
|
-
|
428
|
+
"stream" => {
|
429
|
+
description: "Whether to stream output from scripts and commands to the console. "\
|
430
|
+
"**This option is experimental**.",
|
431
|
+
type: [TrueClass, FalseClass],
|
432
|
+
_plugin: false,
|
433
|
+
_default: false,
|
434
|
+
_example: true
|
435
|
+
},
|
427
436
|
"tasks" => {
|
428
437
|
description: "A list of task names and glob patterns to filter the project's tasks by. This option is used "\
|
429
438
|
"to limit the visibility of tasks for users of the project. For example, project authors "\
|
@@ -440,8 +449,8 @@ module Bolt
|
|
440
449
|
},
|
441
450
|
"trusted-external-command" => {
|
442
451
|
description: "The path to an executable on the Bolt controller that can produce external trusted facts. "\
|
443
|
-
"**External trusted facts are experimental in both Puppet and Bolt and this API
|
444
|
-
"be removed.**",
|
452
|
+
"**External trusted facts are experimental in both Puppet and Bolt and this API might "\
|
453
|
+
"change or be removed.**",
|
445
454
|
type: String,
|
446
455
|
_plugin: false,
|
447
456
|
_example: "/etc/puppetlabs/facts/trusted_external.sh"
|
@@ -475,6 +484,13 @@ module Bolt
|
|
475
484
|
_plugin: true,
|
476
485
|
_example: { "cleanup" => false, "tmpdir" => "/tmp/bolt" }
|
477
486
|
},
|
487
|
+
"lxd" => {
|
488
|
+
description: "A map of configuration options for the LXD transport. The LXD transport is "\
|
489
|
+
"experimental and might include breaking changes between minor versions.",
|
490
|
+
type: Hash,
|
491
|
+
_plugin: true,
|
492
|
+
_example: { cleanup: false }
|
493
|
+
},
|
478
494
|
"pcp" => {
|
479
495
|
description: "A map of configuration options for the pcp transport.",
|
480
496
|
type: Hash,
|
@@ -530,6 +546,7 @@ module Bolt
|
|
530
546
|
puppetdb
|
531
547
|
save-rerun
|
532
548
|
spinner
|
549
|
+
stream
|
533
550
|
].freeze
|
534
551
|
|
535
552
|
# Options that are available in a bolt-project.yaml file
|
@@ -553,6 +570,7 @@ module Bolt
|
|
553
570
|
puppetdb
|
554
571
|
save-rerun
|
555
572
|
spinner
|
573
|
+
stream
|
556
574
|
tasks
|
557
575
|
trusted-external-command
|
558
576
|
].freeze
|