bolt 2.6.0 → 2.11.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 +4 -3
- data/bolt-modules/boltlib/lib/puppet/datatypes/applyresult.rb +2 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/resourceinstance.rb +27 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/result.rb +2 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/resultset.rb +2 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/target.rb +4 -3
- data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_task_with.rb +192 -0
- data/bolt-modules/boltlib/lib/puppet/functions/set_resources.rb +122 -0
- data/bolt-modules/boltlib/types/planresult.pp +12 -1
- data/bolt-modules/file/lib/puppet/functions/file/exists.rb +3 -1
- data/bolt-modules/file/lib/puppet/functions/file/join.rb +1 -1
- data/bolt-modules/file/lib/puppet/functions/file/read.rb +2 -1
- data/bolt-modules/file/lib/puppet/functions/file/readable.rb +3 -1
- data/bolt-modules/file/lib/puppet/functions/file/write.rb +3 -1
- data/bolt-modules/prompt/lib/puppet/functions/prompt.rb +43 -0
- data/lib/bolt/analytics.rb +1 -1
- data/lib/bolt/applicator.rb +3 -2
- data/lib/bolt/apply_inventory.rb +1 -1
- data/lib/bolt/apply_result.rb +1 -1
- data/lib/bolt/apply_target.rb +11 -2
- data/lib/bolt/bolt_option_parser.rb +27 -7
- data/lib/bolt/catalog.rb +32 -3
- data/lib/bolt/cli.rb +52 -22
- data/lib/bolt/config.rb +51 -27
- data/lib/bolt/config/transport/base.rb +3 -3
- data/lib/bolt/config/transport/docker.rb +7 -1
- data/lib/bolt/config/transport/local.rb +9 -1
- data/lib/bolt/config/transport/orch.rb +4 -2
- data/lib/bolt/config/transport/remote.rb +2 -0
- data/lib/bolt/config/transport/ssh.rb +81 -3
- data/lib/bolt/config/transport/winrm.rb +6 -1
- data/lib/bolt/executor.rb +38 -0
- data/lib/bolt/inventory.rb +2 -1
- data/lib/bolt/inventory/group.rb +1 -0
- data/lib/bolt/inventory/inventory.rb +9 -0
- data/lib/bolt/inventory/target.rb +17 -1
- data/lib/bolt/node/output.rb +1 -1
- data/lib/bolt/outputter/human.rb +5 -4
- data/lib/bolt/outputter/json.rb +1 -1
- data/lib/bolt/pal.rb +32 -14
- data/lib/bolt/pal/yaml_plan.rb +1 -0
- data/lib/bolt/plugin.rb +14 -8
- data/lib/bolt/plugin/env_var.rb +2 -1
- data/lib/bolt/plugin/module.rb +40 -7
- data/lib/bolt/plugin/prompt.rb +1 -1
- data/lib/bolt/plugin/puppetdb.rb +5 -2
- data/lib/bolt/project.rb +135 -0
- data/lib/bolt/puppetdb/config.rb +16 -28
- data/lib/bolt/rerun.rb +1 -1
- data/lib/bolt/resource_instance.rb +126 -0
- data/lib/bolt/result.rb +46 -23
- data/lib/bolt/result_set.rb +2 -5
- data/lib/bolt/secret.rb +20 -4
- data/lib/bolt/shell/bash.rb +27 -14
- data/lib/bolt/shell/bash/tmpdir.rb +1 -1
- data/lib/bolt/shell/powershell.rb +43 -15
- data/lib/bolt/shell/powershell/snippets.rb +1 -1
- data/lib/bolt/target.rb +18 -2
- data/lib/bolt/transport/base.rb +24 -8
- data/lib/bolt/transport/docker.rb +3 -3
- data/lib/bolt/transport/docker/connection.rb +11 -7
- data/lib/bolt/transport/local/connection.rb +13 -7
- data/lib/bolt/transport/orch.rb +5 -1
- data/lib/bolt/transport/ssh.rb +6 -2
- data/lib/bolt/transport/ssh/connection.rb +26 -1
- data/lib/bolt/transport/ssh/exec_connection.rb +110 -0
- data/lib/bolt/transport/winrm/connection.rb +10 -2
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/pe/pal.rb +1 -38
- data/lib/bolt_server/transport_app.rb +7 -7
- data/lib/bolt_spec/bolt_context.rb +3 -6
- data/lib/bolt_spec/plans.rb +78 -8
- data/lib/bolt_spec/plans/action_stubs.rb +37 -7
- data/lib/bolt_spec/plans/action_stubs/plan_stub.rb +55 -0
- data/lib/bolt_spec/plans/mock_executor.rb +62 -2
- data/lib/bolt_spec/run.rb +10 -13
- metadata +26 -7
- data/lib/bolt/boltdir.rb +0 -54
- data/lib/bolt/plugin/pkcs7.rb +0 -104
- data/lib/bolt/secret/base.rb +0 -41
data/lib/bolt/config.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
require 'etc'
|
4
4
|
require 'logging'
|
5
5
|
require 'pathname'
|
6
|
-
require 'bolt/
|
6
|
+
require 'bolt/project'
|
7
7
|
require 'bolt/logger'
|
8
8
|
require 'bolt/util'
|
9
9
|
# Transport config objects
|
@@ -23,7 +23,7 @@ module Bolt
|
|
23
23
|
end
|
24
24
|
|
25
25
|
class Config
|
26
|
-
attr_reader :config_files, :warnings, :data, :transports, :
|
26
|
+
attr_reader :config_files, :warnings, :data, :transports, :project
|
27
27
|
|
28
28
|
TRANSPORT_CONFIG = {
|
29
29
|
'ssh' => Bolt::Config::Transport::SSH,
|
@@ -34,6 +34,8 @@ module Bolt
|
|
34
34
|
'remote' => Bolt::Config::Transport::Remote
|
35
35
|
}.freeze
|
36
36
|
|
37
|
+
# NOTE: All configuration options should have a corresponding schema property
|
38
|
+
# in schemas/bolt-config.schema.json
|
37
39
|
OPTIONS = {
|
38
40
|
"apply_settings" => "A map of Puppet settings to use when applying Puppet code",
|
39
41
|
"color" => "Whether to use colored output when printing messages to the console.",
|
@@ -64,8 +66,8 @@ module Bolt
|
|
64
66
|
|
65
67
|
DEFAULT_OPTIONS = {
|
66
68
|
"color" => true,
|
67
|
-
"concurrency" => 100,
|
68
69
|
"compile-concurrency" => "Number of cores",
|
70
|
+
"concurrency" => "100 or one-third of the ulimit, whichever is lower",
|
69
71
|
"format" => "human",
|
70
72
|
"hiera-config" => "Boltdir/hiera.yaml",
|
71
73
|
"inventoryfile" => "Boltdir/inventory.yaml",
|
@@ -101,31 +103,33 @@ module Bolt
|
|
101
103
|
"show_diff" => false
|
102
104
|
}.freeze
|
103
105
|
|
106
|
+
DEFAULT_DEFAULT_CONCURRENCY = 100
|
107
|
+
|
104
108
|
def self.default
|
105
|
-
new(Bolt::
|
109
|
+
new(Bolt::Project.new('.'), {})
|
106
110
|
end
|
107
111
|
|
108
|
-
def self.
|
112
|
+
def self.from_project(project, overrides = {})
|
109
113
|
data = {
|
110
|
-
filepath:
|
111
|
-
data: Bolt::Util.read_optional_yaml_hash(
|
114
|
+
filepath: project.config_file,
|
115
|
+
data: Bolt::Util.read_optional_yaml_hash(project.config_file, 'config')
|
112
116
|
}
|
113
117
|
|
114
118
|
data = load_defaults.push(data).select { |config| config[:data]&.any? }
|
115
119
|
|
116
|
-
new(
|
120
|
+
new(project, data, overrides)
|
117
121
|
end
|
118
122
|
|
119
123
|
def self.from_file(configfile, overrides = {})
|
120
|
-
|
124
|
+
project = Bolt::Project.new(Pathname.new(configfile).expand_path.dirname)
|
121
125
|
|
122
126
|
data = {
|
123
|
-
filepath:
|
127
|
+
filepath: project.config_file,
|
124
128
|
data: Bolt::Util.read_yaml_hash(configfile, 'config')
|
125
129
|
}
|
126
130
|
data = load_defaults.push(data).select { |config| config[:data]&.any? }
|
127
131
|
|
128
|
-
new(
|
132
|
+
new(project, data, overrides)
|
129
133
|
end
|
130
134
|
|
131
135
|
def self.load_defaults
|
@@ -148,14 +152,14 @@ module Bolt
|
|
148
152
|
confs
|
149
153
|
end
|
150
154
|
|
151
|
-
def initialize(
|
155
|
+
def initialize(project, config_data, overrides = {})
|
152
156
|
unless config_data.is_a?(Array)
|
153
|
-
config_data = [{ filepath:
|
157
|
+
config_data = [{ filepath: project.config_file, data: config_data }]
|
154
158
|
end
|
155
159
|
|
156
160
|
@logger = Logging.logger[self]
|
157
161
|
@warnings = []
|
158
|
-
@
|
162
|
+
@project = project
|
159
163
|
@transports = {}
|
160
164
|
@config_files = []
|
161
165
|
|
@@ -163,7 +167,7 @@ module Bolt
|
|
163
167
|
'apply_settings' => {},
|
164
168
|
'color' => true,
|
165
169
|
'compile-concurrency' => Etc.nprocessors,
|
166
|
-
'concurrency' =>
|
170
|
+
'concurrency' => default_concurrency,
|
167
171
|
'format' => 'human',
|
168
172
|
'log' => { 'console' => {} },
|
169
173
|
'plugin_hooks' => {},
|
@@ -181,10 +185,22 @@ module Bolt
|
|
181
185
|
|
182
186
|
override_data = normalize_overrides(overrides)
|
183
187
|
|
188
|
+
# If we need to lower concurrency and concurrency is not configured
|
189
|
+
ld_concurrency = loaded_data.map(&:keys).flatten.include?('concurrency')
|
190
|
+
if default_concurrency != DEFAULT_DEFAULT_CONCURRENCY &&
|
191
|
+
!ld_concurrency &&
|
192
|
+
!override_data.key?('concurrency')
|
193
|
+
concurrency_warning = { option: 'concurrency',
|
194
|
+
msg: "Concurrency will default to #{default_concurrency} because ulimit "\
|
195
|
+
"is low: #{Etc.sysconf(Etc::SC_OPEN_MAX)}. Set concurrency with "\
|
196
|
+
"'--concurrency', or set your ulimit with 'ulimit -n <limit>'" }
|
197
|
+
@warnings << concurrency_warning
|
198
|
+
end
|
199
|
+
|
184
200
|
@data = merge_config_layers(default_data, *loaded_data, override_data)
|
185
201
|
|
186
202
|
TRANSPORT_CONFIG.each do |transport, config|
|
187
|
-
@transports[transport] = config.new(@data.delete(transport), @
|
203
|
+
@transports[transport] = config.new(@data.delete(transport), @project.path)
|
188
204
|
end
|
189
205
|
|
190
206
|
finalize_data
|
@@ -250,7 +266,7 @@ module Bolt
|
|
250
266
|
@data['log'] = update_logs(@data['log'])
|
251
267
|
end
|
252
268
|
|
253
|
-
# Expand paths relative to the
|
269
|
+
# Expand paths relative to the project. Any settings that came from the
|
254
270
|
# CLI will already be absolute, so the expand will be skipped.
|
255
271
|
if @data.key?('modulepath')
|
256
272
|
moduledirs = if data['modulepath'].is_a?(String)
|
@@ -259,12 +275,12 @@ module Bolt
|
|
259
275
|
data['modulepath']
|
260
276
|
end
|
261
277
|
@data['modulepath'] = moduledirs.map do |moduledir|
|
262
|
-
File.expand_path(moduledir, @
|
278
|
+
File.expand_path(moduledir, @project.path)
|
263
279
|
end
|
264
280
|
end
|
265
281
|
|
266
282
|
%w[hiera-config inventoryfile trusted-external-command].each do |opt|
|
267
|
-
@data[opt] = File.expand_path(@data[opt], @
|
283
|
+
@data[opt] = File.expand_path(@data[opt], @project.path) if @data.key?(opt)
|
268
284
|
end
|
269
285
|
|
270
286
|
# Filter hashes to only include valid options
|
@@ -275,7 +291,7 @@ module Bolt
|
|
275
291
|
private def normalize_log(target)
|
276
292
|
return target if target == 'console'
|
277
293
|
target = target[5..-1] if target.start_with?('file:')
|
278
|
-
'file:' + File.expand_path(target, @
|
294
|
+
'file:' + File.expand_path(target, @project.path)
|
279
295
|
end
|
280
296
|
|
281
297
|
private def update_logs(logs)
|
@@ -310,10 +326,10 @@ module Bolt
|
|
310
326
|
@warnings << { option: 'future', msg: msg }
|
311
327
|
end
|
312
328
|
|
313
|
-
keys = OPTIONS.keys - %w[plugins plugin_hooks]
|
329
|
+
keys = OPTIONS.keys - %w[plugins plugin_hooks puppetdb]
|
314
330
|
keys.each do |key|
|
315
331
|
next unless Bolt::Util.references?(@data[key])
|
316
|
-
valid_keys = TRANSPORT_CONFIG.keys + %w[plugins plugin_hooks]
|
332
|
+
valid_keys = TRANSPORT_CONFIG.keys + %w[plugins plugin_hooks puppetdb]
|
317
333
|
raise Bolt::ValidationError,
|
318
334
|
"Found unsupported key _plugin in config setting #{key}. Plugins are only available in "\
|
319
335
|
"#{valid_keys.join(', ')}."
|
@@ -348,23 +364,23 @@ module Bolt
|
|
348
364
|
end
|
349
365
|
|
350
366
|
def default_inventoryfile
|
351
|
-
@
|
367
|
+
@project.inventory_file
|
352
368
|
end
|
353
369
|
|
354
370
|
def rerunfile
|
355
|
-
@
|
371
|
+
@project.rerunfile
|
356
372
|
end
|
357
373
|
|
358
374
|
def hiera_config
|
359
|
-
@data['hiera-config'] || @
|
375
|
+
@data['hiera-config'] || @project.hiera_config
|
360
376
|
end
|
361
377
|
|
362
378
|
def puppetfile
|
363
|
-
@puppetfile || @
|
379
|
+
@puppetfile || @project.puppetfile
|
364
380
|
end
|
365
381
|
|
366
382
|
def modulepath
|
367
|
-
@data['modulepath'] || @
|
383
|
+
@data['modulepath'] || @project.modulepath
|
368
384
|
end
|
369
385
|
|
370
386
|
def modulepath=(value)
|
@@ -456,5 +472,13 @@ module Bolt
|
|
456
472
|
l =~ /[A-Za-z]/ ? "[#{l.upcase}#{l.downcase}]" : l
|
457
473
|
end.join
|
458
474
|
end
|
475
|
+
|
476
|
+
def default_concurrency
|
477
|
+
if Bolt::Util.windows? || Etc.sysconf(Etc::SC_OPEN_MAX) >= 300 || Etc.sysconf(Etc::SC_OPEN_MAX).nil?
|
478
|
+
DEFAULT_DEFAULT_CONCURRENCY
|
479
|
+
else
|
480
|
+
(Etc.sysconf(Etc::SC_OPEN_MAX) / 3).floor
|
481
|
+
end
|
482
|
+
end
|
459
483
|
end
|
460
484
|
end
|
@@ -9,12 +9,12 @@ module Bolt
|
|
9
9
|
class Base
|
10
10
|
attr_reader :input
|
11
11
|
|
12
|
-
def initialize(data = {},
|
12
|
+
def initialize(data = {}, project = nil)
|
13
13
|
assert_hash_or_config(data)
|
14
14
|
@input = data
|
15
15
|
@resolved = !Bolt::Util.references?(input)
|
16
16
|
@config = resolved? ? Bolt::Util.deep_merge(defaults, filter(input)) : defaults
|
17
|
-
@
|
17
|
+
@project = project
|
18
18
|
|
19
19
|
validate if resolved?
|
20
20
|
end
|
@@ -62,7 +62,7 @@ module Bolt
|
|
62
62
|
Bolt::Util.deep_merge(acc, layer_data)
|
63
63
|
end
|
64
64
|
|
65
|
-
self.class.new(merged, @
|
65
|
+
self.class.new(merged, @project)
|
66
66
|
end
|
67
67
|
|
68
68
|
# Resolve any references in the input data, then remerge it with the defaults
|
@@ -7,7 +7,11 @@ module Bolt
|
|
7
7
|
class Config
|
8
8
|
module Transport
|
9
9
|
class Docker < Base
|
10
|
+
# NOTE: All transport configuration options should have a corresponding schema definition
|
11
|
+
# in schemas/bolt-transport-definitions.json
|
10
12
|
OPTIONS = {
|
13
|
+
"cleanup" => { type: TrueClass,
|
14
|
+
desc: "Whether to clean up temporary files created on targets." },
|
11
15
|
"host" => { type: String,
|
12
16
|
desc: "Host name." },
|
13
17
|
"interpreters" => { type: Hash,
|
@@ -27,7 +31,9 @@ module Bolt
|
|
27
31
|
desc: "Whether to enable tty on exec commands." }
|
28
32
|
}.freeze
|
29
33
|
|
30
|
-
DEFAULTS = {
|
34
|
+
DEFAULTS = {
|
35
|
+
'cleanup' => true
|
36
|
+
}.freeze
|
31
37
|
|
32
38
|
private def validate
|
33
39
|
super
|
@@ -7,7 +7,11 @@ module Bolt
|
|
7
7
|
class Config
|
8
8
|
module Transport
|
9
9
|
class Local < Base
|
10
|
+
# NOTE: All transport configuration options should have a corresponding schema definition
|
11
|
+
# in schemas/bolt-transport-definitions.json
|
10
12
|
OPTIONS = {
|
13
|
+
"cleanup" => { type: TrueClass,
|
14
|
+
desc: "Whether to clean up temporary files created on targets." },
|
11
15
|
"interpreters" => { type: Hash,
|
12
16
|
desc: "A map of an extension name to the absolute path of an executable, "\
|
13
17
|
"enabling you to override the shebang defined in a task executable. The "\
|
@@ -36,6 +40,8 @@ module Bolt
|
|
36
40
|
}.freeze
|
37
41
|
|
38
42
|
WINDOWS_OPTIONS = {
|
43
|
+
"cleanup" => { type: TrueClass,
|
44
|
+
desc: "Whether to clean up temporary files created on targets." },
|
39
45
|
"interpreters" => { type: Hash,
|
40
46
|
desc: "A map of an extension name to the absolute path of an executable, "\
|
41
47
|
"enabling you to override the shebang defined in a task executable. The "\
|
@@ -47,7 +53,9 @@ module Bolt
|
|
47
53
|
desc: "The directory to copy and execute temporary files." }
|
48
54
|
}.freeze
|
49
55
|
|
50
|
-
DEFAULTS = {
|
56
|
+
DEFAULTS = {
|
57
|
+
'cleanup' => true
|
58
|
+
}.freeze
|
51
59
|
|
52
60
|
def self.options
|
53
61
|
Bolt::Util.windows? ? WINDOWS_OPTIONS : OPTIONS
|
@@ -7,6 +7,8 @@ module Bolt
|
|
7
7
|
class Config
|
8
8
|
module Transport
|
9
9
|
class Orch < Base
|
10
|
+
# NOTE: All transport configuration options should have a corresponding schema definition
|
11
|
+
# in schemas/bolt-transport-definitions.json
|
10
12
|
OPTIONS = {
|
11
13
|
"cacert" => { type: String,
|
12
14
|
desc: "The path to the CA certificate." },
|
@@ -32,12 +34,12 @@ module Bolt
|
|
32
34
|
super
|
33
35
|
|
34
36
|
if @config['cacert']
|
35
|
-
@config['cacert'] = File.expand_path(@config['cacert'], @
|
37
|
+
@config['cacert'] = File.expand_path(@config['cacert'], @project)
|
36
38
|
Bolt::Util.validate_file('cacert', @config['cacert'])
|
37
39
|
end
|
38
40
|
|
39
41
|
if @config['token-file']
|
40
|
-
@config['token-file'] = File.expand_path(@config['token-file'], @
|
42
|
+
@config['token-file'] = File.expand_path(@config['token-file'], @project)
|
41
43
|
Bolt::Util.validate_file('token-file', @config['token-file'])
|
42
44
|
end
|
43
45
|
end
|
@@ -7,6 +7,8 @@ module Bolt
|
|
7
7
|
class Config
|
8
8
|
module Transport
|
9
9
|
class Remote < Base
|
10
|
+
# NOTE: All transport configuration options should have a corresponding schema definition
|
11
|
+
# in schemas/bolt-transport-definitions.json
|
10
12
|
OPTIONS = {
|
11
13
|
"run-on" => { type: String,
|
12
14
|
desc: "The proxy target that the task executes on." }
|
@@ -7,16 +7,35 @@ module Bolt
|
|
7
7
|
class Config
|
8
8
|
module Transport
|
9
9
|
class SSH < Base
|
10
|
+
LOGIN_SHELLS = %w[sh bash zsh dash ksh powershell].freeze
|
11
|
+
|
12
|
+
# NOTE: All transport configuration options should have a corresponding schema definition
|
13
|
+
# in schemas/bolt-transport-definitions.json
|
10
14
|
OPTIONS = {
|
15
|
+
"cleanup" => { type: TrueClass,
|
16
|
+
external: true,
|
17
|
+
desc: "Whether to clean up temporary files created on targets." },
|
11
18
|
"connect-timeout" => { type: Integer,
|
12
19
|
desc: "How long to wait when establishing connections." },
|
20
|
+
"copy-command" => { external: true,
|
21
|
+
desc: "Command to use when copying files using ssh-command. "\
|
22
|
+
"Bolt runs `<copy-command> <src> <dest>`. **This option is experimental.**" },
|
13
23
|
"disconnect-timeout" => { type: Integer,
|
14
24
|
desc: "How long to wait before force-closing a connection." },
|
15
25
|
"host" => { type: String,
|
26
|
+
external: true,
|
16
27
|
desc: "Host name." },
|
17
28
|
"host-key-check" => { type: TrueClass,
|
29
|
+
external: true,
|
18
30
|
desc: "Whether to perform host key validation when connecting." },
|
31
|
+
"extensions" => { type: Array,
|
32
|
+
desc: "List of file extensions that are accepted for scripts or tasks on Windows. "\
|
33
|
+
"Scripts with these file extensions rely on the target's file type "\
|
34
|
+
"association to run. For example, if Python is installed on the system, "\
|
35
|
+
"a `.py` script runs with `python.exe`. The extensions `.ps1`, `.rb`, and "\
|
36
|
+
"`.pp` are always allowed and run via hard-coded executables." },
|
19
37
|
"interpreters" => { type: Hash,
|
38
|
+
external: true,
|
20
39
|
desc: "A map of an extension name to the absolute path of an executable, "\
|
21
40
|
"enabling you to override the shebang defined in a task executable. The "\
|
22
41
|
"extension can optionally be specified with the `.` character (`.py` and "\
|
@@ -25,29 +44,43 @@ module Bolt
|
|
25
44
|
"Bolt Ruby interpreter by default." },
|
26
45
|
"load-config" => { type: TrueClass,
|
27
46
|
desc: "Whether to load system SSH configuration." },
|
47
|
+
"login-shell" => { type: String,
|
48
|
+
desc: "Which login shell Bolt should expect on the target. "\
|
49
|
+
"Supported shells are #{LOGIN_SHELLS.join(', ')}. "\
|
50
|
+
"**This option is experimental.**" },
|
28
51
|
"password" => { type: String,
|
29
52
|
desc: "Login password." },
|
30
53
|
"port" => { type: Integer,
|
54
|
+
external: true,
|
31
55
|
desc: "Connection port." },
|
32
|
-
"private-key" => {
|
56
|
+
"private-key" => { external: true,
|
57
|
+
desc: "Either the path to the private key file to use for authentication, or a "\
|
33
58
|
"hash with the key `key-data` and the contents of the private key." },
|
34
59
|
"proxyjump" => { type: String,
|
35
60
|
desc: "A jump host to proxy connections through, and an optional user to "\
|
36
61
|
"connect with." },
|
37
62
|
"run-as" => { type: String,
|
63
|
+
external: true,
|
38
64
|
desc: "A different user to run commands as after login." },
|
39
65
|
"run-as-command" => { type: Array,
|
66
|
+
external: true,
|
40
67
|
desc: "The command to elevate permissions. Bolt appends the user and command "\
|
41
68
|
"strings to the configured `run-as-command` before running it on the "\
|
42
69
|
"target. This command must not require an interactive password prompt, "\
|
43
70
|
"and the `sudo-password` option is ignored when `run-as-command` is "\
|
44
71
|
"specified. The `run-as-command` must be specified as an array." },
|
45
72
|
"script-dir" => { type: String,
|
73
|
+
external: true,
|
46
74
|
desc: "The subdirectory of the tmpdir to use in place of a randomized "\
|
47
75
|
"subdirectory for uploading and executing temporary files on the "\
|
48
76
|
"target. It's expected that this directory already exists as a subdir "\
|
49
77
|
"of tmpdir, which is either configured or defaults to `/tmp`." },
|
78
|
+
"ssh-command" => { external: true,
|
79
|
+
desc: "Command and flags to use when SSHing. This enables the external "\
|
80
|
+
"SSH transport which shells out to the specified command. "\
|
81
|
+
"**This option is experimental.**" },
|
50
82
|
"sudo-executable" => { type: String,
|
83
|
+
external: true,
|
51
84
|
desc: "The executable to use when escalating to the configured `run-as` "\
|
52
85
|
"user. This is useful when you want to escalate using the configured "\
|
53
86
|
"`sudo-password`, since `run-as-command` does not use `sudo-password` "\
|
@@ -55,22 +88,27 @@ module Bolt
|
|
55
88
|
"`<sudo-executable> -S -u <user> -p custom_bolt_prompt <command>`. "\
|
56
89
|
"**This option is experimental.**" },
|
57
90
|
"sudo-password" => { type: String,
|
91
|
+
external: true,
|
58
92
|
desc: "Password to use when changing users via `run-as`." },
|
59
93
|
"tmpdir" => { type: String,
|
94
|
+
external: true,
|
60
95
|
desc: "The directory to upload and execute temporary files on the target." },
|
61
96
|
"tty" => { type: TrueClass,
|
62
97
|
desc: "Request a pseudo tty for the session. This option is generally "\
|
63
98
|
"only used in conjunction with the `run-as` option when the sudoers "\
|
64
99
|
"policy requires a `tty`." },
|
65
100
|
"user" => { type: String,
|
101
|
+
external: true,
|
66
102
|
desc: "Login user." }
|
67
103
|
}.freeze
|
68
104
|
|
69
105
|
DEFAULTS = {
|
106
|
+
"cleanup" => true,
|
70
107
|
"connect-timeout" => 10,
|
71
108
|
"tty" => false,
|
72
109
|
"load-config" => true,
|
73
|
-
"disconnect-timeout" => 5
|
110
|
+
"disconnect-timeout" => 5,
|
111
|
+
"login-shell" => 'bash'
|
74
112
|
}.freeze
|
75
113
|
|
76
114
|
private def validate
|
@@ -84,7 +122,14 @@ module Bolt
|
|
84
122
|
end
|
85
123
|
|
86
124
|
if key_opt.instance_of?(String)
|
87
|
-
@config['private-key'] = File.expand_path(key_opt, @
|
125
|
+
@config['private-key'] = File.expand_path(key_opt, @project)
|
126
|
+
|
127
|
+
# We have an explicit test for this to only warn if using net-ssh transport
|
128
|
+
Bolt::Util.validate_file('ssh key', @config['private-key']) if @config['ssh-command']
|
129
|
+
end
|
130
|
+
|
131
|
+
if key_opt.instance_of?(Hash) && @config['ssh-command']
|
132
|
+
raise Bolt::ValidationError, 'private-key must be a filepath when using ssh-command'
|
88
133
|
end
|
89
134
|
end
|
90
135
|
|
@@ -92,12 +137,45 @@ module Bolt
|
|
92
137
|
@config['interpreters'] = normalize_interpreters(@config['interpreters'])
|
93
138
|
end
|
94
139
|
|
140
|
+
if @config['login-shell'] && !LOGIN_SHELLS.include?(@config['login-shell'])
|
141
|
+
raise Bolt::ValidationError,
|
142
|
+
"Unsupported login-shell #{@config['login-shell']}. Supported shells are #{LOGIN_SHELLS.join(', ')}"
|
143
|
+
end
|
144
|
+
|
95
145
|
if (run_as_cmd = @config['run-as-command'])
|
96
146
|
unless run_as_cmd.all? { |n| n.is_a?(String) }
|
97
147
|
raise Bolt::ValidationError,
|
98
148
|
"run-as-command must be an Array of Strings, received #{run_as_cmd.class} #{run_as_cmd.inspect}"
|
99
149
|
end
|
100
150
|
end
|
151
|
+
|
152
|
+
if @config['login-shell'] == 'powershell'
|
153
|
+
%w[tty run-as].each do |key|
|
154
|
+
if @config[key]
|
155
|
+
raise Bolt::ValidationError,
|
156
|
+
"#{key} is not supported when using PowerShell"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
if @config['ssh-command'] && !@config['load-config']
|
162
|
+
msg = 'Cannot use external SSH transport with load-config set to false'
|
163
|
+
raise Bolt::ValidationError, msg
|
164
|
+
end
|
165
|
+
|
166
|
+
if (ssh_cmd = @config['ssh-command'])
|
167
|
+
unless ssh_cmd.is_a?(String) || ssh_cmd.is_a?(Array)
|
168
|
+
raise Bolt::ValidationError,
|
169
|
+
"ssh-command must be a String or Array, received #{ssh_cmd.class} #{ssh_cmd.inspect}"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
if (copy_cmd = @config['copy-command'])
|
174
|
+
unless copy_cmd.is_a?(String) || copy_cmd.is_a?(Array)
|
175
|
+
raise Bolt::ValidationError,
|
176
|
+
"copy-command must be a String or Array, received #{copy_cmd.class} #{copy_cmd.inspect}"
|
177
|
+
end
|
178
|
+
end
|
101
179
|
end
|
102
180
|
end
|
103
181
|
end
|