bolt 2.44.0 → 3.4.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 +11 -9
- data/bolt-modules/boltlib/lib/puppet/functions/add_facts.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +25 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +20 -2
- 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/lib/puppet/functions/wait_until_available.rb +7 -3
- 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 +9 -123
- data/lib/bolt/cli.rb +125 -127
- data/lib/bolt/config.rb +39 -214
- data/lib/bolt/config/options.rb +34 -125
- data/lib/bolt/config/transport/local.rb +1 -0
- data/lib/bolt/config/transport/lxd.rb +23 -0
- data/lib/bolt/config/transport/options.rb +9 -2
- data/lib/bolt/executor.rb +20 -5
- data/lib/bolt/logger.rb +9 -1
- 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 +52 -24
- data/lib/bolt/outputter/json.rb +16 -16
- data/lib/bolt/pal.rb +26 -5
- data/lib/bolt/pal/yaml_plan.rb +1 -2
- data/lib/bolt/pal/yaml_plan/evaluator.rb +5 -153
- data/lib/bolt/pal/yaml_plan/step.rb +91 -52
- 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/plugin/module.rb +0 -23
- data/lib/bolt/plugin/puppet_connect_data.rb +45 -3
- data/lib/bolt/project.rb +16 -56
- data/lib/bolt/project_manager.rb +5 -4
- data/lib/bolt/project_manager/module_migrator.rb +7 -6
- data/lib/bolt/result.rb +10 -11
- 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 +35 -14
- data/lib/bolt/shell/powershell/snippets.rb +37 -150
- 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 +86 -161
- data/lib/bolt/transport/local.rb +1 -9
- 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 +8 -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 +4 -0
- data/modules/aggregate/plans/count.pp +21 -0
- data/modules/aggregate/plans/targets.pp +21 -0
- data/modules/puppet_connect/plans/test_input_data.pp +67 -0
- data/modules/puppetdb_fact/plans/init.pp +10 -0
- metadata +7 -3
- data/modules/aggregate/plans/nodes.pp +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2e66e28078af9324bb7d5668ee5079535d829913a2dcb4bce65daa4d471d4524
|
4
|
+
data.tar.gz: a821d82c490030be200c0d4ab5dc4a56a1abf1aa862d69d1e4c6a4595e47952d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 120dd18c9478c105387f2ad3634276cbaae05fe3638cc01d378aa9cbb1c423bf737991b7278ab4f96eb0a7cca39cd3d259cbba3d1734cea6ac071ba0695da901
|
7
|
+
data.tar.gz: 61171ff383d06883e6f6ffa0cafc423a80d41ea0f2d45c3c0e4b76c7037a4626ad7a4b8b625e3a013e077b9e96cdafaab06cad6d5a490dae392af3fbb410d0fe
|
data/Puppetfile
CHANGED
@@ -5,14 +5,14 @@ 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', '
|
9
|
-
mod 'puppetlabs-puppet_agent', '4.
|
8
|
+
mod 'puppetlabs-service', '2.0.0'
|
9
|
+
mod 'puppetlabs-puppet_agent', '4.5.0'
|
10
10
|
mod 'puppetlabs-facts', '1.4.0'
|
11
11
|
|
12
12
|
# Core types and providers for Puppet 6
|
13
|
-
mod 'puppetlabs-augeas_core', '1.1.
|
13
|
+
mod 'puppetlabs-augeas_core', '1.1.2'
|
14
14
|
mod 'puppetlabs-host_core', '1.0.3'
|
15
|
-
mod 'puppetlabs-scheduled_task', '
|
15
|
+
mod 'puppetlabs-scheduled_task', '3.0.0'
|
16
16
|
mod 'puppetlabs-sshkeys_core', '2.2.0'
|
17
17
|
mod 'puppetlabs-zfs_core', '1.2.0'
|
18
18
|
mod 'puppetlabs-cron_core', '1.0.5'
|
@@ -22,19 +22,20 @@ mod 'puppetlabs-yumrepo_core', '1.0.7'
|
|
22
22
|
mod 'puppetlabs-zone_core', '1.0.3'
|
23
23
|
|
24
24
|
# Useful additional modules
|
25
|
-
mod 'puppetlabs-package', '
|
26
|
-
mod 'puppetlabs-
|
25
|
+
mod 'puppetlabs-package', '2.0.0'
|
26
|
+
mod 'puppetlabs-powershell_task_helper', '0.1.0'
|
27
|
+
mod 'puppetlabs-puppet_conf', '1.1.0'
|
27
28
|
mod 'puppetlabs-python_task_helper', '0.5.0'
|
28
|
-
mod 'puppetlabs-reboot', '
|
29
|
+
mod 'puppetlabs-reboot', '4.0.2'
|
29
30
|
mod 'puppetlabs-ruby_task_helper', '0.6.0'
|
30
31
|
mod 'puppetlabs-ruby_plugin_helper', '0.2.0'
|
31
|
-
mod 'puppetlabs-stdlib', '
|
32
|
+
mod 'puppetlabs-stdlib', '7.0.0'
|
32
33
|
|
33
34
|
# Plugin modules
|
34
35
|
mod 'puppetlabs-aws_inventory', '0.6.0'
|
35
36
|
mod 'puppetlabs-azure_inventory', '0.5.0'
|
36
37
|
mod 'puppetlabs-gcloud_inventory', '0.2.0'
|
37
|
-
mod 'puppetlabs-http_request', '0.2.
|
38
|
+
mod 'puppetlabs-http_request', '0.2.2'
|
38
39
|
mod 'puppetlabs-pkcs7', '0.1.1'
|
39
40
|
mod 'puppetlabs-secure_env_vars', '0.2.0'
|
40
41
|
mod 'puppetlabs-terraform', '0.6.1'
|
@@ -45,3 +46,4 @@ mod 'puppetlabs-yaml', '0.2.0'
|
|
45
46
|
mod 'canary', local: true
|
46
47
|
mod 'aggregate', local: true
|
47
48
|
mod 'puppetdb_fact', local: true
|
49
|
+
mod 'puppet_connect', local: true
|
@@ -7,7 +7,7 @@ require 'bolt/error'
|
|
7
7
|
# > **Note:** Not available in apply block
|
8
8
|
Puppet::Functions.create_function(:add_facts) do
|
9
9
|
# @param target A target.
|
10
|
-
# @param facts A hash of fact names to values that
|
10
|
+
# @param facts A hash of fact names to values that can include structured facts.
|
11
11
|
# @return A `Target` object.
|
12
12
|
# @example Adding facts to a target
|
13
13
|
# add_facts($target, { 'os' => { 'family' => 'windows', 'name' => 'windows' } })
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'bolt/logger'
|
3
4
|
require 'bolt/task'
|
4
5
|
|
5
6
|
# Installs the `puppet-agent` package on targets if needed, then collects facts,
|
@@ -131,10 +132,20 @@ Puppet::Functions.create_function(:apply_prep) do
|
|
131
132
|
task = applicator.custom_facts_task
|
132
133
|
arguments = { 'plugins' => Puppet::Pops::Types::PSensitiveType::Sensitive.new(plugins) }
|
133
134
|
results = executor.run_task(targets, task, arguments)
|
135
|
+
|
134
136
|
# TODO: Standardize RunFailure type with error above
|
135
137
|
raise Bolt::RunFailure.new(results, 'run_task', task.name) unless results.ok?
|
136
138
|
|
137
139
|
results.each do |result|
|
140
|
+
# Log a warning if the client version is < 6
|
141
|
+
if unsupported_puppet?(result['clientversion'])
|
142
|
+
Bolt::Logger.deprecate(
|
143
|
+
"unsupported_puppet",
|
144
|
+
"Detected unsupported Puppet agent version #{result['clientversion']} on target "\
|
145
|
+
"#{result.target}. Bolt supports Puppet agent 6.0.0 and higher."
|
146
|
+
)
|
147
|
+
end
|
148
|
+
|
138
149
|
inventory.add_facts(result.target, result.value)
|
139
150
|
end
|
140
151
|
end
|
@@ -143,4 +154,18 @@ Puppet::Functions.create_function(:apply_prep) do
|
|
143
154
|
# Return nothing
|
144
155
|
nil
|
145
156
|
end
|
157
|
+
|
158
|
+
# Returns true if the client's major version is < 6.
|
159
|
+
#
|
160
|
+
private def unsupported_puppet?(client_version)
|
161
|
+
if client_version.nil?
|
162
|
+
false
|
163
|
+
else
|
164
|
+
begin
|
165
|
+
Integer(client_version.split('.').first) < 6
|
166
|
+
rescue StandardError
|
167
|
+
false
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
146
171
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'bolt/error'
|
4
|
+
require 'json'
|
4
5
|
|
5
6
|
# Runs a command on the given set of targets and returns the result from each command execution.
|
6
7
|
# This function does nothing if the list of targets is empty.
|
@@ -13,7 +14,7 @@ Puppet::Functions.create_function(:run_command) do
|
|
13
14
|
# @param options A hash of additional options.
|
14
15
|
# @option options [Boolean] _catch_errors Whether to catch raised errors.
|
15
16
|
# @option options [String] _run_as User to run as using privilege escalation.
|
16
|
-
# @option options [Hash] _env_vars Map of environment variables to set
|
17
|
+
# @option options [Hash[String, Any]] _env_vars Map of environment variables to set
|
17
18
|
# @return A list of results, one entry per target.
|
18
19
|
# @example Run a command on targets
|
19
20
|
# run_command('hostname', $targets, '_catch_errors' => true)
|
@@ -31,7 +32,7 @@ Puppet::Functions.create_function(:run_command) do
|
|
31
32
|
# @param options A hash of additional options.
|
32
33
|
# @option options [Boolean] _catch_errors Whether to catch raised errors.
|
33
34
|
# @option options [String] _run_as User to run as using privilege escalation.
|
34
|
-
# @option options [Hash] _env_vars Map of environment variables to set
|
35
|
+
# @option options [Hash[String, Any]] _env_vars Map of environment variables to set
|
35
36
|
# @return A list of results, one entry per target.
|
36
37
|
# @example Run a command on targets
|
37
38
|
# run_command('hostname', $targets, 'Get hostname')
|
@@ -56,6 +57,23 @@ Puppet::Functions.create_function(:run_command) do
|
|
56
57
|
options = options.transform_keys { |k| k.sub(/^_/, '').to_sym }
|
57
58
|
options[:description] = description if description
|
58
59
|
|
60
|
+
# Ensure env_vars is a hash and that each hash value is transformed to JSON
|
61
|
+
# so we don't accidentally pass Ruby-style data to the target.
|
62
|
+
if options[:env_vars]
|
63
|
+
unless options[:env_vars].is_a?(Hash)
|
64
|
+
raise Bolt::ValidationError, "Option 'env_vars' must be a hash"
|
65
|
+
end
|
66
|
+
|
67
|
+
if (bad_keys = options[:env_vars].keys.reject { |k| k.is_a?(String) }).any?
|
68
|
+
raise Bolt::ValidationError,
|
69
|
+
"Keys for option 'env_vars' must be strings: #{bad_keys.map(&:inspect).join(', ')}"
|
70
|
+
end
|
71
|
+
|
72
|
+
options[:env_vars] = options[:env_vars].transform_values do |val|
|
73
|
+
[Array, Hash].include?(val.class) ? val.to_json : val
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
59
77
|
executor = Puppet.lookup(:bolt_executor)
|
60
78
|
inventory = Puppet.lookup(:bolt_inventory)
|
61
79
|
|
@@ -256,7 +256,7 @@ Puppet::Functions.create_function(:run_plan, Puppet::Functions::InternalFunction
|
|
256
256
|
if nodes_param
|
257
257
|
if params['nodes']
|
258
258
|
raise ArgumentError,
|
259
|
-
"A plan's 'nodes' parameter
|
259
|
+
"A plan's 'nodes' parameter can be specified as the second positional argument to " \
|
260
260
|
"run_plan(), but in that case 'nodes' must not be specified in the named arguments " \
|
261
261
|
"hash."
|
262
262
|
end
|
@@ -265,7 +265,7 @@ Puppet::Functions.create_function(:run_plan, Puppet::Functions::InternalFunction
|
|
265
265
|
elsif targets_param
|
266
266
|
if params['targets']
|
267
267
|
raise ArgumentError,
|
268
|
-
"A plan's 'targets' parameter
|
268
|
+
"A plan's 'targets' parameter can be specified as the second positional argument to " \
|
269
269
|
"run_plan(), but in that case 'targets' must not be specified in the named arguments " \
|
270
270
|
"hash."
|
271
271
|
end
|
@@ -6,19 +6,24 @@
|
|
6
6
|
# > **Note:** Not available in apply block
|
7
7
|
Puppet::Functions.create_function(:run_script, Puppet::Functions::InternalFunction) do
|
8
8
|
# Run a script.
|
9
|
-
# @param script Path to a script to run on target.
|
9
|
+
# @param script Path to a script to run on target. Can be an absolute path or a modulename/filename selector for a
|
10
10
|
# file in $MODULEROOT/files.
|
11
11
|
# @param targets A pattern identifying zero or more targets. See {get_targets} for accepted patterns.
|
12
12
|
# @param options A hash of additional options.
|
13
13
|
# @option options [Array[String]] arguments An array of arguments to be passed to the script.
|
14
|
+
# Cannot be used with `pwsh_params`.
|
15
|
+
# @option options [Hash] pwsh_params Map of named parameters to pass to a PowerShell script.
|
16
|
+
# Cannot be used with `arguments`.
|
14
17
|
# @option options [Boolean] _catch_errors Whether to catch raised errors.
|
15
18
|
# @option options [String] _run_as User to run as using privilege escalation.
|
16
|
-
# @option options [Hash] _env_vars Map of environment variables to set
|
19
|
+
# @option options [Hash[String, Any]] _env_vars Map of environment variables to set.
|
17
20
|
# @return A list of results, one entry per target.
|
18
21
|
# @example Run a local script on Linux targets as 'root'
|
19
22
|
# run_script('/var/tmp/myscript', $targets, '_run_as' => 'root')
|
20
23
|
# @example Run a module-provided script with arguments
|
21
24
|
# run_script('iis/setup.ps1', $target, 'arguments' => ['/u', 'Administrator'])
|
25
|
+
# @example Pass named parameters to a PowerShell script
|
26
|
+
# run_script('iis/setup.ps1', $target, 'pwsh_params' => { 'User' => 'Administrator' })
|
22
27
|
dispatch :run_script do
|
23
28
|
scope_param
|
24
29
|
param 'String[1]', :script
|
@@ -28,15 +33,18 @@ Puppet::Functions.create_function(:run_script, Puppet::Functions::InternalFuncti
|
|
28
33
|
end
|
29
34
|
|
30
35
|
# Run a script, logging the provided description.
|
31
|
-
# @param script Path to a script to run on target.
|
36
|
+
# @param script Path to a script to run on target. Can be an absolute path or a modulename/filename selector for a
|
32
37
|
# file in $MODULEROOT/files.
|
33
38
|
# @param targets A pattern identifying zero or more targets. See {get_targets} for accepted patterns.
|
34
39
|
# @param description A description to be output when calling this function.
|
35
40
|
# @param options A hash of additional options.
|
36
41
|
# @option options [Array[String]] arguments An array of arguments to be passed to the script.
|
42
|
+
# Cannot be used with `pwsh_params`.
|
43
|
+
# @option options [Hash] pwsh_params Map of named parameters to pass to a PowerShell script.
|
44
|
+
# Cannot be used with `arguments`.
|
37
45
|
# @option options [Boolean] _catch_errors Whether to catch raised errors.
|
38
46
|
# @option options [String] _run_as User to run as using privilege escalation.
|
39
|
-
# @option options [Hash] _env_vars Map of environment variables to set
|
47
|
+
# @option options [Hash[String, Any]] _env_vars Map of environment variables to set.
|
40
48
|
# @return A list of results, one entry per target.
|
41
49
|
# @example Run a script
|
42
50
|
# run_script('/var/tmp/myscript', $targets, 'Downloading my application')
|
@@ -59,9 +67,40 @@ Puppet::Functions.create_function(:run_script, Puppet::Functions::InternalFuncti
|
|
59
67
|
.from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, action: 'run_script')
|
60
68
|
end
|
61
69
|
|
70
|
+
if options.key?('arguments') && options.key?('pwsh_params')
|
71
|
+
raise Bolt::ValidationError, "Cannot specify both 'arguments' and 'pwsh_params'"
|
72
|
+
end
|
73
|
+
|
74
|
+
if options.key?('pwsh_params') && !options['pwsh_params'].is_a?(Hash)
|
75
|
+
raise Bolt::ValidationError, "Option 'pwsh_params' must be a hash"
|
76
|
+
end
|
77
|
+
|
78
|
+
if options.key?('arguments') && !options['arguments'].is_a?(Array)
|
79
|
+
raise Bolt::ValidationError, "Option 'arguments' must be an array"
|
80
|
+
end
|
81
|
+
|
62
82
|
arguments = options['arguments'] || []
|
83
|
+
pwsh_params = options['pwsh_params']
|
63
84
|
options = options.select { |opt| opt.start_with?('_') }.transform_keys { |k| k.sub(/^_/, '').to_sym }
|
64
85
|
options[:description] = description if description
|
86
|
+
options[:pwsh_params] = pwsh_params if pwsh_params
|
87
|
+
|
88
|
+
# Ensure env_vars is a hash and that each hash value is transformed to JSON
|
89
|
+
# so we don't accidentally pass Ruby-style data to the target.
|
90
|
+
if options[:env_vars]
|
91
|
+
unless options[:env_vars].is_a?(Hash)
|
92
|
+
raise Bolt::ValidationError, "Option 'env_vars' must be a hash"
|
93
|
+
end
|
94
|
+
|
95
|
+
if (bad_keys = options[:env_vars].keys.reject { |k| k.is_a?(String) }).any?
|
96
|
+
raise Bolt::ValidationError,
|
97
|
+
"Keys for option 'env_vars' must be strings: #{bad_keys.map(&:inspect).join(', ')}"
|
98
|
+
end
|
99
|
+
|
100
|
+
options[:env_vars] = options[:env_vars].transform_values do |val|
|
101
|
+
[Array, Hash].include?(val.class) ? val.to_json : val
|
102
|
+
end
|
103
|
+
end
|
65
104
|
|
66
105
|
executor = Puppet.lookup(:bolt_executor)
|
67
106
|
inventory = Puppet.lookup(:bolt_inventory)
|
@@ -80,7 +119,7 @@ Puppet::Functions.create_function(:run_script, Puppet::Functions::InternalFuncti
|
|
80
119
|
Puppet::Pops::Issues::NOT_A_FILE, file: script
|
81
120
|
)
|
82
121
|
end
|
83
|
-
|
122
|
+
executor.report_file_source(self.class.name, script)
|
84
123
|
# Ensure that given targets are all Target instances)
|
85
124
|
targets = inventory.get_targets(targets)
|
86
125
|
|
@@ -76,7 +76,7 @@ Puppet::Functions.create_function(:upload_file, Puppet::Functions::InternalFunct
|
|
76
76
|
Puppet::Pops::Issues::NO_SUCH_FILE_OR_DIRECTORY, file: source
|
77
77
|
)
|
78
78
|
end
|
79
|
-
|
79
|
+
executor.report_file_source(self.class.name, source)
|
80
80
|
# Ensure that that given targets are all Target instances
|
81
81
|
targets = inventory.get_targets(targets)
|
82
82
|
if targets.empty?
|
@@ -2,7 +2,11 @@
|
|
2
2
|
|
3
3
|
require 'bolt/util'
|
4
4
|
|
5
|
-
# Wait until all targets accept connections.
|
5
|
+
# Wait until all targets accept connections. This function allows a plan execution to wait for a customizable
|
6
|
+
# amount of time via the `wait_time` option until a target connection can be reestablished. The plan proceeds
|
7
|
+
# to the next step if the connection fails to reconnect in the time specified (default: 120 seconds). A typical
|
8
|
+
# use case for this function is if your plan reboots a remote host and the plan needs to wait for the host to reconnect
|
9
|
+
# before it continues to the next step.
|
6
10
|
#
|
7
11
|
# > **Note:** Not available in apply block
|
8
12
|
Puppet::Functions.create_function(:wait_until_available) do
|
@@ -10,8 +14,8 @@ Puppet::Functions.create_function(:wait_until_available) do
|
|
10
14
|
# @param targets A pattern identifying zero or more targets. See {get_targets} for accepted patterns.
|
11
15
|
# @param options A hash of additional options.
|
12
16
|
# @option options [String] description A description for logging. (default: 'wait until available')
|
13
|
-
# @option options [Numeric] wait_time The time to wait. (default: 120)
|
14
|
-
# @option options [Numeric] retry_interval The interval to wait before retrying. (default: 1)
|
17
|
+
# @option options [Numeric] wait_time The time to wait, in seconds. (default: 120)
|
18
|
+
# @option options [Numeric] retry_interval The interval to wait before retrying, in seconds. (default: 1)
|
15
19
|
# @option options [Boolean] _catch_errors Whether to catch raised errors.
|
16
20
|
# @return A list of results, one entry per target. Successful results have no value.
|
17
21
|
# @example Wait for targets
|
@@ -17,7 +17,8 @@ Puppet::Functions.create_function(:'file::read', Puppet::Functions::InternalFunc
|
|
17
17
|
|
18
18
|
def read(scope, filename)
|
19
19
|
# Send Analytics Report
|
20
|
-
Puppet.lookup(:bolt_executor) {}
|
20
|
+
executor = Puppet.lookup(:bolt_executor) {}
|
21
|
+
executor&.report_function_call(self.class.name)
|
21
22
|
|
22
23
|
found = Puppet::Parser::Files.find_file(filename, scope.compiler.environment)
|
23
24
|
unless found && Puppet::FileSystem.exist?(found)
|
@@ -25,7 +26,7 @@ Puppet::Functions.create_function(:'file::read', Puppet::Functions::InternalFunc
|
|
25
26
|
Puppet::Pops::Issues::NO_SUCH_FILE_OR_DIRECTORY, file: filename
|
26
27
|
)
|
27
28
|
end
|
28
|
-
|
29
|
+
executor&.report_file_source(self.class.name, filename)
|
29
30
|
File.read(found)
|
30
31
|
end
|
31
32
|
end
|
@@ -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
|