bolt 2.1.0 → 2.2.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.

Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/Puppetfile +5 -5
  3. data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +1 -1
  4. data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +1 -1
  5. data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +1 -1
  6. data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +1 -1
  7. data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +1 -1
  8. data/lib/bolt/applicator.rb +2 -2
  9. data/lib/bolt/bolt_option_parser.rb +1 -1
  10. data/lib/bolt/cli.rb +1 -1
  11. data/lib/bolt/config.rb +201 -206
  12. data/lib/bolt/config/transport/base.rb +142 -0
  13. data/lib/bolt/config/transport/docker.rb +42 -0
  14. data/lib/bolt/config/transport/local.rb +73 -0
  15. data/lib/bolt/config/transport/orch.rb +47 -0
  16. data/lib/bolt/config/transport/remote.rb +25 -0
  17. data/lib/bolt/config/transport/ssh.rb +105 -0
  18. data/lib/bolt/config/transport/winrm.rb +80 -0
  19. data/lib/bolt/executor.rb +17 -0
  20. data/lib/bolt/inventory.rb +12 -5
  21. data/lib/bolt/inventory/group.rb +1 -1
  22. data/lib/bolt/inventory/inventory.rb +16 -22
  23. data/lib/bolt/inventory/target.rb +26 -29
  24. data/lib/bolt/plugin.rb +5 -5
  25. data/lib/bolt/plugin/module.rb +1 -1
  26. data/lib/bolt/plugin/pkcs7.rb +1 -1
  27. data/lib/bolt/result.rb +1 -1
  28. data/lib/bolt/target.rb +5 -2
  29. data/lib/bolt/transport/base.rb +0 -18
  30. data/lib/bolt/transport/docker.rb +0 -26
  31. data/lib/bolt/transport/local.rb +0 -30
  32. data/lib/bolt/transport/local_windows.rb +4 -36
  33. data/lib/bolt/transport/orch.rb +0 -20
  34. data/lib/bolt/transport/remote.rb +0 -20
  35. data/lib/bolt/transport/ssh.rb +0 -85
  36. data/lib/bolt/transport/sudoable.rb +0 -7
  37. data/lib/bolt/transport/winrm.rb +0 -66
  38. data/lib/bolt/util.rb +11 -0
  39. data/lib/bolt/version.rb +1 -1
  40. data/lib/bolt_server/transport_app.rb +1 -0
  41. data/lib/bolt_spec/plans.rb +1 -1
  42. data/lib/bolt_spec/plans/action_stubs/command_stub.rb +1 -1
  43. data/lib/bolt_spec/plans/action_stubs/script_stub.rb +1 -1
  44. data/lib/bolt_spec/plans/action_stubs/task_stub.rb +2 -2
  45. data/lib/bolt_spec/plans/action_stubs/upload_stub.rb +1 -1
  46. data/lib/bolt_spec/run.rb +1 -1
  47. data/libexec/apply_catalog.rb +1 -1
  48. data/libexec/custom_facts.rb +1 -1
  49. data/libexec/query_resources.rb +1 -1
  50. metadata +9 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5d912a5ba19a113e4e5a57aed09f04f1a72a659b05fdb7cc09164146b59fc0cc
4
- data.tar.gz: 9344eaf150b512c769e8b6fd7ac91fef7ece7de62cb39bede4f22ebd15f52cd3
3
+ metadata.gz: 7875970096b75c44b55dc718b1586f8b360e11041198893207c9c146649b89b7
4
+ data.tar.gz: f81ded40f2a72fd9e83b0f63f1ea0d7d4a5148589d1bdb65de82c023335ed611
5
5
  SHA512:
