bolt 3.4.0 → 3.7.1

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/Puppetfile +2 -2
  3. data/bolt-modules/boltlib/lib/puppet/datatypes/applyresult.rb +26 -0
  4. data/bolt-modules/boltlib/lib/puppet/datatypes/containerresult.rb +51 -0
  5. data/bolt-modules/boltlib/lib/puppet/datatypes/resourceinstance.rb +43 -0
  6. data/bolt-modules/boltlib/lib/puppet/datatypes/result.rb +29 -0
  7. data/bolt-modules/boltlib/lib/puppet/datatypes/resultset.rb +34 -0
  8. data/bolt-modules/boltlib/lib/puppet/datatypes/target.rb +55 -0
  9. data/bolt-modules/boltlib/lib/puppet/functions/add_to_group.rb +1 -0
  10. data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +1 -0
  11. data/bolt-modules/boltlib/lib/puppet/functions/parallelize.rb +1 -0
  12. data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_command.rb +66 -0
  13. data/bolt-modules/boltlib/lib/puppet/functions/remove_from_group.rb +1 -0
  14. data/bolt-modules/boltlib/lib/puppet/functions/run_container.rb +162 -0
  15. data/bolt-modules/boltlib/lib/puppet/functions/write_file.rb +1 -0
  16. data/bolt-modules/boltlib/types/planresult.pp +1 -0
  17. data/bolt-modules/ctrl/lib/puppet/functions/ctrl/do_until.rb +2 -0
  18. data/guides/guide.txt +17 -0
  19. data/guides/links.txt +13 -0
  20. data/guides/targets.txt +29 -0
  21. data/guides/transports.txt +23 -0
  22. data/lib/bolt/analytics.rb +4 -8
  23. data/lib/bolt/bolt_option_parser.rb +329 -225
  24. data/lib/bolt/cli.rb +58 -29
  25. data/lib/bolt/config.rb +11 -7
  26. data/lib/bolt/config/options.rb +41 -9
  27. data/lib/bolt/config/transport/podman.rb +33 -0
  28. data/lib/bolt/container_result.rb +105 -0
  29. data/lib/bolt/error.rb +15 -0
  30. data/lib/bolt/executor.rb +17 -13
  31. data/lib/bolt/inventory.rb +5 -4
  32. data/lib/bolt/inventory/inventory.rb +3 -2
  33. data/lib/bolt/inventory/options.rb +9 -0
  34. data/lib/bolt/inventory/target.rb +16 -0
  35. data/lib/bolt/module_installer/specs/git_spec.rb +10 -6
  36. data/lib/bolt/outputter/human.rb +242 -76
  37. data/lib/bolt/outputter/json.rb +6 -4
  38. data/lib/bolt/outputter/logger.rb +17 -0
  39. data/lib/bolt/pal/yaml_plan/step.rb +4 -2
  40. data/lib/bolt/plan_creator.rb +2 -2
  41. data/lib/bolt/plugin.rb +13 -11
  42. data/lib/bolt/puppetdb/client.rb +54 -0
  43. data/lib/bolt/result.rb +1 -4
  44. data/lib/bolt/shell/bash.rb +23 -10
  45. data/lib/bolt/transport/docker.rb +1 -1
  46. data/lib/bolt/transport/docker/connection.rb +23 -34
  47. data/lib/bolt/transport/podman.rb +19 -0
  48. data/lib/bolt/transport/podman/connection.rb +98 -0
  49. data/lib/bolt/transport/ssh/connection.rb +3 -6
  50. data/lib/bolt/util.rb +34 -0
  51. data/lib/bolt/version.rb +1 -1
  52. data/lib/bolt_server/transport_app.rb +3 -0
  53. data/lib/bolt_spec/plans/mock_executor.rb +91 -11
  54. data/modules/puppet_connect/plans/test_input_data.pp +22 -0
  55. metadata +13 -2
@@ -39,8 +39,6 @@ module Bolt
39
39
  end
40
40
  end
41
41
 
42
- PAGEANT_NAME = "Pageant\0".encode(Encoding::UTF_16LE)
43
-
44
42
  def connect
