bolt 2.42.0 → 3.3.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 (90) hide show
  1. checksums.yaml +4 -4
  2. data/Puppetfile +21 -19
  3. data/bolt-modules/boltlib/lib/puppet/functions/add_facts.rb +1 -1
  4. data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +25 -0
  5. data/bolt-modules/boltlib/lib/puppet/functions/parallelize.rb +6 -8
  6. data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +2 -2
  7. data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +27 -5
  8. data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +1 -1
  9. data/bolt-modules/boltlib/lib/puppet/functions/wait_until_available.rb +7 -3
  10. data/bolt-modules/file/lib/puppet/functions/file/read.rb +3 -2
  11. data/lib/bolt/analytics.rb +3 -2
  12. data/lib/bolt/applicator.rb +11 -1
  13. data/lib/bolt/apply_result.rb +1 -1
  14. data/lib/bolt/bolt_option_parser.rb +9 -116
  15. data/lib/bolt/catalog.rb +10 -29
  16. data/lib/bolt/cli.rb +90 -154
  17. data/lib/bolt/config.rb +66 -239
  18. data/lib/bolt/config/options.rb +79 -102
  19. data/lib/bolt/config/transport/local.rb +1 -0
  20. data/lib/bolt/config/transport/lxd.rb +21 -0
  21. data/lib/bolt/config/transport/options.rb +9 -2
  22. data/lib/bolt/config/transport/orch.rb +1 -0
  23. data/lib/bolt/executor.rb +23 -6
  24. data/lib/bolt/inventory.rb +1 -1
  25. data/lib/bolt/inventory/group.rb +7 -4
  26. data/lib/bolt/logger.rb +123 -11
  27. data/lib/bolt/module_installer.rb +6 -4
  28. data/lib/bolt/module_installer/puppetfile.rb +2 -2
  29. data/lib/bolt/module_installer/resolver.rb +59 -14
  30. data/lib/bolt/module_installer/specs/forge_spec.rb +10 -4
  31. data/lib/bolt/module_installer/specs/git_spec.rb +19 -4
  32. data/lib/bolt/outputter/human.rb +56 -17
  33. data/lib/bolt/outputter/json.rb +16 -16
  34. data/lib/bolt/outputter/rainbow.rb +3 -3
  35. data/lib/bolt/pal.rb +95 -15
  36. data/lib/bolt/pal/yaml_plan.rb +9 -4
  37. data/lib/bolt/pal/yaml_plan/evaluator.rb +5 -153
  38. data/lib/bolt/pal/yaml_plan/step.rb +91 -52
  39. data/lib/bolt/pal/yaml_plan/step/command.rb +16 -16
  40. data/lib/bolt/pal/yaml_plan/step/download.rb +15 -16
  41. data/lib/bolt/pal/yaml_plan/step/eval.rb +11 -11
  42. data/lib/bolt/pal/yaml_plan/step/message.rb +13 -4
  43. data/lib/bolt/pal/yaml_plan/step/plan.rb +19 -15
  44. data/lib/bolt/pal/yaml_plan/step/resources.rb +82 -21
  45. data/lib/bolt/pal/yaml_plan/step/script.rb +32 -17
  46. data/lib/bolt/pal/yaml_plan/step/task.rb +19 -16
  47. data/lib/bolt/pal/yaml_plan/step/upload.rb +16 -17
  48. data/lib/bolt/pal/yaml_plan/transpiler.rb +2 -1
  49. data/lib/bolt/plan_creator.rb +1 -1
  50. data/lib/bolt/plugin.rb +2 -2
  51. data/lib/bolt/plugin/cache.rb +7 -7
  52. data/lib/bolt/plugin/module.rb +0 -23
  53. data/lib/bolt/plugin/puppet_connect_data.rb +77 -0
  54. data/lib/bolt/plugin/puppetdb.rb +1 -1
  55. data/lib/bolt/project.rb +54 -81
  56. data/lib/bolt/project_manager.rb +5 -4
  57. data/lib/bolt/project_manager/module_migrator.rb +7 -6
  58. data/lib/bolt/rerun.rb +1 -1
  59. data/lib/bolt/result.rb +6 -1
  60. data/lib/bolt/shell.rb +16 -0
  61. data/lib/bolt/shell/bash.rb +57 -25
  62. data/lib/bolt/shell/bash/tmpdir.rb +6 -3
  63. data/lib/bolt/shell/powershell.rb +33 -10
  64. data/lib/bolt/shell/powershell/snippets.rb +37 -150
  65. data/lib/bolt/task.rb +2 -2
  66. data/lib/bolt/transport/base.rb +0 -9
  67. data/lib/bolt/transport/docker.rb +1 -125
  68. data/lib/bolt/transport/docker/connection.rb +86 -161
  69. data/lib/bolt/transport/local.rb +1 -9
  70. data/lib/bolt/transport/lxd.rb +26 -0
  71. data/lib/bolt/transport/lxd/connection.rb +99 -0
  72. data/lib/bolt/transport/orch/connection.rb +1 -1
  73. data/lib/bolt/transport/ssh.rb +1 -2
  74. data/lib/bolt/transport/ssh/connection.rb +2 -2
  75. data/lib/bolt/transport/winrm/connection.rb +1 -1
  76. data/lib/bolt/validator.rb +2 -2
  77. data/lib/bolt/version.rb +1 -1
  78. data/lib/bolt_server/config.rb +1 -1
  79. data/lib/bolt_server/transport_app.rb +61 -32
  80. data/lib/bolt_spec/bolt_context.rb +9 -4
  81. data/lib/bolt_spec/plans.rb +1 -109
  82. data/lib/bolt_spec/plans/action_stubs.rb +1 -1
  83. data/lib/bolt_spec/plans/mock_executor.rb +4 -0
  84. data/libexec/bolt_catalog +1 -1
  85. data/modules/aggregate/plans/count.pp +21 -0
  86. data/modules/aggregate/plans/targets.pp +21 -0
  87. data/modules/puppet_connect/plans/test_input_data.pp +67 -0
  88. data/modules/puppetdb_fact/plans/init.pp +10 -0
  89. metadata +13 -9
  90. data/modules/aggregate/plans/nodes.pp +0 -36
