bolt 2.8.0 → 2.12.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 +2 -2
- 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 +61 -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/lib/bolt/analytics.rb +21 -2
- data/lib/bolt/applicator.rb +3 -1
- data/lib/bolt/apply_result.rb +1 -1
- data/lib/bolt/apply_target.rb +3 -2
- data/lib/bolt/bolt_option_parser.rb +18 -8
- data/lib/bolt/cli.rb +35 -5
- data/lib/bolt/config.rb +45 -13
- data/lib/bolt/config/transport/docker.rb +2 -0
- data/lib/bolt/config/transport/local.rb +2 -0
- data/lib/bolt/config/transport/orch.rb +2 -0
- data/lib/bolt/config/transport/remote.rb +2 -0
- data/lib/bolt/config/transport/ssh.rb +50 -1
- data/lib/bolt/config/transport/winrm.rb +2 -0
- data/lib/bolt/inventory.rb +2 -1
- data/lib/bolt/inventory/group.rb +1 -0
- data/lib/bolt/inventory/inventory.rb +5 -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 +4 -1
- data/lib/bolt/pal/yaml_plan.rb +1 -0
- data/lib/bolt/plugin.rb +13 -7
- data/lib/bolt/plugin/puppetdb.rb +5 -2
- data/lib/bolt/project.rb +25 -7
- data/lib/bolt/puppetdb/config.rb +14 -26
- 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/shell/bash.rb +1 -1
- data/lib/bolt/shell/powershell.rb +12 -4
- data/lib/bolt/target.rb +12 -1
- data/lib/bolt/transport/ssh.rb +6 -2
- data/lib/bolt/transport/ssh/connection.rb +4 -0
- data/lib/bolt/transport/ssh/exec_connection.rb +110 -0
- data/lib/bolt/transport/winrm/connection.rb +6 -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 +1 -4
- data/lib/bolt_spec/plans/mock_executor.rb +1 -0
- data/lib/bolt_spec/run.rb +2 -5
- metadata +6 -2
data/lib/bolt/apply_target.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
module Bolt
|
4
4
|
class ApplyTarget
|
5
5
|
ATTRIBUTES = %i[uri name target_alias config vars facts features
|
6
|
-
plugin_hooks safe_name].freeze
|
6
|
+
plugin_hooks resources safe_name].freeze
|
7
7
|
COMPUTED = %i[host password port protocol user].freeze
|
8
8
|
|
9
9
|
attr_reader(*ATTRIBUTES)
|
@@ -24,7 +24,8 @@ module Bolt
|
|
24
24
|
facts = nil,
|
25
25
|
vars = nil,
|
26
26
|
features = nil,
|
27
|
-
plugin_hooks = nil
|
27
|
+
plugin_hooks = nil,
|
28
|
+
resources = nil)
|
28
29
|
raise Bolt::Error.new("Target objects cannot be instantiated inside apply blocks", 'bolt/apply-error')
|
29
30
|
end
|
30
31
|
# rubocop:enable Lint/UnusedMethodArgument
|
@@ -11,7 +11,7 @@ module Bolt
|
|
11
11
|
escalation: %w[run-as sudo-password sudo-password-prompt sudo-executable],
|
12
12
|
run_context: %w[concurrency inventoryfile save-rerun cleanup],
|
13
13
|
global_config_setters: %w[modulepath boltdir configfile],
|
14
|
-
transports: %w[transport connect-timeout tty],
|
14
|
+
transports: %w[transport connect-timeout tty ssh-command copy-command],
|
15
15
|
display: %w[format color verbose trace],
|
16
16
|
global: %w[help version debug] }.freeze
|
17
17
|
|
@@ -20,7 +20,7 @@ module Bolt
|
|
20
20
|
def get_help_text(subcommand, action = nil)
|
21
21
|
case subcommand
|
22
22
|
when 'apply'
|
23
|
-
{ flags: ACTION_OPTS + %w[noop execute compile-concurrency],
|
23
|
+
{ flags: ACTION_OPTS + %w[noop execute compile-concurrency hiera-config],
|
24
24
|
banner: APPLY_HELP }
|
25
25
|
when 'command'
|
26
26
|
case action
|
@@ -172,13 +172,14 @@ module Bolt
|
|
172
172
|
apply
|
173
173
|
|
174
174
|
USAGE
|
175
|
-
bolt apply
|
175
|
+
bolt apply [manifest.pp] [options]
|
176
176
|
|
177
177
|
DESCRIPTION
|
178
178
|
Apply Puppet manifest code on the specified targets.
|
179
179
|
|
180
180
|
EXAMPLES
|
181
|
-
bolt apply manifest.pp
|
181
|
+
bolt apply manifest.pp -t target
|
182
|
+
bolt apply -e "file { '/etc/puppetlabs': ensure => present }" -t target
|
182
183
|
HELP
|
183
184
|
|
184
185
|
COMMAND_HELP = <<~HELP
|
@@ -594,6 +595,7 @@ module Bolt
|
|
594
595
|
HELP
|
595
596
|
|
596
597
|
attr_reader :warnings
|
598
|
+
|
597
599
|
def initialize(options)
|
598
600
|
super()
|
599
601
|
|
@@ -655,8 +657,8 @@ module Bolt
|
|
655
657
|
@options[:password] = STDIN.noecho(&:gets).chomp
|
656
658
|
STDERR.puts
|
657
659
|
end
|
658
|
-
define('--private-key KEY', '
|
659
|
-
@options[:'private-key'] = key
|
660
|
+
define('--private-key KEY', 'Path to private ssh key to authenticate with') do |key|
|
661
|
+
@options[:'private-key'] = File.expand_path(key)
|
660
662
|
end
|
661
663
|
define('--[no-]host-key-check', 'Check host keys with SSH') do |host_key_check|
|
662
664
|
@options[:'host-key-check'] = host_key_check
|
@@ -688,7 +690,7 @@ module Bolt
|
|
688
690
|
|
689
691
|
separator "\nRUN CONTEXT OPTIONS"
|
690
692
|
define('-c', '--concurrency CONCURRENCY', Integer,
|
691
|
-
'Maximum number of simultaneous connections
|
693
|
+
'Maximum number of simultaneous connections') do |concurrency|
|
692
694
|
@options[:concurrency] = concurrency
|
693
695
|
end
|
694
696
|
define('--compile-concurrency CONCURRENCY', Integer,
|
@@ -718,7 +720,7 @@ module Bolt
|
|
718
720
|
end
|
719
721
|
define('--hiera-config FILEPATH',
|
720
722
|
'Specify where to load Hiera config from (default: ~/.puppetlabs/bolt/hiera.yaml)') do |path|
|
721
|
-
@options[:'hiera-config'] = path
|
723
|
+
@options[:'hiera-config'] = File.expand_path(path)
|
722
724
|
end
|
723
725
|
define('-i', '--inventoryfile FILEPATH',
|
724
726
|
'Specify where to load inventory from (default: ~/.puppetlabs/bolt/inventory.yaml)') do |path|
|
@@ -741,6 +743,14 @@ module Bolt
|
|
741
743
|
"Specify a default transport: #{TRANSPORTS.keys.join(', ')}") do |t|
|
742
744
|
@options[:transport] = t
|
743
745
|
end
|
746
|
+
define('--ssh-command EXEC', "Executable to use instead of the net-ssh ruby library. ",
|
747
|
+
"This option is experimental.") do |exec|
|
748
|
+
@options[:'ssh-command'] = exec
|
749
|
+
end
|
750
|
+
define('--copy-command EXEC', "Command to copy files to remote hosts if using external SSH. ",
|
751
|
+
"This option is experimental.") do |exec|
|
752
|
+
@options[:'copy-command'] = exec
|
753
|
+
end
|
744
754
|
define('--connect-timeout TIMEOUT', Integer, 'Connection timeout (defaults vary)') do |timeout|
|
745
755
|
@options[:'connect-timeout'] = timeout
|
746
756
|
end
|
data/lib/bolt/cli.rb
CHANGED
@@ -124,8 +124,9 @@ module Bolt
|
|
124
124
|
|
125
125
|
Bolt::Logger.configure(config.log, config.color)
|
126
126
|
|
127
|
-
# Logger must be configured before checking path case, otherwise warnings will not display
|
127
|
+
# Logger must be configured before checking path case and project file, otherwise warnings will not display
|
128
128
|
@config.check_path_case('modulepath', @config.modulepath)
|
129
|
+
@config.project.check_deprecated_file
|
129
130
|
|
130
131
|
# Log the file paths for loaded config files
|
131
132
|
config_loaded
|
@@ -257,13 +258,11 @@ module Bolt
|
|
257
258
|
end
|
258
259
|
|
259
260
|
def puppetdb_client
|
260
|
-
|
261
|
-
puppetdb_config = Bolt::PuppetDB::Config.load_config(nil, config.puppetdb, config.project.path)
|
262
|
-
@puppetdb_client = Bolt::PuppetDB::Client.new(puppetdb_config)
|
261
|
+
plugins.puppetdb_client
|
263
262
|
end
|
264
263
|
|
265
264
|
def plugins
|
266
|
-
@plugins ||= Bolt::Plugin.setup(config, pal,
|
265
|
+
@plugins ||= Bolt::Plugin.setup(config, pal, analytics)
|
267
266
|
end
|
268
267
|
|
269
268
|
def query_puppetdb_nodes(query)
|
@@ -538,6 +537,17 @@ module Bolt
|
|
538
537
|
Puppet[:tasks] = false
|
539
538
|
ast = pal.parse_manifest(code, filename)
|
540
539
|
|
540
|
+
if defined?(ast.body) &&
|
541
|
+
(ast.body.is_a?(Puppet::Pops::Model::HostClassDefinition) ||
|
542
|
+
ast.body.is_a?(Puppet::Pops::Model::ResourceTypeDefinition))
|
543
|
+
message = "Manifest only contains definitions and will result in no changes on the targets. "\
|
544
|
+
"Definitions must be declared for their resources to be applied. You can read more "\
|
545
|
+
"about defining and declaring classes and types in the Puppet documentation at "\
|
546
|
+
"https://puppet.com/docs/puppet/latest/lang_classes.html and "\
|
547
|
+
"https://puppet.com/docs/puppet/latest/lang_defined_types.html"
|
548
|
+
@logger.warn(message)
|
549
|
+
end
|
550
|
+
|
541
551
|
executor = Bolt::Executor.new(config.concurrency, analytics, noop)
|
542
552
|
executor.subscribe(outputter) if options.fetch(:format, 'human') == 'human'
|
543
553
|
executor.subscribe(log_outputter)
|
@@ -804,6 +814,20 @@ module Bolt
|
|
804
814
|
end
|
805
815
|
|
806
816
|
def bundled_content
|
817
|
+
# If the bundled content directory is empty, Bolt is likely installed as a gem.
|
818
|
+
if ENV['BOLT_GEM'].nil? && incomplete_install?
|
819
|
+
msg = <<~MSG.chomp
|
820
|
+
Bolt may be installed as a gem. To use Bolt reliably and with all of its
|
821
|
+
dependencies, uninstall the 'bolt' gem and install Bolt as a package:
|
822
|
+
https://puppet.com/docs/bolt/latest/bolt_installing.html
|
823
|
+
|
824
|
+
If you meant to install Bolt as a gem and want to disable this warning,
|
825
|
+
set the BOLT_GEM environment variable.
|
826
|
+
MSG
|
827
|
+
|
828
|
+
@logger.warn(msg)
|
829
|
+
end
|
830
|
+
|
807
831
|
# We only need to enumerate bundled content when running a task or plan
|
808
832
|
content = { 'Plan' => [],
|
809
833
|
'Task' => [],
|
@@ -827,5 +851,11 @@ module Bolt
|
|
827
851
|
MSG
|
828
852
|
@logger.debug(msg)
|
829
853
|
end
|
854
|
+
|
855
|
+
# Gem installs include the aggregate, canary, and puppetdb_fact modules, while
|
856
|
+
# package installs include modules listed in the Bolt repo Puppetfile
|
857
|
+
def incomplete_install?
|
858
|
+
(Dir.children(Bolt::PAL::MODULES_PATH) - %w[aggregate canary puppetdb_fact]).empty?
|
859
|
+
end
|
830
860
|
end
|
831
861
|
end
|
data/lib/bolt/config.rb
CHANGED
@@ -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,6 +103,8 @@ module Bolt
|
|
101
103
|
"show_diff" => false
|
102
104
|
}.freeze
|
103
105
|
|
106
|
+
DEFAULT_DEFAULT_CONCURRENCY = 100
|
107
|
+
|
104
108
|
def self.default
|
105
109
|
new(Bolt::Project.new('.'), {})
|
106
110
|
end
|
@@ -111,7 +115,7 @@ module Bolt
|
|
111
115
|
data: Bolt::Util.read_optional_yaml_hash(project.config_file, 'config')
|
112
116
|
}
|
113
117
|
|
114
|
-
data = load_defaults.push(data).select { |config| config[:data]&.any? }
|
118
|
+
data = load_defaults(project).push(data).select { |config| config[:data]&.any? }
|
115
119
|
|
116
120
|
new(project, data, overrides)
|
117
121
|
end
|
@@ -123,27 +127,29 @@ module Bolt
|
|
123
127
|
filepath: project.config_file,
|
124
128
|
data: Bolt::Util.read_yaml_hash(configfile, 'config')
|
125
129
|
}
|
126
|
-
data = load_defaults.push(data).select { |config| config[:data]&.any? }
|
130
|
+
data = load_defaults(project).push(data).select { |config| config[:data]&.any? }
|
127
131
|
|
128
132
|
new(project, data, overrides)
|
129
133
|
end
|
130
134
|
|
131
|
-
def self.load_defaults
|
135
|
+
def self.load_defaults(project)
|
132
136
|
# Lazy-load expensive gem code
|
133
137
|
require 'win32/dir' if Bolt::Util.windows?
|
134
138
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
139
|
+
# Don't load /etc/puppetlabs/bolt/bolt.yaml twice
|
140
|
+
confs = if project.path == Bolt::Project.system_path
|
141
|
+
[]
|
142
|
+
else
|
143
|
+
system_path = Pathname.new(File.join(Bolt::Project.system_path, 'bolt.yaml'))
|
144
|
+
[{ filepath: system_path, data: Bolt::Util.read_optional_yaml_hash(system_path, 'config') }]
|
145
|
+
end
|
146
|
+
|
140
147
|
user_path = begin
|
141
148
|
Pathname.new(File.expand_path(File.join('~', '.puppetlabs', 'etc', 'bolt', 'bolt.yaml')))
|
142
149
|
rescue ArgumentError
|
143
150
|
nil
|
144
151
|
end
|
145
152
|
|
146
|
-
confs = [{ filepath: system_path, data: Bolt::Util.read_optional_yaml_hash(system_path, 'config') }]
|
147
153
|
confs << { filepath: user_path, data: Bolt::Util.read_optional_yaml_hash(user_path, 'config') } if user_path
|
148
154
|
confs
|
149
155
|
end
|
@@ -163,7 +169,7 @@ module Bolt
|
|
163
169
|
'apply_settings' => {},
|
164
170
|
'color' => true,
|
165
171
|
'compile-concurrency' => Etc.nprocessors,
|
166
|
-
'concurrency' =>
|
172
|
+
'concurrency' => default_concurrency,
|
167
173
|
'format' => 'human',
|
168
174
|
'log' => { 'console' => {} },
|
169
175
|
'plugin_hooks' => {},
|
@@ -181,6 +187,18 @@ module Bolt
|
|
181
187
|
|
182
188
|
override_data = normalize_overrides(overrides)
|
183
189
|
|
190
|
+
# If we need to lower concurrency and concurrency is not configured
|
191
|
+
ld_concurrency = loaded_data.map(&:keys).flatten.include?('concurrency')
|
192
|
+
if default_concurrency != DEFAULT_DEFAULT_CONCURRENCY &&
|
193
|
+
!ld_concurrency &&
|
194
|
+
!override_data.key?('concurrency')
|
195
|
+
concurrency_warning = { option: 'concurrency',
|
196
|
+
msg: "Concurrency will default to #{default_concurrency} because ulimit "\
|
197
|
+
"is low: #{Etc.sysconf(Etc::SC_OPEN_MAX)}. Set concurrency with "\
|
198
|
+
"'--concurrency', or set your ulimit with 'ulimit -n <limit>'" }
|
199
|
+
@warnings << concurrency_warning
|
200
|
+
end
|
201
|
+
|
184
202
|
@data = merge_config_layers(default_data, *loaded_data, override_data)
|
185
203
|
|
186
204
|
TRANSPORT_CONFIG.each do |transport, config|
|
@@ -310,10 +328,10 @@ module Bolt
|
|
310
328
|
@warnings << { option: 'future', msg: msg }
|
311
329
|
end
|
312
330
|
|
313
|
-
keys = OPTIONS.keys - %w[plugins plugin_hooks]
|
331
|
+
keys = OPTIONS.keys - %w[plugins plugin_hooks puppetdb]
|
314
332
|
keys.each do |key|
|
315
333
|
next unless Bolt::Util.references?(@data[key])
|
316
|
-
valid_keys = TRANSPORT_CONFIG.keys + %w[plugins plugin_hooks]
|
334
|
+
valid_keys = TRANSPORT_CONFIG.keys + %w[plugins plugin_hooks puppetdb]
|
317
335
|
raise Bolt::ValidationError,
|
318
336
|
"Found unsupported key _plugin in config setting #{key}. Plugins are only available in "\
|
319
337
|
"#{valid_keys.join(', ')}."
|
@@ -456,5 +474,19 @@ module Bolt
|
|
456
474
|
l =~ /[A-Za-z]/ ? "[#{l.upcase}#{l.downcase}]" : l
|
457
475
|
end.join
|
458
476
|
end
|
477
|
+
|
478
|
+
# Etc::SC_OPEN_MAX is meaningless on windows, not defined in PE Jruby and not available
|
479
|
+
# on some platforms. This method holds the logic to decide whether or not to even consider it.
|
480
|
+
def sc_open_max_available?
|
481
|
+
!Bolt::Util.windows? && defined?(Etc::SC_OPEN_MAX) && Etc.sysconf(Etc::SC_OPEN_MAX)
|
482
|
+
end
|
483
|
+
|
484
|
+
def default_concurrency
|
485
|
+
@default_concurrency ||= if !sc_open_max_available? || Etc.sysconf(Etc::SC_OPEN_MAX) >= 300
|
486
|
+
DEFAULT_DEFAULT_CONCURRENCY
|
487
|
+
else
|
488
|
+
Etc.sysconf(Etc::SC_OPEN_MAX) / 3
|
489
|
+
end
|
490
|
+
end
|
459
491
|
end
|
460
492
|
end
|
@@ -7,6 +7,8 @@ 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 = {
|
11
13
|
"cleanup" => { type: TrueClass,
|
12
14
|
desc: "Whether to clean up temporary files created on targets." },
|
@@ -7,6 +7,8 @@ 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 = {
|
11
13
|
"cleanup" => { type: TrueClass,
|
12
14
|
desc: "Whether to clean up temporary files created on targets." },
|
@@ -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." },
|
@@ -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." }
|
@@ -8,16 +8,25 @@ module Bolt
|
|
8
8
|
module Transport
|
9
9
|
class SSH < Base
|
10
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
|
11
14
|
OPTIONS = {
|
12
15
|
"cleanup" => { type: TrueClass,
|
16
|
+
external: true,
|
13
17
|
desc: "Whether to clean up temporary files created on targets." },
|
14
18
|
"connect-timeout" => { type: Integer,
|
15
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.**" },
|
16
23
|
"disconnect-timeout" => { type: Integer,
|
17
24
|
desc: "How long to wait before force-closing a connection." },
|
18
25
|
"host" => { type: String,
|
26
|
+
external: true,
|
19
27
|
desc: "Host name." },
|
20
28
|
"host-key-check" => { type: TrueClass,
|
29
|
+
external: true,
|
21
30
|
desc: "Whether to perform host key validation when connecting." },
|
22
31
|
"extensions" => { type: Array,
|
23
32
|
desc: "List of file extensions that are accepted for scripts or tasks on Windows. "\
|
@@ -26,6 +35,7 @@ module Bolt
|
|
26
35
|
"a `.py` script runs with `python.exe`. The extensions `.ps1`, `.rb`, and "\
|
27
36
|
"`.pp` are always allowed and run via hard-coded executables." },
|
28
37
|
"interpreters" => { type: Hash,
|
38
|
+
external: true,
|
29
39
|
desc: "A map of an extension name to the absolute path of an executable, "\
|
30
40
|
"enabling you to override the shebang defined in a task executable. The "\
|
31
41
|
"extension can optionally be specified with the `.` character (`.py` and "\
|
@@ -41,26 +51,36 @@ module Bolt
|
|
41
51
|
"password" => { type: String,
|
42
52
|
desc: "Login password." },
|
43
53
|
"port" => { type: Integer,
|
54
|
+
external: true,
|
44
55
|
desc: "Connection port." },
|
45
|
-
"private-key" => {
|
56
|
+
"private-key" => { external: true,
|
57
|
+
desc: "Either the path to the private key file to use for authentication, or a "\
|
46
58
|
"hash with the key `key-data` and the contents of the private key." },
|
47
59
|
"proxyjump" => { type: String,
|
48
60
|
desc: "A jump host to proxy connections through, and an optional user to "\
|
49
61
|
"connect with." },
|
50
62
|
"run-as" => { type: String,
|
63
|
+
external: true,
|
51
64
|
desc: "A different user to run commands as after login." },
|
52
65
|
"run-as-command" => { type: Array,
|
66
|
+
external: true,
|
53
67
|
desc: "The command to elevate permissions. Bolt appends the user and command "\
|
54
68
|
"strings to the configured `run-as-command` before running it on the "\
|
55
69
|
"target. This command must not require an interactive password prompt, "\
|
56
70
|
"and the `sudo-password` option is ignored when `run-as-command` is "\
|
57
71
|
"specified. The `run-as-command` must be specified as an array." },
|
58
72
|
"script-dir" => { type: String,
|
73
|
+
external: true,
|
59
74
|
desc: "The subdirectory of the tmpdir to use in place of a randomized "\
|
60
75
|
"subdirectory for uploading and executing temporary files on the "\
|
61
76
|
"target. It's expected that this directory already exists as a subdir "\
|
62
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.**" },
|
63
82
|
"sudo-executable" => { type: String,
|
83
|
+
external: true,
|
64
84
|
desc: "The executable to use when escalating to the configured `run-as` "\
|
65
85
|
"user. This is useful when you want to escalate using the configured "\
|
66
86
|
"`sudo-password`, since `run-as-command` does not use `sudo-password` "\
|
@@ -68,14 +88,17 @@ module Bolt
|
|
68
88
|
"`<sudo-executable> -S -u <user> -p custom_bolt_prompt <command>`. "\
|
69
89
|
"**This option is experimental.**" },
|
70
90
|
"sudo-password" => { type: String,
|
91
|
+
external: true,
|
71
92
|
desc: "Password to use when changing users via `run-as`." },
|
72
93
|
"tmpdir" => { type: String,
|
94
|
+
external: true,
|
73
95
|
desc: "The directory to upload and execute temporary files on the target." },
|
74
96
|
"tty" => { type: TrueClass,
|
75
97
|
desc: "Request a pseudo tty for the session. This option is generally "\
|
76
98
|
"only used in conjunction with the `run-as` option when the sudoers "\
|
77
99
|
"policy requires a `tty`." },
|
78
100
|
"user" => { type: String,
|
101
|
+
external: true,
|
79
102
|
desc: "Login user." }
|
80
103
|
}.freeze
|
81
104
|
|
@@ -100,6 +123,13 @@ module Bolt
|
|
100
123
|
|
101
124
|
if key_opt.instance_of?(String)
|
102
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'
|
103
133
|
end
|
104
134
|
end
|
105
135
|
|
@@ -127,6 +157,25 @@ module Bolt
|
|
127
157
|
end
|
128
158
|
end
|
129
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
|
130
179
|
end
|
131
180
|
end
|
132
181
|
end
|