45
43
  options = {
46
44
  logger: @transport_logger,
@@ -115,10 +113,9 @@ module Bolt
115
113
  options[:use_agent] = false
116
114
  end
117
115
  elsif Bolt::Util.windows?
118
- require 'Win32API' # case matters in this require!
119
- # https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-findwindoww
120
- @find_window ||= Win32API.new('user32', 'FindWindowW', %w[P P], 'L')
121
- if @find_window.call(nil, PAGEANT_NAME).to_i == 0
116
+ pageant = Net::SSH::Authentication::Pageant::Win.FindWindow("Pageant", "Pageant")
117
+ # If pageant is not running
118
+ if pageant.to_i == 0
122
119
  @logger.debug { "Disabling use_agent in net-ssh: pageant process not running" }
123
120
  options[:use_agent] = false
124
121
  end
data/lib/bolt/util.rb CHANGED
@@ -332,6 +332,40 @@ module Bolt
332
332
  end
333
333
  end
334
334
 
335
+ # Executes a Docker CLI command. This is useful for running commands as
336
+ # part of this class without having to go through the `execute`
337
+ # function and manage pipes.
338
+ #
339
+ # @param cmd [String] The docker command and arguments to run
340
+ # e.g. 'cp <src> <dest>' for `docker cp <src> <dest>`
341
+ # @return [String, String, Process::Status] The output of the command: STDOUT, STDERR, Process Status
342
+ def exec_docker(cmd, env = {})
343
+ Open3.capture3(env, 'docker', *cmd, { binmode: true })
344
+ end
345
+
346
+ # Executes a Podman CLI command. This is useful for running commands as
347
+ # part of this class without having to go through the `execute`
348
+ # function and manage pipes.
349
+ #
350
+ # @param cmd [String] The podman command and arguments to run
351
+ # e.g. 'cp <src> <dest>' for `podman cp <src> <dest>`
352
+ # @return [String, String, Process::Status] The output of the command: STDOUT, STDERR, Process Status
353
+ def exec_podman(cmd, env = {})
354
+ Open3.capture3(env, 'podman', *cmd, { binmode: true })
355
+ end
356
+
357
+ # Formats a map of environment variables to be passed to a command that
358
+ # accepts repeated `--env` flags
359
+ #
360
+ # @param env_vars [Hash] A map of environment variables keys and their values
361
+ # @return [String]
362
+ def format_env_vars_for_cli(env_vars)
363
+ @env_vars = env_vars.each_with_object([]) do |(key, value), acc|
364
+ acc << "--env"
365
+ acc << "#{key}=#{value}"
366
+ end
367
+ end
368
+
335
369
  def unix_basename(path)
336
370
  raise Bolt::ValidationError, "path must be a String, received #{path.class} #{path}" unless path.is_a?(String)
337
371
  path.split('/').last
data/lib/bolt/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bolt
4
- VERSION = '3.4.0'
4
+ VERSION = '3.7.1'
5
5
  end
@@ -703,6 +703,9 @@ module BoltServer
703
703
  connect_plugin = BoltServer::Plugin::PuppetConnectData.new(body['puppet_connect_data'])
704
704
  plugins = Bolt::Plugin.setup(context[:config], context[:pal], load_plugins: false)
705
705
  plugins.add_plugin(connect_plugin)
706
+ %w[aws_inventory azure_inventory gcloud_inventory].each do |plugin_name|
707
+ plugins.add_module_plugin(plugin_name) if plugins.known_plugin?(plugin_name)
708
+ end
706
709
  inventory = Bolt::Inventory.from_config(context[:config], plugins)
707
710
  target_list = inventory.get_targets('all').map do |targ|
708
711
  targ.to_h.merge({ 'transport' => targ.transport, 'plugin_hooks' => targ.plugin_hooks })
@@ -17,13 +17,14 @@ module BoltSpec
17
17
 
18
18
  # Nothing on the executor is 'public'
19
19
  class MockExecutor
20
- attr_reader :noop, :error_message, :in_parallel
20
+ attr_reader :noop, :error_message, :in_parallel, :transports, :future
21
21
  attr_accessor :run_as, :transport_features, :execute_any_plan
22
22
 
23
23
  def initialize(modulepath)
24
24
  @noop = false
25
25
  @run_as = nil
26
26
  @in_parallel = false
27
+ @future = {}
27
28
  @error_message = nil
28
29
  @allow_apply = false
29
30
  @modulepath = [modulepath].flatten.map { |path| File.absolute_path(path) }
@@ -91,6 +92,14 @@ module BoltSpec
91
92
  result
92
93
  end
93
94
 
95
+ def run_task_with(target_mapping, task, options = {}, _position = [])
96
+ resultsets = target_mapping.map do |target, arguments|
97
+ run_task([target], task, arguments, options)
98
+ end.compact
99
+
100
+ Bolt::ResultSet.new(resultsets.map(&:results).flatten)
101
+ end
102
+
94
103
  def download_file(targets, source, destination, options = {}, _position = [])
95
104
  result = nil
96
105
  if (doub = @download_doubles[source] || @download_doubles[:default])
@@ -210,16 +219,6 @@ module BoltSpec
210
219
  yield
211
220
  end
212
221
 
213
- def report_function_call(_function); end
214
-
215
- def report_bundled_content(_mode, _name); end
216
-
217
- def report_file_source(_plan_function, _source); end
218
-
219
- def report_apply(_statements, _resources); end
220
-
221
- def report_yaml_plan(_plan); end
222
-
223
222
  def publish_event(event)
224
223
  if event[:type] == :message
225
224
  unless @stub_out_message
@@ -257,6 +256,87 @@ module BoltSpec
257
256
  end.new(transport_features)
258
257
  end
259
258
  # End apply_prep mocking
259
+
260
+ # Evaluates a `parallelize()` block and returns the result. Normally,
261
+ # Bolt's executor wraps this in a Yarn for each object passed to the
262
+ # `parallelize()` function, and then executes them in parallel before
263
+ # returning the result from the block. However, in BoltSpec the block is
264
+ # executed for each object sequentially, and this function returns the
265
+ # result itself.
266
+ #
267
+ def create_yarn(scope, block, object, _index)
268
+ # Create the new scope
269
+ newscope = Puppet::Parser::Scope.new(scope.compiler)
270
+ local = Puppet::Parser::Scope::LocalScope.new
271
+
272
+ # Compress the current scopes into a single vars hash to add to the new scope
273
+ current_scope = scope.effective_symtable(true)
274
+ until current_scope.nil?
275
+ current_scope.instance_variable_get(:@symbols)&.each_pair { |k, v| local[k] = v }
276
+ current_scope = current_scope.parent
277
+ end
278
+ newscope.push_ephemerals([local])
279
+
280
+ begin
281
+ result = catch(:return) do
282
+ args = { block.parameters[0][1].to_s => object }
283
+ block.closure.call_by_name_with_scope(newscope, args, true)
284
+ end
285
+
286
+ # If we got a return from the block, get it's value
287
+ # Otherwise the result is the last line from the block
288
+ result = result.value if result.is_a?(Puppet::Pops::Evaluator::Return)
289
+
290
+ # Validate the result is a PlanResult
291
+ unless Puppet::Pops::Types::TypeParser.singleton.parse('Boltlib::PlanResult').instance?(result)
292
+ raise Bolt::InvalidParallelResult.new(result.to_s, *Puppet::Pops::PuppetStack.top_of_stack)
293
+ end
294
+
295
+ result
296
+ rescue Puppet::PreformattedError => e
297
+ if e.cause.is_a?(Bolt::Error)
298
+ e.cause
299
+ else
300
+ raise e
301
+ end
302
+ end
303
+ end
304
+
305
+ # BoltSpec already evaluated the `parallelize()` block for each object
306
+ # passed to the function, so these results can be returned as-is.
307
+ #
308
+ def round_robin(results)
309
+ results
310
+ end
311
+
312
+ # Public methods on Bolt::Executor that need to be mocked so there aren't
313
+ # "undefined method" errors.
314
+
315
+ def batch_execute(_targets); end
316
+
317
+ def finish_plan(_plan_result); end
318
+
319
+ def handle_event(_event); end
320
+
321
+ def prompt(_prompt, _options); end
322
+
323
+ def report_function_call(_function); end
324
+
325
+ def report_bundled_content(_mode, _name); end
326
+
327
+ def report_file_source(_plan_function, _source); end
328
+
329
+ def report_apply(_statements, _resources); end
330
+
331
+ def report_yaml_plan(_plan); end
332
+
333
+ def shutdown; end
334
+
335
+ def start_plan(_plan_context); end
336
+
337
+ def subscribe(_subscriber, _types = nil); end
338
+
339
+ def unsubscribe(_subscriber, _types = nil); end
260
340
  end
261
341
  end
262
342
  end
@@ -13,6 +13,19 @@
13
13
  #
14
14
  plan puppet_connect::test_input_data(TargetSpec $targets = 'all') {
15
15
  $targs = get_targets($targets)
16
+ $unique_plugins = $targs.group_by |$t| {$t.plugin_hooks['puppet_library']}
17
+ if ($unique_plugins.keys.length > 1) {
18
+ out::message('Multiple puppet_library plugin hooks detected')
19
+ $unique_plugins.each |$plug, $target_list| {
20
+ $target_message = if ($target_list.length > 10) {
21
+ "${target_list.length} targets"
22
+ } else {
23
+ $target_list.join(', ')
24
+ }
25
+ out::message("Plugin hook ${plug} configured for ${target_message}")
26
+ }
27
+ fail_plan("The puppet_library plugin config must be the same across all targets")
28
+ }
16
29
  $targs.each |$target| {
17
30
  case $target.transport {
18
31
  'ssh': {
@@ -59,6 +72,15 @@ plan puppet_connect::test_input_data(TargetSpec $targets = 'all') {
59
72
  fail_plan("Inventory contains target ${target} with unsupported transport, must be ssh or winrm")
60
73
  }
61
74
  }
75
+
76
+ # Bolt defaults to using the "module" based form of the puppet_agent plugin. Connect defaults
77
+ # to using the "task" based form as *only* the task based form in supported in Connect. This check
78
+ # ensures that if the default is not being used, only task based plugins are allowed.
79
+ $plugin = $target.plugin_hooks["puppet_library"]
80
+ $user_configured_plugin = $plugin != { "plugin"=> "puppet_agent", "stop_service"=> true }
81
+ if ($user_configured_plugin and $plugin["plugin"] != "task"){
82
+ fail_plan("Only task plugins are acceptable for puppet_library hook")
83
+ }
62
84
  }
63
85
  # The SSH/WinRM transports will report an 'unknown host' error for targets where
64
86
  # 'host' is unknown so run_command's implementation will take care of raising that
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bolt
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.0
4
+ version: 3.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppet
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-03-23 00:00:00.000000000 Z
11
+ date: 2021-04-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -398,6 +398,7 @@ extra_rdoc_files: []
398
398
  files:
399
399
  - Puppetfile
400
400
  - bolt-modules/boltlib/lib/puppet/datatypes/applyresult.rb
401
+ - bolt-modules/boltlib/lib/puppet/datatypes/containerresult.rb
401
402
  - bolt-modules/boltlib/lib/puppet/datatypes/resourceinstance.rb
402
403
  - bolt-modules/boltlib/lib/puppet/datatypes/result.rb
403
404
  - bolt-modules/boltlib/lib/puppet/datatypes/resultset.rb
@@ -413,12 +414,14 @@ files:
413
414
  - bolt-modules/boltlib/lib/puppet/functions/get_target.rb
414
415
  - bolt-modules/boltlib/lib/puppet/functions/get_targets.rb
415
416
  - bolt-modules/boltlib/lib/puppet/functions/parallelize.rb
417
+ - bolt-modules/boltlib/lib/puppet/functions/puppetdb_command.rb
416
418
  - bolt-modules/boltlib/lib/puppet/functions/puppetdb_fact.rb
417
419
  - bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb
418
420
  - bolt-modules/boltlib/lib/puppet/functions/remove_from_group.rb
419
421
  - bolt-modules/boltlib/lib/puppet/functions/resolve_references.rb
420
422
  - bolt-modules/boltlib/lib/puppet/functions/resource.rb
421
423
  - bolt-modules/boltlib/lib/puppet/functions/run_command.rb
424
+ - bolt-modules/boltlib/lib/puppet/functions/run_container.rb
422
425
  - bolt-modules/boltlib/lib/puppet/functions/run_plan.rb
423
426
  - bolt-modules/boltlib/lib/puppet/functions/run_script.rb
424
427
  - bolt-modules/boltlib/lib/puppet/functions/run_task.rb
@@ -447,11 +450,15 @@ files:
447
450
  - bolt-modules/prompt/lib/puppet/functions/prompt/menu.rb
448
451
  - bolt-modules/system/lib/puppet/functions/system/env.rb
449
452
  - exe/bolt
453
+ - guides/guide.txt
450
454
  - guides/inventory.txt
455
+ - guides/links.txt
451
456
  - guides/logging.txt
452
457
  - guides/module.txt
453
458
  - guides/modulepath.txt
454
459
  - guides/project.txt
460
+ - guides/targets.txt
461
+ - guides/transports.txt
455
462
  - lib/bolt.rb
456
463
  - lib/bolt/analytics.rb
457
464
  - lib/bolt/applicator.rb
@@ -471,9 +478,11 @@ files:
471
478
  - lib/bolt/config/transport/lxd.rb
472
479
  - lib/bolt/config/transport/options.rb
473
480
  - lib/bolt/config/transport/orch.rb
481
+ - lib/bolt/config/transport/podman.rb
474
482
  - lib/bolt/config/transport/remote.rb
475
483
  - lib/bolt/config/transport/ssh.rb
476
484
  - lib/bolt/config/transport/winrm.rb
485
+ - lib/bolt/container_result.rb
477
486
  - lib/bolt/error.rb
478
487
  - lib/bolt/executor.rb
479
488
  - lib/bolt/inventory.rb
@@ -561,6 +570,8 @@ files:
561
570
  - lib/bolt/transport/lxd/connection.rb
562
571
  - lib/bolt/transport/orch.rb
563
572
  - lib/bolt/transport/orch/connection.rb
573
+ - lib/bolt/transport/podman.rb
574
+ - lib/bolt/transport/podman/connection.rb
564
575
  - lib/bolt/transport/remote.rb
565
576
  - lib/bolt/transport/simple.rb
566
577
  - lib/bolt/transport/ssh.rb