@@ -11,18 +11,10 @@ module Bolt
11
11
  end
12
12
 
13
13
  def with_connection(target)
14
- if target.transport_config['bundled-ruby'] || target.name == 'localhost'
14
+ if target.transport_config['bundled-ruby']
15
15
  target.set_local_defaults
16
16
  end
17
17
 
18
- if target.name != 'localhost' &&
19
- !target.transport_config.key?('bundled-ruby')
20
- msg = "The local transport will default to using Bolt's Ruby interpreter and "\
21
- "setting the 'puppet-agent' feature in Bolt 3.0. Enable or disable these "\
22
- "defaults by setting 'bundled-ruby' in the local transport config."
23
- Bolt::Logger.warn_once('local default config', msg)
24
- end
25
-
26
18
  yield Connection.new(target)
27
19
  end
28
20
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bolt/logger'
4
+ require 'bolt/node/errors'
5
+ require 'bolt/transport/simple'
6
+
7
+ module Bolt
8
+ module Transport
9
+ class LXD < Simple
10
+ def provided_features
11
+ ['shell']
12
+ end
13
+
14
+ def with_connection(target, options = {})
15
+ Bolt::Logger.warn_once("lxd_experimental",
16
+ "The LXD transport is experimental, and might "\
17
+ "include breaking changes between minor versions.")
18
+ conn = Connection.new(target, options)
19
+ conn.connect
20
+ yield conn
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ require 'bolt/transport/lxd/connection'
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logging'
4
+ require 'bolt/node/errors'
5
+
6
+ module Bolt
7
+ module Transport
8
+ class LXD < Simple
9
+ class Connection
10
+ attr_reader :user, :target
11
+
12
+ def initialize(target, options)
13
+ raise Bolt::ValidationError, "Target #{target.safe_name} does not have a host" unless target.host
14
+
15
+ @target = target
16
+ @user = ENV['USER'] || Etc.getlogin
17
+ @options = options
18
+ @logger = Bolt::Logger.logger(target.safe_name)
19
+ @logger.trace("Initializing LXD connection to #{target.safe_name}")
20
+ end
21
+
22
+ def shell
23
+ Bolt::Shell::Bash.new(target, self)
24
+ end
25
+
26
+ def container_id
27
+ "local:#{@target.host}"
28
+ end
29
+
30
+ def connect
31
+ out, err, status = execute_local_command(%w[list --format json])
32
+ unless status.exitstatus.zero?
33
+ raise "Error listing available containers: #{err}"
34
+ end
35
+ containers = JSON.parse(out).map { |c| c['name'] }
36
+ unless containers.include?(@target.host)
37
+ raise "Could not find a container with name or ID matching '#{@target.host}'"
38
+ end
39
+ @logger.trace("Opened session")
40
+ true
41
+ rescue StandardError => e
42
+ raise Bolt::Node::ConnectError.new(
43
+ "Failed to connect to #{container_id}: #{e.message}",
44
+ 'CONNECT_ERROR'
45
+ )
46
+ end
47
+
48
+ def add_env_vars(env_vars)
49
+ @env_vars = env_vars.each_with_object([]) do |env_var, acc|
50
+ acc << "--env"
51
+ acc << "#{env_var[0]}=#{Shellwords.shellescape(env_var[1])}"
52
+ end
53
+ end
54
+
55
+ def execute(command)
56
+ lxc_command = %w[lxc exec]
57
+ lxc_command += @env_vars if @env_vars
58
+ lxc_command += %W[#{container_id} -- sh -c #{Shellwords.shellescape(command)}]
59
+
60
+ @logger.trace { "Executing: #{lxc_command.join(' ')}" }
61
+ Open3.popen3(lxc_command.join(' '))
62
+ end
63
+
64
+ private def execute_local_command(command)
65
+ Open3.capture3('lxc', *command, { binmode: true })
66
+ end
67
+
68
+ def upload_file(source, destination)
69
+ @logger.trace { "Uploading #{source} to #{destination}" }
70
+ args = %w[--create-dirs]
71
+ if File.directory?(source)
72
+ args << '--recursive'
73
+ # If we don't do this, LXD will upload to
74
+ # /tmp/d2020-11/d2020-11/dir instead of /tmp/d2020-11/dir
75
+ destination = Pathname.new(destination).dirname.to_s
76
+ end
77
+ cmd = %w[file push] + args + %W[#{source} #{container_id}#{destination}]
78
+ _out, err, stat = execute_local_command(cmd)
79
+ unless stat.exitstatus.zero?
80
+ raise "Error writing to #{container_id}: #{err}"
81
+ end
82
+ rescue StandardError => e
83
+ raise Bolt::Node::FileError.new(e.message, 'WRITE_ERROR')
84
+ end
85
+
86
+ def download_file(source, destination, _download)
87
+ @logger.trace { "Downloading #{source} to #{destination}" }
88
+ FileUtils.mkdir_p(destination)
89
+ _out, err, stat = execute_local_command(%W[file pull --recursive #{container_id}#{source} #{destination}])
90
+ unless stat.exitstatus.zero?
91
+ raise "Error downloading content from container #{container_id}: #{err}"
92
+ end
93
+ rescue StandardError => e
94
+ raise Bolt::Node::FileError.new(e.message, 'WRITE_ERROR')
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -21,7 +21,7 @@ module Bolt
21
21
 
22
22
  @logger = logger
23
23
  @key = self.class.get_key(opts)
24
- client_opts = opts.slice('token-file', 'cacert', 'job-poll-interval', 'job-poll-timeout')
24
+ client_opts = opts.slice('token-file', 'cacert', 'job-poll-interval', 'job-poll-timeout', 'read-timeout')
25
25
 
26
26
  if opts['service-url']
27
27
  uri = Addressable::URI.parse(opts['service-url'])
@@ -23,8 +23,7 @@ module Bolt
23
23
 
24
24
  def with_connection(target)
25
25
  if target.transport_config['ssh-command'] && !target.transport_config['native-ssh']
26
- Bolt::Logger.warn_once("ssh-command and native-ssh conflict",
27
- "native-ssh must be true to use ssh-command")
26
+ Bolt::Logger.warn_once("native_ssh_disabled", "native-ssh must be true to use ssh-command")
28
27
  end
29
28
 
30
29
  conn = if target.transport_config['native-ssh']
@@ -34,7 +34,7 @@ module Bolt
34
34
  begin
35
35
  Bolt::Util.validate_file('ssh key', target.options['private-key'])
36
36
  rescue Bolt::FileError => e
37
- @logger.warn(e.msg)
37
+ Bolt::Logger.warn("invalid_ssh_key", e.msg)
38
38
  end
39
39
  end
40
40
  end
@@ -230,7 +230,7 @@ module Bolt
230
230
  end
231
231
  [in_wr, out_rd, err_rd, th]
232
232
  rescue Errno::EMFILE => e
233
- msg = "#{e.message}. This may be resolved by increasing your user limit "\
233
+ msg = "#{e.message}. This might be resolved by increasing your user limit "\
234
234
  "with 'ulimit -n 1024'. See https://puppet.com/docs/bolt/latest/bolt_known_issues.html for details."
235
235
  raise Bolt::Error.new(msg, 'bolt/too-many-files')
236
236
  end
@@ -130,7 +130,7 @@ module Bolt
130
130
 
131
131
  [inp, out_rd, err_rd, th]
132
132
  rescue Errno::EMFILE => e
133
- msg = "#{e.message}. This may be resolved by increasing your user limit "\
133
+ msg = "#{e.message}. This might be resolved by increasing your user limit "\
134
134
  "with 'ulimit -n 1024'. See https://puppet.com/docs/bolt/latest/bolt_known_issues.html for details."
135
135
  raise Bolt::Error.new(msg, 'bolt/too-many-files')
136
136
  rescue StandardError
@@ -147,7 +147,7 @@ module Bolt
147
147
  message += " at '#{path}'" if @path.any?
148
148
  message += " at #{@location}" if @location
149
149
  message += "."
150
- @warnings << message
150
+ @warnings << { id: 'unknown_option', msg: message }
151
151
  end
152
152
  end
153
153
 
@@ -160,7 +160,7 @@ module Bolt
160
160
  message = "Option '#{path}' "
161
161
  message += "at #{@location} " if @location
162
162
  message += "is deprecated. #{definition[:_deprecation]}"
163
- @deprecations << { option: key, message: message }
163
+ @deprecations << { id: "#{key}_option", msg: message }
164
164
  end
165
165
  end
166
166
 
data/lib/bolt/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bolt
4
- VERSION = '2.42.0'
4
+ VERSION = '3.3.0'
5
5
  end
@@ -9,7 +9,7 @@ module BoltServer
9
9
  def config_keys
10
10
  super + %w[concurrency cache-dir file-server-conn-timeout
11
11
  file-server-uri projects-dir environments-codedir
12
- environmentpath basemodulepath]
12
+ environmentpath basemodulepath builtin-content-dir]
13
13
  end
14
14
 
15
15
  def env_keys
@@ -133,7 +133,14 @@ module BoltServer
133
133
  task_data = body['task']
134
134
  task = Bolt::Task::PuppetServer.new(task_data['name'], task_data['metadata'], task_data['files'], @file_cache)
135
135
  parameters = body['parameters'] || {}
136
- [@executor.run_task(target, task, parameters), nil]
136
+ task_result = @executor.run_task(target, task, parameters)
137
+ task_result.each do |result|
138
+ value = result.value
139
+ next unless value.is_a?(Hash)
140
+ next unless value.key?('_sensitive')
141
+ value['_sensitive'] = value['_sensitive'].unwrap
142
+ end
143
+ [task_result, nil]
137
144
  end
138
145
 
139
146
  def run_command(target, body)
@@ -275,14 +282,19 @@ module BoltServer
275
282
  Bolt::Config.from_project(project, { log: { 'bolt-debug.log' => 'disable' } })
276
283
  end
277
284
 
285
+ def pal_from_project_bolt_config(bolt_config)
286
+ modulepath_object = Bolt::Config::Modulepath.new(
287
+ bolt_config.modulepath,
288
+ boltlib_path: [PE_BOLTLIB_PATH, Bolt::Config::Modulepath::BOLTLIB_PATH],
289
+ builtin_content_path: @config['builtin-content-dir']
290
+ )
291
+ Bolt::PAL.new(modulepath_object, nil, nil, nil, nil, nil, bolt_config.project)
292
+ end
293
+
278
294
  def in_bolt_project(versioned_project)
279
295
  @pal_mutex.synchronize do
280
296
  bolt_config = config_from_project(versioned_project)
281
- modulepath_object = Bolt::Config::Modulepath.new(
282
- bolt_config.modulepath,
283
- boltlib_path: [PE_BOLTLIB_PATH, Bolt::Config::Modulepath::BOLTLIB_PATH]
284
- )
285
- pal = Bolt::PAL.new(modulepath_object, nil, nil, nil, nil, nil, bolt_config.project)
297
+ pal = pal_from_project_bolt_config(bolt_config)
286
298
  context = {
287
299
  pal: pal,
288
300
  config: bolt_config
@@ -350,8 +362,8 @@ module BoltServer
350
362
  }
351
363
  end
352
364
 
353
- def allowed_helper(metadata, allowlist)
354
- allowed = allowlist.nil? || allowlist.include?(metadata['name']) ? true : false
365
+ def allowed_helper(pal, metadata, allowlist)
366
+ allowed = !pal.filter_content([metadata['name']], allowlist).empty?
355
367
  metadata.merge({ 'allowed' => allowed })
356
368
  end
357
369
 
@@ -365,21 +377,27 @@ module BoltServer
365
377
  plans.map { |plan_name| { 'name' => plan_name } }
366
378
  end
367
379
 
368
- def file_metadatas(pal, module_name, file)
369
- pal.in_bolt_compiler do
370
- mod = Puppet.lookup(:current_environment).module(module_name)
371
- raise ArgumentError, "`module_name`: #{module_name} does not exist" unless mod
372
- abs_file_path = mod.file(file)
373
- raise ArgumentError, "`file`: #{file} does not exist inside the module's 'files' directory" unless abs_file_path
374
- fileset = Puppet::FileServing::Fileset.new(abs_file_path, 'recurse' => 'yes')
375
- Puppet::FileServing::Fileset.merge(fileset).collect do |relative_file_path, base_path|
376
- metadata = Puppet::FileServing::Metadata.new(base_path, relative_path: relative_file_path)
377
- metadata.checksum_type = 'sha256'
378
- metadata.links = 'follow'
379
- metadata.collect
380
- metadata.to_data_hash
380
+ def file_metadatas(versioned_project, module_name, file)
381
+ abs_file_path = @pal_mutex.synchronize do
382
+ bolt_config = config_from_project(versioned_project)
383
+ pal = pal_from_project_bolt_config(bolt_config)
384
+ pal.in_bolt_compiler do
385
+ mod = Puppet.lookup(:current_environment).module(module_name)
386
+ raise ArgumentError, "`module_name`: #{module_name} does not exist" unless mod
387
+ mod.file(file)
381
388
  end
382
389
  end
390
+
391
+ raise ArgumentError, "`file`: #{file} does not exist inside the module's 'files' directory" unless abs_file_path
392
+
393
+ fileset = Puppet::FileServing::Fileset.new(abs_file_path, 'recurse' => 'yes')
394
+ Puppet::FileServing::Fileset.merge(fileset).collect do |relative_file_path, base_path|
395
+ metadata = Puppet::FileServing::Metadata.new(base_path, relative_path: relative_file_path)
396
+ metadata.checksum_type = 'sha256'
397
+ metadata.links = 'follow'
398
+ metadata.collect
399
+ metadata.to_data_hash
400
+ end
383
401
  end
384
402
 
385
403
  get '/' do
@@ -519,7 +537,7 @@ module BoltServer
519
537
  return MISSING_VERSIONED_PROJECT_RESPONSE if params['versioned_project'].nil?
520
538
  in_bolt_project(params['versioned_project']) do |context|
521
539
  plan_info = pe_plan_info(context[:pal], params[:module_name], params[:plan_name])
522
- plan_info = allowed_helper(plan_info, context[:config].project.plans)
540
+ plan_info = allowed_helper(context[:pal], plan_info, context[:config].project.plans)
523
541
  [200, plan_info.to_json]
524
542
  end
525
543
  rescue Bolt::Error => e
@@ -549,7 +567,7 @@ module BoltServer
549
567
  'versioned_project' => params['versioned_project']
550
568
  }
551
569
  task_info = pe_task_info(context[:pal], params[:module_name], params[:task_name], ps_parameters)
552
- task_info = allowed_helper(task_info, context[:config].project.tasks)
570
+ task_info = allowed_helper(context[:pal], task_info, context[:config].project.tasks)
553
571
  [200, task_info.to_json]
554
572
  end
555
573
  rescue Bolt::Error => e
@@ -589,7 +607,7 @@ module BoltServer
589
607
  plans_response = plan_list(context[:pal])
590
608
 
591
609
  # Dig in context for the allowlist of plans from project object
592
- plans_response.map! { |metadata| allowed_helper(metadata, context[:config].project.plans) }
610
+ plans_response.map! { |metadata| allowed_helper(context[:pal], metadata, context[:config].project.plans) }
593
611
 
594
612
  # We structure this array of plans to be an array of hashes so that it matches the structure
595
613
  # returned by the puppetserver API that serves data like this. Structuring the output this way
@@ -625,7 +643,7 @@ module BoltServer
625
643
  tasks_response = task_list(context[:pal])
626
644
 
627
645
  # Dig in context for the allowlist of tasks from project object
628
- tasks_response.map! { |metadata| allowed_helper(metadata, context[:config].project.tasks) }
646
+ tasks_response.map! { |metadata| allowed_helper(context[:pal], metadata, context[:config].project.tasks) }
629
647
 
630
648
  # We structure this array of tasks to be an array of hashes so that it matches the structure
631
649
  # returned by the puppetserver API that serves data like this. Structuring the output this way
@@ -641,12 +659,11 @@ module BoltServer
641
659
  #
642
660
  # @param versioned_project [String] the versioned_project to fetch the file metadatas from
643
661
  get '/project_file_metadatas/:module_name/*' do
644
- return MISSING_VERSIONED_PROJECT_RESPONSE if params['versioned_project'].nil?
645
- in_bolt_project(params['versioned_project']) do |context|
646
- file = params[:splat].first
647
- metadatas = file_metadatas(context[:pal], params[:module_name], file)
648
- [200, metadatas.to_json]
649
- end
662
+ versioned_project = params['versioned_project']
663
+ return MISSING_VERSIONED_PROJECT_RESPONSE if versioned_project.nil?
664
+ file = params[:splat].first
665
+ metadatas = file_metadatas(versioned_project, params[:module_name], file)
666
+ [200, metadatas.to_json]
650
667
  rescue Bolt::Error => e
651
668
  [400, e.to_json]
652
669
  rescue ArgumentError => e
@@ -673,11 +690,23 @@ module BoltServer
673
690
  Bolt::Util.validate_file('inventory file', context[:config].project.inventory_file)
674
691
 
675
692
  begin
693
+ # Set the default puppet_library plugin hook if it has not already been
694
+ # set
695
+ context[:config].data['plugin-hooks']['puppet_library'] ||= {
696
+ 'plugin' => 'task',
697
+ 'task' => 'puppet_agent::install',
698
+ 'parameters' => {
699
+ 'stop_service' => true
700
+ }
701
+ }
702
+
676
703
  connect_plugin = BoltServer::Plugin::PuppetConnectData.new(body['puppet_connect_data'])
677
704
  plugins = Bolt::Plugin.setup(context[:config], context[:pal], load_plugins: false)
678
705
  plugins.add_plugin(connect_plugin)
679
706
  inventory = Bolt::Inventory.from_config(context[:config], plugins)
680
- target_list = inventory.get_targets('all').map { |targ| targ.to_h.merge({ 'transport' => targ.transport }) }
707
+ target_list = inventory.get_targets('all').map do |targ|
708
+ targ.to_h.merge({ 'transport' => targ.transport, 'plugin_hooks' => targ.plugin_hooks })
709
+ end
681
710
  rescue Bolt::Plugin::PluginError::LoadingDisabled => e
682
711
  msg = "Cannot load plugin #{e.details['plugin_name']}: plugin not supported"
683
712
  raise BoltServer::Plugin::PluginNotSupported.new(msg, e.details['plugin_name'])
@@ -130,11 +130,16 @@ module BoltSpec
130
130
  @executor ||= BoltSpec::Plans::MockExecutor.new(modulepath)
131
131
  end
132
132
 
133
- # Override in your tests
133
+ # Overrides inventory for tests.
134
134
  def inventory_data
135
135
  {}
136
136
  end
137
137
 
138
+ # Overrides configuration for tests.
139
+ def config_data
140
+ {}
141
+ end
142
+
138
143
  def inventory
139
144
  @inventory ||= Bolt::Inventory.create_version(inventory_data, config.transport, config.transports, plugins)
140
145
  end
@@ -142,7 +147,7 @@ module BoltSpec
142
147
  # Override in your tests
143
148
  def config
144
149
  @config ||= begin
145
- conf = Bolt::Config.default
150
+ conf = Bolt::Config.new(Bolt::Project.default_project, config_data)
146
151
  conf.modulepath = [modulepath].flatten
147
152
  conf
148
153
  end
@@ -161,7 +166,7 @@ module BoltSpec
161
166
  BoltSpec::Plans::MOCKED_ACTIONS.each do |action|
162
167
  # Allowed action stubs can be called up to be_called_times number of times
163
168
  define_method :"allow_#{action}" do |object|
164
- executor.send(:"stub_#{action}", object).add_stub
169
+ executor.send(:"stub_#{action}", object).add_stub(inventory)
165
170
  end
166
171
 
167
172
  # Expected action stubs must be called exactly the expected number of times
@@ -172,7 +177,7 @@ module BoltSpec
172
177
 
173
178
  # This stub will catch any action call if there are no stubs specifically for that task
174
179
  define_method :"allow_any_#{action}" do
175
- executor.send(:"stub_#{action}", :default).add_stub
180
+ executor.send(:"stub_#{action}", :default).add_stub(inventory)
176
181
  end
177
182
  end
178
183