bolt 1.45.0 → 1.47.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/lib/bolt/config.rb +67 -6
- data/lib/bolt/outputter/human.rb +9 -6
- data/lib/bolt/plugin.rb +1 -1
- data/lib/bolt/result.rb +5 -4
- data/lib/bolt/target.rb +28 -0
- data/lib/bolt/transport/docker.rb +15 -1
- data/lib/bolt/transport/local.rb +23 -1
- data/lib/bolt/transport/local_windows.rb +18 -1
- data/lib/bolt/transport/orch.rb +11 -1
- data/lib/bolt/transport/remote.rb +4 -0
- data/lib/bolt/transport/ssh.rb +42 -2
- data/lib/bolt/transport/ssh/connection.rb +3 -3
- data/lib/bolt/transport/sudoable/connection.rb +9 -2
- data/lib/bolt/transport/winrm.rb +28 -4
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/transport_app.rb +19 -2
- data/libexec/apply_catalog.rb +2 -1
- data/libexec/custom_facts.rb +2 -1
- data/libexec/query_resources.rb +2 -1
- metadata +2 -3
- data/lib/bolt/plugin/install_agent.rb +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8d8c51d1ab9354303ccda2f36ebd31553fa0d8bf91adfe2e505e701cb8fc32eb
|
4
|
+
data.tar.gz: f092a00fc4ea73fea86b54e6d36f535e873a15d79d00bc85bae433b5fa6eace5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 741f8a885261e3b50413201fcfb0688d5a0c39a593a6225e9472c2822a114ae135be3b3fb30ee0433d0572ec4440f6cc0f505e10727098d55613b722fd9d86aa
|
7
|
+
data.tar.gz: 3bce21f684265bd81f23b2a182c6d3bdc858a742faa28591a2483836dea04c736282d0e3551cd54843c7276d85d2e27e1f0794e956a7d973f57493e18973311a
|
data/lib/bolt/config.rb
CHANGED
@@ -4,6 +4,7 @@ require 'etc'
|
|
4
4
|
require 'logging'
|
5
5
|
require 'pathname'
|
6
6
|
require 'bolt/boltdir'
|
7
|
+
require 'bolt/logger'
|
7
8
|
require 'bolt/transport/ssh'
|
8
9
|
require 'bolt/transport/winrm'
|
9
10
|
require 'bolt/transport/orch'
|
@@ -36,11 +37,69 @@ module Bolt
|
|
36
37
|
:puppetfile_config, :plugins, :plugin_hooks, :future, :trusted_external
|
37
38
|
attr_writer :modulepath
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
OPTIONS = {
|
41
|
+
"color" => "Whether to use colored output when printing messages to the console.",
|
42
|
+
"compile-concurrency" => "The maximum number of simultaneous manifest block compiles.",
|
43
|
+
"concurrency" => "The number of threads to use when executing on remote targets.",
|
44
|
+
"format" => "The format to use when printing results. Options are `human` and `json`.",
|
45
|
+
"hiera-config" => "The path to your Hiera config.",
|
46
|
+
"interpreters" => "A map of an extension name to the absolute path of an executable, "\
|
47
|
+
"enabling you to override the shebang defined in a task executable. The "\
|
48
|
+
"extension can optionally be specified with the `.` character (`.py` and "\
|
49
|
+
"`py` both map to a task executable `task.py`) and the extension is case "\
|
50
|
+
"sensitive. The transports that support interpreter configuration are "\
|
51
|
+
"`docker`, `local`, `ssh`, and `winrm`. When a target's name is `localhost`, "\
|
52
|
+
"Ruby tasks run with the Bolt Ruby interpreter by default.",
|
53
|
+
"inventoryfile" => "The path to a structured data inventory file used to refer to groups of "\
|
54
|
+
"targets on the command line and from plans.",
|
55
|
+
"log" => "The configuration of the logfile output. Configuration can be set for "\
|
56
|
+
"`console` and the path to a log file, such as `~/.puppetlabs/bolt/debug.log`.",
|
57
|
+
"modulepath" => "The module path for loading tasks and plan code. This is either an array "\
|
58
|
+
"of directories or a string containing a list of directories separated by the "\
|
59
|
+
"OS-specific PATH separator.",
|
60
|
+
"plugin_hooks" => "Which plugins a specific hook should use.",
|
61
|
+
"puppetfile" => "A map containing options for the `bolt puppetfile install` command.",
|
62
|
+
"save-rerun" => "Whether to update `.rerun.json` in the Bolt project directory. If "\
|
63
|
+
"your target names include passwords, set this value to `false` to avoid "\
|
64
|
+
"writing passwords to disk.",
|
65
|
+
"transport" => "The default transport to use when the transport for a target is not "\
|
66
|
+
"specified in the URL or inventory.",
|
67
|
+
"trusted-external-command" => "The path to an executable on the Bolt controller that can produce "\
|
68
|
+
"external trusted facts. **External trusted facts are experimental in both "\
|
69
|
+
"Puppet and Bolt and this API may change or be removed.**",
|
70
|
+
"future" => "Whether to use new, breaking changes. This allows testing if Bolt content "\
|
71
|
+
"is compatible with expected future behavior."
|
72
|
+
}.freeze
|
73
|
+
|
74
|
+
DEFAULT_OPTIONS = {
|
75
|
+
"color" => true,
|
76
|
+
"concurrency" => 100,
|
77
|
+
"compile-concurrency" => "Number of cores",
|
78
|
+
"format" => "human",
|
79
|
+
"hiera-config" => "Boltdir/hiera.yaml",
|
80
|
+
"inventoryfile" => "Boltdir/inventory.yaml",
|
81
|
+
"modulepath" => ["Boltdir/modules", "Boltdir/site-modules", "Boltdir/site"],
|
82
|
+
"save-rerun" => true,
|
83
|
+
"future" => false
|
84
|
+
}.freeze
|
85
|
+
|
86
|
+
PUPPETFILE_OPTIONS = {
|
87
|
+
"forge" => "A subsection that can have its own `proxy` setting to set an HTTP proxy for Forge operations "\
|
88
|
+
"only, and a `baseurl` setting to specify a different Forge host.",
|
89
|
+
"proxy" => "The HTTP proxy to use for Git and Forge operations."
|
90
|
+
}.freeze
|
91
|
+
|
92
|
+
LOG_OPTIONS = {
|
93
|
+
"append" => "Add output to an existing log file. Available only for logs output to a "\
|
94
|
+
"filepath.",
|
95
|
+
"level" => "The type of information in the log. Either `debug`, `info`, `notice`, "\
|
96
|
+
"`warn`, or `error`."
|
97
|
+
}.freeze
|
98
|
+
|
99
|
+
DEFAULT_LOG_OPTIONS = {
|
100
|
+
"append" => true,
|
101
|
+
"level" => "`warn` for console, `notice` for file"
|
102
|
+
}.freeze
|
44
103
|
|
45
104
|
def self.default
|
46
105
|
new(Bolt::Boltdir.new('.'), {})
|
@@ -194,8 +253,10 @@ module Bolt
|
|
194
253
|
@compile_concurrency = options[:'compile-concurrency'] if options[:'compile-concurrency']
|
195
254
|
|
196
255
|
TRANSPORTS.each_key do |transport|
|
256
|
+
# Get the options first since transport is modified in the next line
|
257
|
+
transport_options = TRANSPORTS[transport]::OPTIONS.keys.map(&:to_sym)
|
197
258
|
transport = @transports[transport]
|
198
|
-
|
259
|
+
transport_options.each do |key|
|
199
260
|
if options[key]
|
200
261
|
transport[key.to_s] = Bolt::Util.walk_keys(options[key], &:to_s)
|
201
262
|
end
|
data/lib/bolt/outputter/human.rb
CHANGED
@@ -96,12 +96,15 @@ module Bolt
|
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
|
-
if
|
100
|
-
|
101
|
-
|
99
|
+
# Only print results if there's something other than empty string and hash
|
100
|
+
if result.value.empty? || (result.value.keys == ['_output'] && !result.message?)
|
101
|
+
@stream.puts(indent(2, "#{result.action.capitalize} completed successfully with no result"))
|
102
|
+
else
|
103
|
+
# Only print messages that have something other than whitespace
|
104
|
+
if result.message?
|
105
|
+
@stream.puts(remove_trail(indent(2, result.message)))
|
106
|
+
end
|
102
107
|
|
103
|
-
# There is more information to output
|
104
|
-
if result.generic_value
|
105
108
|
# Use special handling if the result looks like a command or script result
|
106
109
|
if result.generic_value.keys == %w[stdout stderr exit_code]
|
107
110
|
unless result['stdout'].strip.empty?
|
@@ -112,7 +115,7 @@ module Bolt
|
|
112
115
|
@stream.puts(indent(2, "STDERR:"))
|
113
116
|
@stream.puts(indent(4, result['stderr']))
|
114
117
|
end
|
115
|
-
|
118
|
+
elsif result.generic_value.any?
|
116
119
|
@stream.puts(indent(2, ::JSON.pretty_generate(result.generic_value)))
|
117
120
|
end
|
118
121
|
end
|
data/lib/bolt/plugin.rb
CHANGED
@@ -142,7 +142,7 @@ module Bolt
|
|
142
142
|
plugins
|
143
143
|
end
|
144
144
|
|
145
|
-
RUBY_PLUGINS = %w[
|
145
|
+
RUBY_PLUGINS = %w[task pkcs7 prompt].freeze
|
146
146
|
BUILTIN_PLUGINS = %w[task terraform pkcs7 prompt vault aws_inventory puppetdb azure_inventory yaml].freeze
|
147
147
|
DEFAULT_PLUGIN_HOOKS = { 'puppet_library' => { 'plugin' => 'puppet_agent', 'stop_service' => true } }.freeze
|
148
148
|
|
data/lib/bolt/result.rb
CHANGED
@@ -95,7 +95,6 @@ module Bolt
|
|
95
95
|
@value = value || {}
|
96
96
|
@action = action
|
97
97
|
@object = object
|
98
|
-
@value_set = !value.nil?
|
99
98
|
if error && !error.is_a?(Hash)
|
100
99
|
raise "TODO: how did we get a string error"
|
101
100
|
end
|
@@ -107,6 +106,10 @@ module Bolt
|
|
107
106
|
@value['_output']
|
108
107
|
end
|
109
108
|
|
109
|
+
def message?
|
110
|
+
message && !message.strip.empty?
|
111
|
+
end
|
112
|
+
|
110
113
|
def status_hash
|
111
114
|
# DEPRECATION: node in status hashes is deprecated and should be removed in 2.0
|
112
115
|
base = {
|
@@ -121,9 +124,7 @@ module Bolt
|
|
121
124
|
end
|
122
125
|
|
123
126
|
def generic_value
|
124
|
-
|
125
|
-
value.reject { |k, _| %w[_error _output].include? k }
|
126
|
-
end
|
127
|
+
value.reject { |k, _| %w[_error _output].include? k }
|
127
128
|
end
|
128
129
|
|
129
130
|
def eql?(other)
|
data/lib/bolt/target.rb
CHANGED
@@ -157,9 +157,37 @@ module Bolt
|
|
157
157
|
|
158
158
|
# Satisfies the Puppet datatypes API
|
159
159
|
def self.from_asserted_hash(hash)
|
160
|
+
if hash['uri'] && hash['options']
|
161
|
+
logger = Logging.logger[self]
|
162
|
+
msg = <<~MSG
|
163
|
+
#{Puppet::Pops::PuppetStack.top_of_stack.join(':')}
|
164
|
+
Deprecation Warning: Starting with Bolt 2.0, using 'Target.new' with an 'options' hash key will no
|
165
|
+
will no longer be supported. Use 'Target.new(<config>)', where 'config' is a hash with the same
|
166
|
+
structure used to define targets in the inventory V2 file. For more information see
|
167
|
+
https://puppet.com/docs/bolt/latest/writing_plans.html#creating-target-objects
|
168
|
+
MSG
|
169
|
+
logger.warn(msg)
|
170
|
+
end
|
171
|
+
|
160
172
|
new(hash['uri'], hash['options'])
|
161
173
|
end
|
162
174
|
|
175
|
+
def self.from_asserted_args(uri, options = nil)
|
176
|
+
if options
|
177
|
+
logger = Logging.logger[self]
|
178
|
+
msg = <<~MSG
|
179
|
+
#{Puppet::Pops::PuppetStack.top_of_stack.join(':')}
|
180
|
+
Deprecation Warning: Starting with Bolt 2.0, 'Target.new(<uri>, <options>)' will no
|
181
|
+
longer be supported. Use 'Target.new(<config>)', where 'config' is a hash with the same
|
182
|
+
structure used to define targets in the inventory V2 file. For more information see
|
183
|
+
https://puppet.com/docs/bolt/latest/writing_plans.html#creating-target-objects
|
184
|
+
MSG
|
185
|
+
logger.warn(msg)
|
186
|
+
end
|
187
|
+
|
188
|
+
new(uri, options)
|
189
|
+
end
|
190
|
+
|
163
191
|
# URI can be passes as nil
|
164
192
|
def initialize(uri, options = nil)
|
165
193
|
# lazy-load expensive gem code
|
@@ -7,8 +7,22 @@ require 'bolt/transport/base'
|
|
7
7
|
module Bolt
|
8
8
|
module Transport
|
9
9
|
class Docker < Base
|
10
|
+
OPTIONS = {
|
11
|
+
"host" => "Host name.",
|
12
|
+
"interpreters" => "A map of an extension name to the absolute path of an executable, "\
|
13
|
+
"enabling you to override the shebang defined in a task executable. The "\
|
14
|
+
"extension can optionally be specified with the `.` character (`.py` and "\
|
15
|
+
"`py` both map to a task executable `task.py`) and the extension is case "\
|
16
|
+
"sensitive. When a target's name is `localhost`, Ruby tasks run with the "\
|
17
|
+
"Bolt Ruby interpreter by default.",
|
18
|
+
"service-url" => "URL of the Docker host used for API requests.",
|
19
|
+
"shell-command" => "A shell command to wrap any Docker exec commands in, such as `bash -lc`.",
|
20
|
+
"tmpdir" => "The directory to upload and execute temporary files on the target.",
|
21
|
+
"tty" => "Whether to enable tty on exec commands."
|
22
|
+
}.freeze
|
23
|
+
|
10
24
|
def self.options
|
11
|
-
|
25
|
+
OPTIONS.keys
|
12
26
|
end
|
13
27
|
|
14
28
|
def provided_features
|
data/lib/bolt/transport/local.rb
CHANGED
@@ -3,8 +3,30 @@
|
|
3
3
|
module Bolt
|
4
4
|
module Transport
|
5
5
|
class Local < Sudoable
|
6
|
+
OPTIONS = {
|
7
|
+
"interpreters" => "A map of an extension name to the absolute path of an executable, "\
|
8
|
+
"enabling you to override the shebang defined in a task executable. The "\
|
9
|
+
"extension can optionally be specified with the `.` character (`.py` and "\
|
10
|
+
"`py` both map to a task executable `task.py`) and the extension is case "\
|
11
|
+
"sensitive. When a target's name is `localhost`, Ruby tasks run with the "\
|
12
|
+
"Bolt Ruby interpreter by default.",
|
13
|
+
"run-as" => "A different user to run commands as after login.",
|
14
|
+
"run-as-command" => "The command to elevate permissions. Bolt appends the user and command "\
|
15
|
+
"strings to the configured `run-as-command` before running it on the target. "\
|
16
|
+
"This command must not require an interactive password prompt, and the "\
|
17
|
+
"`sudo-password` option is ignored when `run-as-command` is specified. The "\
|
18
|
+
"`run-as-command` must be specified as an array.",
|
19
|
+
"sudo-executable" => "The executable to use when escalating to the configured `run-as` user. This "\
|
20
|
+
"is useful when you want to escalate using the configured `sudo-password`, since "\
|
21
|
+
"`run-as-command` does not use `sudo-password` or support prompting. The command "\
|
22
|
+
"executed on the target is `<sudo-executable> -S -u <user> -p custom_bolt_prompt "\
|
23
|
+
"<command>`. **This option is experimental.**",
|
24
|
+
"sudo-password" => "Password to use when changing users via `run-as`.",
|
25
|
+
"tmpdir" => "The directory to copy and execute temporary files."
|
26
|
+
}.freeze
|
27
|
+
|
6
28
|
def self.options
|
7
|
-
|
29
|
+
OPTIONS.keys
|
8
30
|
end
|
9
31
|
|
10
32
|
def provided_features
|
@@ -12,8 +12,25 @@ require 'bolt/util'
|
|
12
12
|
module Bolt
|
13
13
|
module Transport
|
14
14
|
class LocalWindows < Base
|
15
|
+
OPTIONS = {
|
16
|
+
"interpreters" => "A map of an extension name to the absolute path of an executable, "\
|
17
|
+
"enabling you to override the shebang defined in a task executable. The "\
|
18
|
+
"extension can optionally be specified with the `.` character (`.py` and "\
|
19
|
+
"`py` both map to a task executable `task.py`) and the extension is case "\
|
20
|
+
"sensitive. When a target's name is `localhost`, Ruby tasks run with the "\
|
21
|
+
"Bolt Ruby interpreter by default.",
|
22
|
+
"run-as" => "A different user to run commands as after login.",
|
23
|
+
"run-as-command" => "The command to elevate permissions. Bolt appends the user and command "\
|
24
|
+
"strings to the configured `run-as-command` before running it on the target. "\
|
25
|
+
"This command must not require an interactive password prompt, and the "\
|
26
|
+
"`sudo-password` option is ignored when `run-as-command` is specified. The "\
|
27
|
+
"`run-as-command` must be specified as an array.",
|
28
|
+
"sudo-password" => "Password to use when changing users via `run-as`.",
|
29
|
+
"tmpdir" => "The directory to copy and execute temporary files."
|
30
|
+
}.freeze
|
31
|
+
|
15
32
|
def self.options
|
16
|
-
|
33
|
+
OPTIONS.keys
|
17
34
|
end
|
18
35
|
|
19
36
|
def provided_features
|
data/lib/bolt/transport/orch.rb
CHANGED
@@ -21,8 +21,18 @@ module Bolt
|
|
21
21
|
|
22
22
|
attr_writer :plan_context
|
23
23
|
|
24
|
+
OPTIONS = {
|
25
|
+
"cacert" => "The path to the CA certificate.",
|
26
|
+
"host" => "Host name.",
|
27
|
+
"job-poll-interval" => "Set interval to poll orchestrator for job status.",
|
28
|
+
"job-poll-timeout" => "Set time to wait for orchestrator job status.",
|
29
|
+
"service-url" => "The URL of the orchestrator API.",
|
30
|
+
"task-environment" => "The environment the orchestrator loads task code from.",
|
31
|
+
"token-file" => "The path to the token file."
|
32
|
+
}.freeze
|
33
|
+
|
24
34
|
def self.options
|
25
|
-
|
35
|
+
OPTIONS.keys
|
26
36
|
end
|
27
37
|
|
28
38
|
def self.default_options
|
@@ -6,6 +6,10 @@ require 'bolt/transport/base'
|
|
6
6
|
module Bolt
|
7
7
|
module Transport
|
8
8
|
class Remote < Base
|
9
|
+
OPTIONS = {
|
10
|
+
"run-on" => "The proxy target that the task executes on."
|
11
|
+
}.freeze
|
12
|
+
|
9
13
|
# The options for the remote transport not defined.
|
10
14
|
def self.filter_options(unfiltered)
|
11
15
|
unfiltered
|
data/lib/bolt/transport/ssh.rb
CHANGED
@@ -8,9 +8,49 @@ require 'shellwords'
|
|
8
8
|
module Bolt
|
9
9
|
module Transport
|
10
10
|
class SSH < Sudoable
|
11
|
+
OPTIONS = {
|
12
|
+
"connect-timeout" => "How long to wait when establishing connections.",
|
13
|
+
"disconnect-timeout" => "How long to wait before force-closing a connection.",
|
14
|
+
"host" => "Host name.",
|
15
|
+
"host-key-check" => "Whether to perform host key validation when connecting.",
|
16
|
+
"interpreters" => "A map of an extension name to the absolute path of an executable, "\
|
17
|
+
"enabling you to override the shebang defined in a task executable. The "\
|
18
|
+
"extension can optionally be specified with the `.` character (`.py` and "\
|
19
|
+
"`py` both map to a task executable `task.py`) and the extension is case "\
|
20
|
+
"sensitive. When a target's name is `localhost`, Ruby tasks run with the "\
|
21
|
+
"Bolt Ruby interpreter by default.",
|
22
|
+
"password" => "Login password.",
|
23
|
+
"port" => "Connection port.",
|
24
|
+
"private-key" => "Either the path to the private key file to use for authentication, or a "\
|
25
|
+
"hash with the key `key-data` and the contents of the private key.",
|
26
|
+
"proxyjump" => "A jump host to proxy connections through, and an optional user to "\
|
27
|
+
"connect with.",
|
28
|
+
"run-as" => "A different user to run commands as after login.",
|
29
|
+
"run-as-command" => "The command to elevate permissions. Bolt appends the user and command "\
|
30
|
+
"strings to the configured `run-as-command` before running it on the "\
|
31
|
+
"target. This command must not require an interactive password prompt, "\
|
32
|
+
"and the `sudo-password` option is ignored when `run-as-command` is "\
|
33
|
+
"specified. The `run-as-command` must be specified as an array.",
|
34
|
+
"script-dir" => "The subdirectory of the tmpdir to use in place of a randomized "\
|
35
|
+
"subdirectory for uploading and executing temporary files on the "\
|
36
|
+
"target. It's expected that this directory already exists as a subdir "\
|
37
|
+
"of tmpdir, which is either configured or defaults to `/tmp`.",
|
38
|
+
"sudo-executable" => "The executable to use when escalating to the configured `run-as` "\
|
39
|
+
"user. This is useful when you want to escalate using the configured "\
|
40
|
+
"`sudo-password`, since `run-as-command` does not use `sudo-password` "\
|
41
|
+
"or support prompting. The command executed on the target is "\
|
42
|
+
"`<sudo-executable> -S -u <user> -p custom_bolt_prompt <command>`. "\
|
43
|
+
"**This option is experimental.**",
|
44
|
+
"sudo-password" => "Password to use when changing users via `run-as`.",
|
45
|
+
"tmpdir" => "The directory to upload and execute temporary files on the target.",
|
46
|
+
"tty" => "Request a pseudo tty for the session. This option is generally "\
|
47
|
+
"only used in conjunction with the `run-as` option when the sudoers "\
|
48
|
+
"policy requires a `tty`.",
|
49
|
+
"user" => "Login user."
|
50
|
+
}.freeze
|
51
|
+
|
11
52
|
def self.options
|
12
|
-
|
13
|
-
connect-timeout disconnect-timeout tmpdir script-dir run-as tty run-as-command proxyjump interpreters]
|
53
|
+
OPTIONS.keys
|
14
54
|
end
|
15
55
|
|
16
56
|
def self.default_options
|
@@ -36,7 +36,7 @@ module Bolt
|
|
36
36
|
|
37
37
|
@sudo_password = @target.options['sudo-password']
|
38
38
|
# rubocop:disable Style/GlobalVars
|
39
|
-
@sudo_password ||= @target.
|
39
|
+
@sudo_password ||= @target.password if $future
|
40
40
|
# rubocop:enable Style/GlobalVars
|
41
41
|
|
42
42
|
if target.options['private-key']&.instance_of?(String)
|
@@ -197,13 +197,13 @@ module Bolt
|
|
197
197
|
if escalate
|
198
198
|
if use_sudo
|
199
199
|
sudo_exec = target.options['sudo-executable'] || "sudo"
|
200
|
-
sudo_flags = [sudo_exec, "-S", "-u", run_as, "-p", Sudoable.sudo_prompt]
|
200
|
+
sudo_flags = [sudo_exec, "-S", "-H", "-u", run_as, "-p", Sudoable.sudo_prompt]
|
201
201
|
sudo_flags += ["-E"] if options[:environment]
|
202
202
|
sudo_str = Shellwords.shelljoin(sudo_flags)
|
203
203
|
else
|
204
204
|
sudo_str = Shellwords.shelljoin(@target.options['run-as-command'] + [run_as])
|
205
205
|
end
|
206
|
-
command_str = build_sudoable_command_str(command_str, sudo_str, @sudo_id, options)
|
206
|
+
command_str = build_sudoable_command_str(command_str, sudo_str, @sudo_id, options.merge(reset_cwd: true))
|
207
207
|
end
|
208
208
|
|
209
209
|
# Including the environment declarations in the shelljoin will escape
|
@@ -77,17 +77,24 @@ module Bolt
|
|
77
77
|
# a random string is echoed to stderr indicating that the stdin is available
|
78
78
|
# for task input data because the sudo password has already either been
|
79
79
|
# provided on stdin or was not needed.
|
80
|
-
def prepend_sudo_success(sudo_id, command_str)
|
80
|
+
def prepend_sudo_success(sudo_id, command_str, reset_cwd)
|
81
|
+
command_str = "cd && #{command_str}" if reset_cwd
|
81
82
|
"sh -c 'echo #{sudo_id} 1>&2; #{command_str}'"
|
82
83
|
end
|
83
84
|
|
85
|
+
def prepend_chdir(command_str)
|
86
|
+
"sh -c 'cd && #{command_str}'"
|
87
|
+
end
|
88
|
+
|
84
89
|
# A helper to build up a single string that contains all of the options for
|
85
90
|
# privilege escalation. A wrapper script is used to direct task input to stdin
|
86
91
|
# when a tty is allocated and thus we do not need to prepend_sudo_success when
|
87
92
|
# using the wrapper or when the task does not require stdin data.
|
88
93
|
def build_sudoable_command_str(command_str, sudo_str, sudo_id, options)
|
89
94
|
if options[:stdin] && !options[:wrapper]
|
90
|
-
"#{sudo_str} #{prepend_sudo_success(sudo_id, command_str)}"
|
95
|
+
"#{sudo_str} #{prepend_sudo_success(sudo_id, command_str, options[:reset_cwd])}"
|
96
|
+
elsif options[:reset_cwd]
|
97
|
+
"#{sudo_str} #{prepend_chdir(command_str)}"
|
91
98
|
else
|
92
99
|
"#{sudo_str} #{command_str}"
|
93
100
|
end
|
data/lib/bolt/transport/winrm.rb
CHANGED
@@ -7,11 +7,35 @@ require 'bolt/transport/powershell'
|
|
7
7
|
module Bolt
|
8
8
|
module Transport
|
9
9
|
class WinRM < Base
|
10
|
+
OPTIONS = {
|
11
|
+
"cacert" => "The path to the CA certificate.",
|
12
|
+
"connect-timeout" => "How long Bolt should wait when establishing connections.",
|
13
|
+
"extensions" => "List of file extensions that are accepted for scripts or tasks. "\
|
14
|
+
"Scripts with these file extensions rely on the target's file type "\
|
15
|
+
"association to run. For example, if Python is installed on the system, "\
|
16
|
+
"a `.py` script runs with `python.exe`. The extensions `.ps1`, `.rb`, and "\
|
17
|
+
"`.pp` are always allowed and run via hard-coded executables.",
|
18
|
+
"file-protocol" => "Which file transfer protocol to use. Either `winrm` or `smb`. Using `smb` is "\
|
19
|
+
"recommended for large file transfers.",
|
20
|
+
"host" => "Host name.",
|
21
|
+
"interpreters" => "A map of an extension name to the absolute path of an executable, "\
|
22
|
+
"enabling you to override the shebang defined in a task executable. The "\
|
23
|
+
"extension can optionally be specified with the `.` character (`.py` and "\
|
24
|
+
"`py` both map to a task executable `task.py`) and the extension is case "\
|
25
|
+
"sensitive. When a target's name is `localhost`, Ruby tasks run with the "\
|
26
|
+
"Bolt Ruby interpreter by default.",
|
27
|
+
"password" => "Login password. **Required unless using Kerberos.**",
|
28
|
+
"port" => "Connection port.",
|
29
|
+
"realm" => "Kerberos realm (Active Directory domain) to authenticate against.",
|
30
|
+
"smb-port" => "With file-protocol set to smb, this is the port to establish a connection on.",
|
31
|
+
"ssl" => "When true, Bolt uses secure https connections for WinRM.",
|
32
|
+
"ssl-verify" => "When true, verifies the targets certificate matches the cacert.",
|
33
|
+
"tmpdir" => "The directory to upload and execute temporary files on the target.",
|
34
|
+
"user" => "Login user. **Required unless using Kerberos.**"
|
35
|
+
}.freeze
|
36
|
+
|
10
37
|
def self.options
|
11
|
-
|
12
|
-
host port user password connect-timeout ssl ssl-verify tmpdir
|
13
|
-
cacert extensions interpreters file-protocol smb-port realm
|
14
|
-
]
|
38
|
+
OPTIONS.keys
|
15
39
|
end
|
16
40
|
|
17
41
|
def self.default_options
|
data/lib/bolt/version.rb
CHANGED
@@ -200,6 +200,19 @@ module BoltServer
|
|
200
200
|
end
|
201
201
|
end
|
202
202
|
|
203
|
+
def pe_plan_info(pal, module_name, plan_name)
|
204
|
+
# Handle case where plan name is simply module name with special `init.pp` plan
|
205
|
+
plan_name = if plan_name == 'init' || plan_name.nil?
|
206
|
+
module_name
|
207
|
+
else
|
208
|
+
"#{module_name}::#{plan_name}"
|
209
|
+
end
|
210
|
+
plan_info = pal.get_plan_info(plan_name)
|
211
|
+
# Path to module is meaningless in PE
|
212
|
+
plan_info.delete('module')
|
213
|
+
plan_info
|
214
|
+
end
|
215
|
+
|
203
216
|
get '/' do
|
204
217
|
200
|
205
218
|
end
|
@@ -305,7 +318,7 @@ module BoltServer
|
|
305
318
|
# @param environment [String] the environment to fetch the plan from
|
306
319
|
get '/plans/:module_name/:plan_name' do
|
307
320
|
in_pe_pal_env(params['environment']) do |pal|
|
308
|
-
plan_info = pal
|
321
|
+
plan_info = pe_plan_info(pal, params[:module_name], params[:plan_name])
|
309
322
|
[200, plan_info.to_json]
|
310
323
|
end
|
311
324
|
end
|
@@ -318,7 +331,11 @@ module BoltServer
|
|
318
331
|
in_pe_pal_env(params['environment']) do |pal|
|
319
332
|
plans = pal.list_plans.flatten
|
320
333
|
if params['metadata']
|
321
|
-
plan_info = plans.each_with_object({})
|
334
|
+
plan_info = plans.each_with_object({}) do |full_name, acc|
|
335
|
+
# Break apart module name from plan name
|
336
|
+
module_name, plan_name = full_name.split('::', 2)
|
337
|
+
acc[full_name] = pe_plan_info(pal, module_name, plan_name)
|
338
|
+
end
|
322
339
|
[200, plan_info.to_json]
|
323
340
|
else
|
324
341
|
# We structure this array of plans to be an array of hashes so that it matches the structure
|
data/libexec/apply_catalog.rb
CHANGED
@@ -39,7 +39,8 @@ begin
|
|
39
39
|
|
40
40
|
Tempfile.open('plugins.tar.gz') do |plugins|
|
41
41
|
File.binwrite(plugins, Base64.decode64(args['plugins']))
|
42
|
-
|
42
|
+
user = Etc.getpwuid.nil? ? Etc.getlogin : Etc.getpwuid.name
|
43
|
+
Puppet::ModuleTool::Tar.instance.unpack(plugins, moduledir, user)
|
43
44
|
end
|
44
45
|
|
45
46
|
env = Puppet.lookup(:environments).get('production')
|
data/libexec/custom_facts.rb
CHANGED
@@ -21,7 +21,8 @@ Dir.mktmpdir do |puppet_root|
|
|
21
21
|
|
22
22
|
Tempfile.open('plugins.tar.gz') do |plugins|
|
23
23
|
File.binwrite(plugins, Base64.decode64(args['plugins']))
|
24
|
-
|
24
|
+
user = Etc.getpwuid.nil? ? Etc.getlogin : Etc.getpwuid.name
|
25
|
+
Puppet::ModuleTool::Tar.instance.unpack(plugins, moduledir, user)
|
25
26
|
end
|
26
27
|
|
27
28
|
env = Puppet.lookup(:environments).get('production')
|
data/libexec/query_resources.rb
CHANGED
@@ -28,7 +28,8 @@ Dir.mktmpdir do |puppet_root|
|
|
28
28
|
|
29
29
|
Tempfile.open('plugins.tar.gz') do |plugins|
|
30
30
|
File.binwrite(plugins, Base64.decode64(args['plugins']))
|
31
|
-
|
31
|
+
user = Etc.getpwuid.nil? ? Etc.getlogin : Etc.getpwuid.name
|
32
|
+
Puppet::ModuleTool::Tar.instance.unpack(plugins, moduledir, user)
|
32
33
|
end
|
33
34
|
|
34
35
|
env = Puppet.lookup(:environments).get('production')
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bolt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.47.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Puppet
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-01-
|
11
|
+
date: 2020-01-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -420,7 +420,6 @@ files:
|
|
420
420
|
- lib/bolt/pal/yaml_plan/transpiler.rb
|
421
421
|
- lib/bolt/plan_result.rb
|
422
422
|
- lib/bolt/plugin.rb
|
423
|
-
- lib/bolt/plugin/install_agent.rb
|
424
423
|
- lib/bolt/plugin/module.rb
|
425
424
|
- lib/bolt/plugin/pkcs7.rb
|
426
425
|
- lib/bolt/plugin/prompt.rb
|
@@ -1,28 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Bolt
|
4
|
-
class Plugin
|
5
|
-
class InstallAgent
|
6
|
-
def hooks
|
7
|
-
%i[puppet_library]
|
8
|
-
end
|
9
|
-
|
10
|
-
def name
|
11
|
-
'install_agent'
|
12
|
-
end
|
13
|
-
|
14
|
-
def initialize(*args); end
|
15
|
-
|
16
|
-
def puppet_library(_opts, target, apply_prep)
|
17
|
-
install_task = apply_prep.get_task("puppet_agent::install")
|
18
|
-
service_task = apply_prep.get_task("service", 'action' => 'stop', 'name' => 'puppet')
|
19
|
-
proc do
|
20
|
-
apply_prep.run_task([target], install_task).first
|
21
|
-
apply_prep.set_agent_feature(target)
|
22
|
-
apply_prep.run_task([target], service_task, 'action' => 'stop', 'name' => 'puppet').first
|
23
|
-
apply_prep.run_task([target], service_task, 'action' => 'disable', 'name' => 'puppet').first
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|