bolt 3.0.1 → 3.6.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/analytics.rb +4 -8
- data/lib/bolt/apply_result.rb +1 -1
- data/lib/bolt/bolt_option_parser.rb +6 -3
- data/lib/bolt/cli.rb +123 -37
- data/lib/bolt/config.rb +15 -7
- data/lib/bolt/config/options.rb +62 -12
- data/lib/bolt/config/transport/lxd.rb +23 -0
- data/lib/bolt/config/transport/options.rb +8 -1
- data/lib/bolt/config/transport/podman.rb +33 -0
- data/lib/bolt/container_result.rb +105 -0
- data/lib/bolt/error.rb +15 -0
- data/lib/bolt/executor.rb +37 -18
- 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 +259 -90
- data/lib/bolt/outputter/json.rb +3 -1
- 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/plugin.rb +13 -11
- 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 +2 -126
- data/lib/bolt/transport/docker/connection.rb +81 -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/podman.rb +19 -0
- data/lib/bolt/transport/podman/connection.rb +98 -0
- data/lib/bolt/transport/ssh/connection.rb +1 -1
- data/lib/bolt/transport/winrm/connection.rb +1 -1
- data/lib/bolt/util.rb +42 -0
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/transport_app.rb +64 -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 +91 -7
- data/modules/puppet_connect/plans/test_input_data.pp +65 -7
- metadata +12 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa3e5ea7d868b032557568e9635fcf159f00b81e4961dce4032246cc150a7c16
|
4
|
+
data.tar.gz: 0e9fada8a0518ab174412e21ec843091272cb0afe87980703ebd6d8ed91002dd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 66d8df12e0142b6d5872a40f7c0d97b0438c833e4681be6646e17b85496c3a9e1148ff0a2ff34572e0ce788861d928c406dddcb97feb5281ac0d7eb2d7d14ead
|
7
|
+
data.tar.gz: f6dafaa37a4af7633610e26cc084d69c865f0b8df18221d407f2ee077e58e0a582e88cccf49d3a590e7984d56d8ac467ee8704e6ac0e60cc7e37b1a846396d26
|
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
|
-
mod 'puppetlabs-aws_inventory', '0.
|
35
|
+
mod 'puppetlabs-aws_inventory', '0.7.0'
|
35
36
|
mod 'puppetlabs-azure_inventory', '0.5.0'
|
36
|
-
mod 'puppetlabs-gcloud_inventory', '0.
|
37
|
-
mod 'puppetlabs-http_request', '0.2.
|
37
|
+
mod 'puppetlabs-gcloud_inventory', '0.3.0'
|
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
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Puppet::DataTypes.create_type('ContainerResult') do
|
4
|
+
interface <<-PUPPET
|
5
|
+
attributes => {
|
6
|
+
'value' => Hash[String[1], Data],
|
7
|
+
},
|
8
|
+
functions => {
|
9
|
+
'[]' => Callable[[String[1]], Data],
|
10
|
+
error => Callable[[], Optional[Error]],
|
11
|
+
ok => Callable[[], Boolean],
|
12
|
+
status => Callable[[], String],
|
13
|
+
stdout => Callable[[], String],
|
14
|
+
stderr => Callable[[], String],
|
15
|
+
to_data => Callable[[], Hash]
|
16
|
+
}
|
17
|
+
PUPPET
|
18
|
+
|
19
|
+
load_file('bolt/container_result')
|
20
|
+
|
21
|
+
# Needed for Puppet to recognize Bolt::ContainerResult as a Puppet object when deserializing
|
22
|
+
Bolt::ContainerResult.include(Puppet::Pops::Types::PuppetObject)
|
23
|
+
implementation_class Bolt::ContainerResult
|
24
|
+
end
|
@@ -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,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
|
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bolt/container_result'
|
4
|
+
require 'bolt/error'
|
5
|
+
require 'bolt/util'
|
6
|
+
|
7
|
+
# Run a container and return its output to stdout and stderr.
|
8
|
+
#
|
9
|
+
# > **Note:** Not available in apply block
|
10
|
+
Puppet::Functions.create_function(:run_container) do
|
11
|
+
# Run a container.
|
12
|
+
# @param image The name of the image to run.
|
13
|
+
# @param options A hash of additional options.
|
14
|
+
# @option options [Boolean] _catch_errors Whether to catch raised errors.
|
15
|
+
# @option options [String] cmd A command to run in the container.
|
16
|
+
# @option options [Hash[String, Data]] env_vars Map of environment variables to set.
|
17
|
+
# @option options [Hash[Integer, Integer]] ports A map of container ports to
|
18
|
+
# publish. Keys are the host port, values are the corresponding container
|
19
|
+
# port.
|
20
|
+
# @option options [Boolean] rm Whether to remove the container once it exits.
|
21
|
+
# @option options [Hash[String, String]] volumes A map of absolute paths on
|
22
|
+
# the host to absolute paths on the remote to mount.
|
23
|
+
# @option options [String] workdir The working directory within the container.
|
24
|
+
# @return Output from the container.
|
25
|
+
# @example Run Nginx proxy manager
|
26
|
+
# run_container('jc21/nginx-proxy-manager', 'ports' => { 80 => 80, 81 => 81, 443 => 443 })
|
27
|
+
dispatch :run_container do
|
28
|
+
param 'String[1]', :image
|
29
|
+
optional_param 'Hash[String[1], Any]', :options
|
30
|
+
return_type 'ContainerResult'
|
31
|
+
end
|
32
|
+
|
33
|
+
def run_container(image, options = {})
|
34
|
+
unless Puppet[:tasks]
|
35
|
+
raise Puppet::ParseErrorWithIssue
|
36
|
+
.from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, action: 'run_container')
|
37
|
+
end
|
38
|
+
|
39
|
+
# Send Analytics Report
|
40
|
+
executor = Puppet.lookup(:bolt_executor)
|
41
|
+
executor.report_function_call(self.class.name)
|
42
|
+
|
43
|
+
options = options.transform_keys { |k| k.sub(/^_/, '').to_sym }
|
44
|
+
validate_options(options)
|
45
|
+
|
46
|
+
if options.key?(:env_vars)
|
47
|
+
options[:env_vars] = options[:env_vars].transform_values do |val|
|
48
|
+
[Array, Hash].include?(val.class) ? val.to_json : val
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
if options[:ports]
|
53
|
+
ports = options[:ports].each_with_object([]) do |(host_port, container_port), acc|
|
54
|
+
acc << "-p"
|
55
|
+
acc << "#{host_port}:#{container_port}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
if options[:volumes]
|
60
|
+
volumes = options[:volumes].each_with_object([]) do |(host_path, remote_path), acc|
|
61
|
+
begin
|
62
|
+
FileUtils.mkdir_p(host_path)
|
63
|
+
rescue StandardError => e
|
64
|
+
message = "Unable to create host volume directory #{host_path}: #{e.message}"
|
65
|
+
raise Bolt::Error.new(message, 'bolt/file-error')
|
66
|
+
end
|
67
|
+
acc << "-v"
|
68
|
+
acc << "#{host_path}:#{remote_path}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Run the container
|
73
|
+
# `docker run` will automatically pull the image if it isn't already downloaded
|
74
|
+
cmd = %w[run]
|
75
|
+
cmd += Bolt::Util.format_env_vars_for_cli(options[:env_vars]) if options[:env_vars]
|
76
|
+
cmd += volumes if volumes
|
77
|
+
cmd += ports if ports
|
78
|
+
cmd << "--rm" if options[:rm]
|
79
|
+
cmd += %W[-w #{options[:workdir]}] if options[:workdir]
|
80
|
+
cmd << image
|
81
|
+
cmd += Shellwords.shellsplit(options[:cmd]) if options[:cmd]
|
82
|
+
|
83
|
+
executor.publish_event(type: :container_start, image: image)
|
84
|
+
out, err, status = Bolt::Util.exec_docker(cmd)
|
85
|
+
|
86
|
+
o = out.is_a?(String) ? out.dup.force_encoding('utf-8') : out
|
87
|
+
e = err.is_a?(String) ? err.dup.force_encoding('utf-8') : err
|
88
|
+
|
89
|
+
unless status.exitstatus.zero?
|
90
|
+
result = Bolt::ContainerResult.from_exception(e,
|
91
|
+
status.exitstatus,
|
92
|
+
image,
|
93
|
+
position: Puppet::Pops::PuppetStack.top_of_stack)
|
94
|
+
executor.publish_event(type: :container_finish, result: result)
|
95
|
+
if options[:catch_errors]
|
96
|
+
return result
|
97
|
+
else
|
98
|
+
raise Bolt::ContainerFailure, result
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
value = { 'stdout' => o, 'stderr' => e, 'exit_code' => status.exitstatus }
|
103
|
+
result = Bolt::ContainerResult.new(value, object: image)
|
104
|
+
executor.publish_event(type: :container_finish, result: result)
|
105
|
+
result
|
106
|
+
end
|
107
|
+
|
108
|
+
def validate_options(options)
|
109
|
+
if options.key?(:env_vars)
|
110
|
+
ev = options[:env_vars]
|
111
|
+
unless ev.is_a?(Hash)
|
112
|
+
msg = "Option 'env_vars' must be a hash. Received #{ev} which is a #{ev.class}"
|
113
|
+
raise Bolt::ValidationError, msg
|
114
|
+
end
|
115
|
+
|
116
|
+
if (bad_keys = ev.keys.reject { |k| k.is_a?(String) }).any?
|
117
|
+
msg = "Keys for option 'env_vars' must be strings: #{bad_keys.map(&:inspect).join(', ')}"
|
118
|
+
raise Bolt::ValidationError, msg
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
if options.key?(:volumes)
|
123
|
+
volumes = options[:volumes]
|
124
|
+
unless volumes.is_a?(Hash)
|
125
|
+
msg = "Option 'volumes' must be a hash. Received #{volumes} which is a #{volumes.class}"
|
126
|
+
raise Bolt::ValidationError, msg
|
127
|
+
end
|
128
|
+
|
129
|
+
if (bad_vs = volumes.reject { |k, v| k.is_a?(String) && v.is_a?(String) }).any?
|
130
|
+
msg = "Option 'volumes' only accepts strings for keys and values. "\
|
131
|
+
"Received: #{bad_vs.map(&:inspect).join(', ')}"
|
132
|
+
raise Bolt::ValidationError, msg
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
if options.key?(:cmd) && !options[:cmd].is_a?(String)
|
137
|
+
cmd = options[:cmd]
|
138
|
+
msg = "Option 'cmd' must be a string. Received #{cmd} which is a #{cmd.class}"
|
139
|
+
raise Bolt::ValidationError, msg
|
140
|
+
end
|
141
|
+
|
142
|
+
if options.key?(:workdir) && !options[:workdir].is_a?(String)
|
143
|
+
wd = options[:workdir]
|
144
|
+
msg = "Option 'workdir' must be a string. Received #{wd} which is a #{wd.class}"
|
145
|
+
raise Bolt::ValidationError, msg
|
146
|
+
end
|
147
|
+
|
148
|
+
if options.key?(:ports)
|
149
|
+
ports = options[:ports]
|
150
|
+
unless ports.is_a?(Hash)
|
151
|
+
msg = "Option 'ports' must be a hash. Received #{ports} which is a #{ports.class}"
|
152
|
+
raise Bolt::ValidationError, msg
|
153
|
+
end
|
154
|
+
|
155
|
+
if (bad_ps = ports.reject { |k, v| k.is_a?(Integer) && v.is_a?(Integer) }).any?
|
156
|
+
msg = "Option 'ports' only accepts integers for keys and values. "\
|
157
|
+
"Received: #{bad_ps.map(&:inspect).join(', ')}"
|
158
|
+
raise Bolt::ValidationError, msg
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -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?
|
@@ -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
|