6
- metadata.gz: 69040995cbcff577cfa377f50a80dc76825ba3aa0fd107788f146c26e5d562131ec089ce79f69c052b47b2fa9b2d7af3c9feb587829e6a4b9297ee9df2b9d9bd
7
- data.tar.gz: ef5b45003158f3f4801877e2c19768b990fa4c09d84fcce40888f4236bf025e0244ac5e5e4b5edc5397c3a49691390e650b0724a8450c3e10382fdee44b80f73
6
+ metadata.gz: 2e4c8c1857380c9177284ce567228058f2bd516541020c7926ebc7ea3af23ab89525f5a3d146b3c40a62721e89401b960e3b7071b3473094caaed00b4225bbb3
7
+ data.tar.gz: a299f639f5e211c4cee1d3dbca7fb3a5ce4b5a770840c8a7e2da1f620a92b7045637113522fe6e0856fe70a7d3e286d5d5563fae6c53bfc852ec893e87250b86
data/Puppetfile CHANGED
@@ -5,25 +5,25 @@ 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', '1.1.0'
8
+ mod 'puppetlabs-service', '1.2.0'
9
9
  mod 'puppetlabs-puppet_agent', '3.0.2'
10
10
  mod 'puppetlabs-facts', '1.0.0'
11
11
 
12
12
  # Core types and providers for Puppet 6
13
13
  mod 'puppetlabs-augeas_core', '1.0.5'
14
14
  mod 'puppetlabs-host_core', '1.0.3'
15
- mod 'puppetlabs-scheduled_task', '2.0.0'
15
+ mod 'puppetlabs-scheduled_task', '2.0.1'
16
16
  mod 'puppetlabs-sshkeys_core', '1.0.3'
17
17
  mod 'puppetlabs-zfs_core', '1.0.4'
18
18
  mod 'puppetlabs-cron_core', '1.0.3'
19
19
  mod 'puppetlabs-mount_core', '1.0.4'
20
20
  mod 'puppetlabs-selinux_core', '1.0.4'
21
- mod 'puppetlabs-yumrepo_core', '1.0.4'
21
+ mod 'puppetlabs-yumrepo_core', '1.0.6'
22
22
  mod 'puppetlabs-zone_core', '1.0.3'
23
23
 
24
24
  # Useful additional modules
25
- mod 'puppetlabs-package', '0.7.0'
26
- mod 'puppetlabs-puppet_conf', '0.4.0'
25
+ mod 'puppetlabs-package', '1.1.0'
26
+ mod 'puppetlabs-puppet_conf', '0.6.0'
27
27
  mod 'puppetlabs-python_task_helper', '0.3.0'
28
28
  mod 'puppetlabs-reboot', '3.0.0'
29
29
  mod 'puppetlabs-ruby_task_helper', '0.4.0'
@@ -51,7 +51,7 @@ Puppet::Functions.create_function(:run_command) do
51
51
  .from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, action: 'run_command')
52
52
  end
53
53
 
54
- options = options.map { |k, v| [k.sub(/^_/, '').to_sym, v] }.to_h
54
+ options = options.transform_keys { |k| k.sub(/^_/, '').to_sym }
55
55
  options[:description] = description if description
56
56
 
57
57
  executor = Puppet.lookup(:bolt_executor)
@@ -59,7 +59,7 @@ Puppet::Functions.create_function(:run_plan, Puppet::Functions::InternalFunction
59
59
  executor = Puppet.lookup(:bolt_executor)
60
60
 
61
61
  options, params = args.partition { |k, _v| k.start_with?('_') }.map(&:to_h)
62
- options = options.map { |k, v| [k.sub(/^_/, '').to_sym, v] }.to_h
62
+ options = options.transform_keys { |k| k.sub(/^_/, '').to_sym }
63
63
 
64
64
  # Bolt calls this function internally to trigger plans from the CLI. We
65
65
  # don't want to count those invocations.
@@ -58,7 +58,7 @@ Puppet::Functions.create_function(:run_script, Puppet::Functions::InternalFuncti
58
58
  end
59
59
 
60
60
  arguments = options['arguments'] || []
61
- options = options.select { |opt| opt.start_with?('_') }.map { |k, v| [k.sub(/^_/, '').to_sym, v] }.to_h
61
+ options = options.select { |opt| opt.start_with?('_') }.transform_keys { |k| k.sub(/^_/, '').to_sym }
62
62
  options[:description] = description if description
63
63
 
64
64
  executor = Puppet.lookup(:bolt_executor)
@@ -56,7 +56,7 @@ Puppet::Functions.create_function(:run_task) do
56
56
  end
57
57
 
58
58
  options, params = args.partition { |k, _v| k.start_with?('_') }.map(&:to_h)
59
- options = options.map { |k, v| [k.sub(/^_/, '').to_sym, v] }.to_h
59
+ options = options.transform_keys { |k| k.sub(/^_/, '').to_sym }
60
60
 
61
61
  executor = Puppet.lookup(:bolt_executor)
62
62
  inventory = Puppet.lookup(:bolt_inventory)
@@ -61,7 +61,7 @@ Puppet::Functions.create_function(:upload_file, Puppet::Functions::InternalFunct
61
61
  .from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, action: 'upload_file')
62
62
  end
63
63
 
64
- options = options.select { |opt| opt.start_with?('_') }.map { |k, v| [k.sub(/^_/, '').to_sym, v] }.to_h
64
+ options = options.select { |opt| opt.start_with?('_') }.transform_keys { |k| k.sub(/^_/, '').to_sym }
65
65
  options[:description] = description if description
66
66
 
67
67
  executor = Puppet.lookup(:bolt_executor)
@@ -151,7 +151,7 @@ module Bolt
151
151
  if args.count > 1
152
152
  type1 = Puppet.lookup(:pal_script_compiler).type('Hash[String, Data]')
153
153
  Puppet::Pal.assert_type(type1, args[1], 'apply options')
154
- options = args[1].map { |k, v| [k.sub(/^_/, '').to_sym, v] }.to_h
154
+ options = args[1].transform_keys { |k| k.sub(/^_/, '').to_sym }
155
155
  end
156
156
 
157
157
  plan_vars = scope.to_hash(true, true)
@@ -191,7 +191,7 @@ module Bolt
191
191
  hiera_config: @hiera_config,
192
192
  plan_vars: plan_vars,
193
193
  # This data isn't available on the target config hash
194
- config: @inventory.config.transport_data_get
194
+ config: @inventory.transport_data_get
195
195
  }
196
196
 
197
197
  description = options[:description] || 'apply catalog'
@@ -720,7 +720,7 @@ module Bolt
720
720
  define('--puppetfile FILEPATH',
721
721
  'Specify a Puppetfile to use when installing modules. (default: ~/.puppetlabs/bolt/Puppetfile)',
722
722
  'Modules are installed in the current Boltdir.') do |path|
723
- @options[:puppetfile] = Pathname.new(File.expand_path(path))
723
+ @options[:puppetfile_path] = Pathname.new(File.expand_path(path))
724
724
  end
725
725
  define('--[no-]save-rerun', 'Whether to update the rerun file after this command.') do |save|
726
726
  @options[:'save-rerun'] = save
@@ -714,7 +714,7 @@ module Bolt
714
714
  end
715
715
 
716
716
  def config_loaded
717
- msg = <<~MSG
717
+ msg = <<~MSG.chomp
718
718
  Loaded configuration from: '#{config.config_files.join("', '")}'
719
719
  MSG
720
720
  @logger.debug(msg)
@@ -5,25 +5,16 @@ require 'logging'
5
5
  require 'pathname'
6
6
  require 'bolt/boltdir'
7
7
  require 'bolt/logger'
8
- require 'bolt/transport/ssh'
9
- require 'bolt/transport/winrm'
10
- require 'bolt/transport/orch'
11
- require 'bolt/transport/local'
12
- require 'bolt/transport/local_windows'
13
- require 'bolt/transport/docker'
14
- require 'bolt/transport/remote'
15
8
  require 'bolt/util'
9
+ # Transport config objects
10
+ require 'bolt/config/transport/ssh'
11
+ require 'bolt/config/transport/winrm'
12
+ require 'bolt/config/transport/orch'
13
+ require 'bolt/config/transport/local'
14
+ require 'bolt/config/transport/docker'
15
+ require 'bolt/config/transport/remote'
16
16
 
17
17
  module Bolt
18
- TRANSPORTS = {
19
- ssh: Bolt::Transport::SSH,
20
- winrm: Bolt::Transport::WinRM,
21
- pcp: Bolt::Transport::Orch,
22
- local: Bolt::Util.windows? ? Bolt::Transport::LocalWindows : Bolt::Transport::Local,
23
- docker: Bolt::Transport::Docker,
24
- remote: Bolt::Transport::Remote
25
- }.freeze
26
-
27
18
  class UnknownTransportError < Bolt::Error
28
19
  def initialize(transport, uri = nil)
29
20
  msg = uri.nil? ? "Unknown transport #{transport}" : "Unknown transport #{transport} found for #{uri}"
@@ -32,12 +23,16 @@ module Bolt
32
23
  end
33
24
 
34
25
  class Config
35
- attr_accessor :concurrency, :format, :trace, :log, :puppetdb, :color, :save_rerun,
36
- :transport, :transports, :inventoryfile, :compile_concurrency, :boltdir,
37
- :puppetfile_config, :plugins, :plugin_hooks, :trusted_external,
38
- :apply_settings
39
- attr_writer :modulepath
40
- attr_reader :config_files, :warnings
26
+ attr_reader :config_files, :warnings, :data, :transports, :boltdir
27
+
28
+ TRANSPORT_CONFIG = {
29
+ 'ssh' => Bolt::Config::Transport::SSH,
30
+ 'winrm' => Bolt::Config::Transport::WinRM,
31
+ 'pcp' => Bolt::Config::Transport::Orch,
32
+ 'local' => Bolt::Config::Transport::Local,
33
+ 'docker' => Bolt::Config::Transport::Docker,
34
+ 'remote' => Bolt::Config::Transport::Remote
35
+ }.freeze
41
36
 
42
37
  OPTIONS = {
43
38
  "apply_settings" => "A map of Puppet settings to use when applying Puppet code",
@@ -154,52 +149,83 @@ module Bolt
154
149
  end
155
150
 
156
151
  @logger = Logging.logger[self]
157
-
158
- @boltdir = boltdir
159
- @concurrency = 100
160
- @compile_concurrency = Etc.nprocessors
161
- @transport = 'ssh'
162
- @format = 'human'
163
- @puppetdb = {}
164
- @color = true
165
- @save_rerun = true
166
- @puppetfile_config = {}
167
- @plugins = {}
168
- @plugin_hooks = {}
169
- @apply_settings = {}
170
152
  @warnings = []
171
-
172
- # add an entry for the default console logger
173
- @log = { 'console' => {} }
174
-
153
+ @boltdir = boltdir
175
154
  @transports = {}
155
+ @config_files = []
156
+
157
+ default_data = {
158
+ 'apply_settings' => {},
159
+ 'color' => true,
160
+ 'compile-concurrency' => Etc.nprocessors,
161
+ 'concurrency' => 100,
162
+ 'format' => 'human',
163
+ 'log' => { 'console' => {} },
164
+ 'plugin_hooks' => {},
165
+ 'plugins' => {},
166
+ 'puppetdb' => {},
167
+ 'puppetfile' => {},
168
+ 'save-rerun' => true,
169
+ 'transport' => 'ssh'
170
+ }
176
171
 
177
- TRANSPORTS.each do |key, transport|
178
- @transports[key] = transport.default_options
172
+ loaded_data = config_data.map do |config|
173
+ @config_files.push(config[:filepath])
174
+ config[:data]
179
175
  end
180
176
 
181
- @config_files = config_data.map { |config| config[:filepath] }
182
- config_data = merge_config_data(config_data)
183
- update_from_file(config_data)
177
+ override_data = normalize_overrides(overrides)
184
178
 
185
- apply_overrides(overrides)
179
+ @data = merge_config_layers(default_data, *loaded_data, override_data)
186
180
 
181
+ TRANSPORT_CONFIG.each do |transport, config|
182
+ @transports[transport] = config.new(@data.delete(transport), @boltdir.path)
183
+ end
184
+
185
+ finalize_data
187
186
  validate
188
187
  end
189
188
 
190
- # Merge configuration
191
- # Precedence from highest to lowest is: project, user-level, system-wide
192
- def merge_config_data(config_data)
189
+ # Transforms CLI options into a config hash that can be merged with
190
+ # default and loaded config.
191
+ def normalize_overrides(options)
192
+ opts = options.transform_keys(&:to_s)
193
+
194
+ # Pull out config options
195
+ overrides = opts.slice(*OPTIONS.keys)
196
+
197
+ # Pull out transport config options
198
+ TRANSPORT_CONFIG.each do |transport, config|
199
+ overrides[transport] = opts.slice(*config.options.keys)
200
+ end
201
+
202
+ # Set console log to debug if in debug mode
203
+ if options[:debug]
204
+ overrides['log'] = { 'console' => { 'level' => :debug } }
205
+ end
206
+
207
+ if options[:puppetfile_path]
208
+ @puppetfile = options[:puppetfile_path]
209
+ end
210
+
211
+ overrides['trace'] = opts['trace'] if opts.key?('trace')
212
+
213
+ overrides
214
+ end
215
+
216
+ # Merge configuration from all sources into a single hash. Precedence from lowest to highest:
217
+ # defaults, system-wide, user-level, project-level, CLI overrides
218
+ def merge_config_layers(*config_data)
193
219
  config_data.inject({}) do |acc, config|
194
- acc.merge(config[:data]) do |key, val1, val2|
220
+ acc.merge(config) do |key, val1, val2|
195
221
  case key
196
222
  # Plugin config is shallow merged for each plugin
197
223
  when 'plugins'
198
224
  val1.merge(val2) { |_, v1, v2| v1.merge(v2) }
199
225
  # Transports are deep merged
200
- when *TRANSPORTS.keys.map(&:to_s)
226
+ when *TRANSPORT_CONFIG.keys
201
227
  Bolt::Util.deep_merge(val1, val2)
202
- # Hash values are shallow mergeed
228
+ # Hash values are shallow merged
203
229
  when 'puppetdb', 'plugin_hooks', 'apply_settings', 'log'
204
230
  val1.merge(val2)
205
231
  # All other values are overwritten
@@ -210,229 +236,198 @@ module Bolt
210
236
  end
211
237
  end
212
238
 
213
- def overwrite_transport_data(transport, transports)
214
- @transport = transport
215
- @transports = transports
216
- end
217
-
218
- def transport_data_get
219
- { transport: @transport, transports: @transports }
220
- end
221
-
222
239
  def deep_clone
223
240
  Bolt::Util.deep_clone(self)
224
241
  end
225
242
 
226
- def normalize_log(target)
227
- return target if target == 'console'
228
- target = target[5..-1] if target.start_with?('file:')
229
- 'file:' + File.expand_path(target, @boltdir.path)
230
- end
231
-
232
- def update_logs(logs)
233
- logs.each_pair do |k, v|
234
- log_name = normalize_log(k)
235
- @log[log_name] ||= {}
236
- log = @log[log_name]
237
-
238
- next unless v.is_a?(Hash)
239
-
240
- if v.key?('level')
241
- log[:level] = v['level'].to_s
242
- end
243
-
244
- if v.key?('append')
245
- log[:append] = v['append']
246
- end
247
- end
248
- end
249
-
250
- def update_from_file(data)
251
- if data['future']
252
- msg = "Configuration option 'future' no longer exposes future behavior."
253
- @warnings << { option: 'future', msg: msg }
254
- end
255
-
256
- if data['log'].is_a?(Hash)
257
- update_logs(data['log'])
243
+ private def finalize_data
244
+ if @data['log'].is_a?(Hash)
245
+ @data['log'] = update_logs(@data['log'])
258
246
  end
259
247
 
260
248
  # Expand paths relative to the Boltdir. Any settings that came from the
261
249
  # CLI will already be absolute, so the expand will be skipped.
262
- if data.key?('modulepath')
250
+ if @data.key?('modulepath')
263
251
  moduledirs = if data['modulepath'].is_a?(String)
264
252
  data['modulepath'].split(File::PATH_SEPARATOR)
265
253
  else
266
254
  data['modulepath']
267
255
  end
268
- @modulepath = moduledirs.map do |moduledir|
256
+ @data['modulepath'] = moduledirs.map do |moduledir|
269
257
  File.expand_path(moduledir, @boltdir.path)
270
258
  end
271
259
  end
272
260
 
273
- @inventoryfile = File.expand_path(data['inventoryfile'], @boltdir.path) if data.key?('inventoryfile')
274
-
275
- if data.key?('puppetfile')
276
- @puppetfile_config = data['puppetfile'].select { |k, _| PUPPETFILE_OPTIONS.include?(k) }
261
+ %w[hiera-config inventoryfile trusted-external-command].each do |opt|
262
+ @data[opt] = File.expand_path(@data[opt], @boltdir.path) if @data.key?(opt)
277
263
  end
278
264
 
279
- @hiera_config = File.expand_path(data['hiera-config'], @boltdir.path) if data.key?('hiera-config')
280
- @trusted_external = if data.key?('trusted-external-command')
281
- File.expand_path(data['trusted-external-command'], @boltdir.path)
282
- end
265
+ # Filter hashes to only include valid options
266
+ @data['apply_settings'] = @data['apply_settings'].slice(*APPLY_SETTINGS.keys)
267
+ @data['puppetfile'] = @data['puppetfile'].slice(*PUPPETFILE_OPTIONS.keys)
268
+ end
283
269
 
284
- if data.key?('apply_settings')
285
- @apply_settings = data['apply_settings'].select { |k, _| APPLY_SETTINGS.keys.include?(k) }
286
- end
270
+ private def normalize_log(target)
271
+ return target if target == 'console'
272
+ target = target[5..-1] if target.start_with?('file:')
273
+ 'file:' + File.expand_path(target, @boltdir.path)
274
+ end
287
275
 
288
- @compile_concurrency = data['compile-concurrency'] if data.key?('compile-concurrency')
276
+ private def update_logs(logs)
277
+ logs.each_with_object({}) do |(key, val), acc|
278
+ next unless val.is_a?(Hash)
289
279
 
290
- @save_rerun = data['save-rerun'] if data.key?('save-rerun')
280
+ name = normalize_log(key)
281
+ acc[name] = val.slice(*LOG_OPTIONS.keys)
282
+ .transform_keys(&:to_sym)
291
283
 
292
- %w[concurrency format puppetdb color plugins plugin_hooks].each do |key|
293
- send("#{key}=", data[key]) if data.key?(key)
294
- end
284
+ if (v = acc[name][:level])
285
+ unless v.is_a?(String) || v.is_a?(Symbol)
286
+ raise Bolt::ValidationError,
287
+ "level of log #{name} must be a String or Symbol, received #{v.class} #{v.inspect}"
288
+ end
289
+ unless Bolt::Logger.valid_level?(v)
290
+ raise Bolt::ValidationError,
291
+ "level of log #{name} must be one of #{Bolt::Logger.levels.join(', ')}; received #{v}"
292
+ end
293
+ end
295
294
 
296
- update_transports(data)
295
+ if (v = acc[name][:append]) && v != true && v != false
296
+ raise Bolt::ValidationError,
297
+ "append flag of log #{name} must be a Boolean, received #{v.class} #{v.inspect}"
298
+ end
299
+ end
297
300
  end
298
- private :update_from_file
299
301
 
300
- def apply_overrides(options)
301
- %i[concurrency transport format trace modulepath inventoryfile color].each do |key|
302
- send("#{key}=", options[key]) if options.key?(key)
302
+ def validate
303
+ if @data['future']
304
+ msg = "Configuration option 'future' no longer exposes future behavior."
305
+ @warnings << { option: 'future', msg: msg }
303
306
  end
304
307
 
305
- @puppetfile = options[:puppetfile] if options.key?(:puppetfile)
306
-
307
- @save_rerun = options[:'save-rerun'] if options.key?(:'save-rerun')
308
-
309
- if options[:debug]
310
- @log['console'][:level] = :debug
308
+ keys = OPTIONS.keys - %w[plugins plugin_hooks]
309
+ keys.each do |key|
310
+ next unless Bolt::Util.references?(@data[key])
311
+ valid_keys = TRANSPORT_CONFIG.keys + %w[plugins plugin_hooks]
312
+ raise Bolt::ValidationError,
313
+ "Found unsupported key _plugin in config setting #{key}. Plugins are only available in "\
314
+ "#{valid_keys.join(', ')}."
311
315
  end
312
316
 
313
- @compile_concurrency = options[:'compile-concurrency'] if options[:'compile-concurrency']
317
+ unless concurrency.is_a?(Integer) && concurrency > 0
318
+ raise Bolt::ValidationError,
319
+ "Concurrency must be a positive Integer, received #{concurrency.class} #{concurrency}"
320
+ end
314
321
 
315
- TRANSPORTS.each_key do |transport|
316
- # Get the options first since transport is modified in the next line
317
- transport_options = TRANSPORTS[transport]::OPTIONS.keys.map(&:to_sym)
318
- transport = @transports[transport]
319
- transport_options.each do |key|
320
- if options[key]
321
- transport[key.to_s] = Bolt::Util.walk_keys(options[key], &:to_s)
322
- end
323
- end
322
+ unless compile_concurrency.is_a?(Integer) && compile_concurrency > 0
323
+ raise Bolt::ValidationError,
324
+ "Compile concurrency must be a positive Integer, received #{compile_concurrency.class} "\
325
+ "#{compile_concurrency}"
324
326
  end
325
327
 
326
- if options.key?(:ssl) # this defaults to true so we need to check the presence of the key
327
- @transports[:winrm]['ssl'] = options[:ssl]
328
+ compile_limit = 2 * Etc.nprocessors
329
+ unless compile_concurrency < compile_limit
330
+ raise Bolt::ValidationError, "Compilation is CPU-intensive, set concurrency less than #{compile_limit}"
328
331
  end
329
332
 
330
- if options.key?(:'ssl-verify') # this defaults to true so we need to check the presence of the key
331
- @transports[:winrm]['ssl-verify'] = options[:'ssl-verify']
333
+ unless %w[human json].include? format
334
+ raise Bolt::ValidationError, "Unsupported format: '#{format}'"
332
335
  end
333
336
 
334
- if options.key?(:'host-key-check') # this defaults to true so we need to check the presence of the key
335
- @transports[:ssh]['host-key-check'] = options[:'host-key-check']
337
+ Bolt::Util.validate_file('hiera-config', @data['hiera_config']) if @data['hiera_config']
338
+ Bolt::Util.validate_file('trusted-external-command', trusted_external) if trusted_external
339
+
340
+ unless TRANSPORT_CONFIG.include?(transport)
341
+ raise UnknownTransportError, transport
336
342
  end
337
343
  end
338
344
 
339
- def update_from_inventory(data)
340
- update_transports(data)
345
+ def default_inventoryfile
346
+ @boltdir.inventory_file
341
347
  end
342
348
 
343
- def update_transports(data)
344
- self.class.update_transport_hash(@boltdir.path, @transports, data)
345
- @transport = data['transport'] if data.key?('transport')
349
+ def rerunfile
350
+ @boltdir.rerunfile
346
351
  end
347
352
 
348
- def self.update_transport_hash(boltdir, existing, data)
349
- TRANSPORTS.each do |key, impl|
350
- if data[key.to_s]
351
- selected = impl.filter_options(data[key.to_s])
353
+ def hiera_config
354
+ @data['hiera-config'] || @boltdir.hiera_config
355
+ end
352
356
 
353
- # Expand file paths relative to the Boltdir
354
- to_expand = %w[private-key cacert token-file] & selected.keys
355
- to_expand.each do |opt|
356
- selected[opt] = File.expand_path(selected[opt], boltdir) if selected[opt].is_a?(String)
357
- end
357
+ def puppetfile
358
+ @puppetfile || @boltdir.puppetfile
359
+ end
358
360
 
359
- existing[key] = Bolt::Util.deep_merge(existing[key], selected)
360
- end
361
- if existing[key]['interpreters']
362
- existing[key]['interpreters'] = normalize_interpreters(existing[key]['interpreters'])
363
- end
364
- end
361
+ def modulepath
362
+ @data['modulepath'] || @boltdir.modulepath
365
363
  end
366
364
 
367
- def self.normalize_interpreters(interpreters)
368
- Bolt::Util.walk_keys(interpreters) do |key|
369
- key.chars[0] == '.' ? key : '.' + key
370
- end
365
+ def modulepath=(value)
366
+ @data['modulepath'] = value
371
367
  end
372
368
 
373
- def transport_conf
374
- { transport: @transport,
375
- transports: @transports }
369
+ def concurrency
370
+ @data['concurrency']
376
371
  end
377
372
 
378
- def default_inventoryfile
379
- @boltdir.inventory_file
373
+ def format
374
+ @data['format']
380
375
  end
381
376
 
382
- def rerunfile
383
- @boltdir.rerunfile
377
+ def format=(value)
378
+ @data['format'] = value
384
379
  end
385
380
 
386
- def hiera_config
387
- @hiera_config || @boltdir.hiera_config
381
+ def trace
382
+ @data['trace']
388
383
  end
389
384
 
390
- def puppetfile
391
- @puppetfile || @boltdir.puppetfile
385
+ def log
386
+ @data['log']
392
387
  end
393
388
 
394
- def modulepath
395
- @modulepath || @boltdir.modulepath
389
+ def puppetdb
390
+ @data['puppetdb']
396
391
  end
397
392
 
398
- def validate
399
- @log.each_pair do |name, params|
400
- if params.key?(:level) && !Bolt::Logger.valid_level?(params[:level])
401
- raise Bolt::ValidationError,
402
- "level of log #{name} must be one of: #{Bolt::Logger.levels.join(', ')}; received #{params[:level]}"
403
- end
404
- if params.key?(:append) && params[:append] != true && params[:append] != false
405
- raise Bolt::ValidationError, "append flag of log #{name} must be a Boolean, received #{params[:append]}"
406
- end
407
- end
393
+ def color
394
+ @data['color']
395
+ end
408
396
 
409
- unless @concurrency.is_a?(Integer) && @concurrency > 0
410
- raise Bolt::ValidationError, 'Concurrency must be a positive integer'
411
- end
397
+ def save_rerun
398
+ @data['save-rerun']
399
+ end
412
400
 
413
- unless @compile_concurrency.is_a?(Integer) && @compile_concurrency > 0
414
- raise Bolt::ValidationError, 'Compile concurrency must be a positive integer'
415
- end
401
+ def inventoryfile
402
+ @data['inventoryfile']
403
+ end
416
404
 
417
- compile_limit = 2 * Etc.nprocessors
418
- unless @compile_concurrency < compile_limit
419
- raise Bolt::ValidationError, "Compilation is CPU-intensive, set concurrency less than #{compile_limit}"
420
- end
405
+ def compile_concurrency
406
+ @data['compile-concurrency']
407
+ end
421
408
 
422
- unless %w[human json].include? @format
423
- raise Bolt::ValidationError, "Unsupported format: '#{@format}'"
424
- end
409
+ def puppetfile_config
410
+ @data['puppetfile']
411
+ end
412
+
413
+ def plugins
414
+ @data['plugins']
415
+ end
425
416
 
426
- Bolt::Util.validate_file('hiera-config', @hiera_config) if @hiera_config
427
- Bolt::Util.validate_file('trusted-external-command', @trusted_external) if @trusted_external
417
+ def plugin_hooks
418
+ @data['plugin_hooks']
419
+ end
428
420
 
429
- unless @transport.nil? || Bolt::TRANSPORTS.include?(@transport.to_sym)
430
- raise UnknownTransportError, @transport
431
- end
421
+ def trusted_external
422
+ @data['trusted-external-command']
423
+ end
432
424
 
433
- TRANSPORTS.each do |transport, impl|
434
- impl.validate(@transports[transport])
435
- end
425
+ def apply_settings
426
+ @data['apply_settings']
427
+ end
428
+
429
+ def transport
430
+ @data['transport']
436
431
  end
437
432
 
438
433
  # Check if there is a case-insensitive match to the path
@@ -451,7 +446,7 @@ module Bolt
451
446
  [*paths].map { |p| Dir.glob([p, casefold(p)]) }.flatten.uniq.reject { |p| [*paths].include?(p) }
452
447
  end
453
448
 
454
- def casefold(path)
449
+ private def casefold(path)
455
450
  path.chars.map do |l|
456
451
  l =~ /[A-Za-z]/ ? "[#{l.upcase}#{l.downcase}]" : l
457
452
  end.join