bolt 3.8.0 → 3.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of bolt might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/bolt-modules/boltlib/lib/puppet/datatypes/future.rb +25 -0
- data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +9 -6
- data/bolt-modules/boltlib/lib/puppet/functions/background.rb +61 -0
- data/bolt-modules/boltlib/lib/puppet/functions/download_file.rb +5 -9
- data/bolt-modules/boltlib/lib/puppet/functions/parallelize.rb +28 -13
- data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +5 -15
- data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +5 -17
- data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +8 -17
- data/bolt-modules/boltlib/lib/puppet/functions/run_task_with.rb +8 -15
- data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +5 -17
- data/bolt-modules/boltlib/lib/puppet/functions/wait.rb +91 -0
- data/bolt-modules/boltlib/types/planresult.pp +1 -0
- data/bolt-modules/file/lib/puppet/functions/file/exists.rb +1 -1
- data/bolt-modules/file/lib/puppet/functions/file/read.rb +1 -1
- data/bolt-modules/file/lib/puppet/functions/file/readable.rb +1 -1
- data/guides/debugging.txt +28 -0
- data/guides/inventory.txt +5 -0
- data/lib/bolt/applicator.rb +3 -2
- data/lib/bolt/bolt_option_parser.rb +51 -4
- data/lib/bolt/cli.rb +38 -10
- data/lib/bolt/config/options.rb +2 -1
- data/lib/bolt/config/transport/docker.rb +1 -1
- data/lib/bolt/config/transport/lxd.rb +1 -1
- data/lib/bolt/config/transport/options.rb +2 -1
- data/lib/bolt/config/transport/podman.rb +1 -1
- data/lib/bolt/error.rb +11 -1
- data/lib/bolt/executor.rb +55 -72
- data/lib/bolt/fiber_executor.rb +141 -0
- data/lib/bolt/logger.rb +1 -1
- data/lib/bolt/module_installer/specs.rb +1 -1
- data/lib/bolt/outputter/human.rb +33 -0
- data/lib/bolt/outputter/json.rb +9 -0
- data/lib/bolt/pal.rb +117 -17
- data/lib/bolt/plan_future.rb +66 -0
- data/lib/bolt/plugin.rb +38 -0
- data/lib/bolt/plugin/env_var.rb +8 -1
- data/lib/bolt/plugin/module.rb +1 -1
- data/lib/bolt/plugin/prompt.rb +8 -1
- data/lib/bolt/plugin/puppet_connect_data.rb +8 -1
- data/lib/bolt/plugin/puppetdb.rb +7 -1
- data/lib/bolt/plugin/task.rb +9 -1
- data/lib/bolt/project.rb +2 -1
- data/lib/bolt/task.rb +7 -0
- data/lib/bolt/transport/docker/connection.rb +5 -2
- data/lib/bolt/transport/lxd/connection.rb +4 -0
- data/lib/bolt/transport/podman/connection.rb +4 -0
- data/lib/bolt/util.rb +13 -1
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/config.rb +1 -1
- data/lib/bolt_server/request_error.rb +11 -0
- data/lib/bolt_server/transport_app.rb +133 -95
- data/lib/bolt_spec/plans/mock_executor.rb +40 -45
- data/lib/bolt_spec/run.rb +4 -1
- data/modules/puppet_connect/plans/test_input_data.pp +8 -3
- data/resources/bolt_bash_completion.sh +214 -0
- metadata +10 -3
- data/lib/bolt/yarn.rb +0 -23
@@ -21,7 +21,7 @@ Puppet::Functions.create_function(:'file::exists', Puppet::Functions::InternalFu
|
|
21
21
|
executor = Puppet.lookup(:bolt_executor) {}
|
22
22
|
executor&.report_function_call(self.class.name)
|
23
23
|
|
24
|
-
future = executor&.future || Puppet.lookup(:future)
|
24
|
+
future = executor&.future || Puppet.lookup(:future) { {} }
|
25
25
|
fallback = future.fetch('file_paths', false)
|
26
26
|
|
27
27
|
# Find the file path if it exists, otherwise return nil
|
@@ -20,7 +20,7 @@ Puppet::Functions.create_function(:'file::read', Puppet::Functions::InternalFunc
|
|
20
20
|
executor = Puppet.lookup(:bolt_executor) {}
|
21
21
|
executor&.report_function_call(self.class.name)
|
22
22
|
|
23
|
-
future = executor&.future || Puppet.lookup(:future)
|
23
|
+
future = executor&.future || Puppet.lookup(:future) { {} }
|
24
24
|
fallback = future.fetch('file_paths', false)
|
25
25
|
|
26
26
|
# Find the file path if it exists, otherwise return nil
|
@@ -21,7 +21,7 @@ Puppet::Functions.create_function(:'file::readable', Puppet::Functions::Internal
|
|
21
21
|
executor = Puppet.lookup(:bolt_executor) {}
|
22
22
|
executor&.report_function_call(self.class.name)
|
23
23
|
|
24
|
-
future = executor&.future || Puppet.lookup(:future)
|
24
|
+
future = executor&.future || Puppet.lookup(:future) { {} }
|
25
25
|
fallback = future.fetch('file_paths', false)
|
26
26
|
|
27
27
|
# Find the file path if it exists, otherwise return nil
|
@@ -0,0 +1,28 @@
|
|
1
|
+
TOPIC
|
2
|
+
debugging
|
3
|
+
|
4
|
+
DESCRIPTION
|
5
|
+
When Bolt isn't behaving as expected, there are a few helpful commands and
|
6
|
+
logs that can help identify common issues. The first place to look is in
|
7
|
+
`<PROJECT>/bolt-debug.log`, which contains debug-level logs from the last Bolt
|
8
|
+
run. This log file includes where the Bolt project was loaded from, the
|
9
|
+
location of any configuration or inventory files that were loaded, and the
|
10
|
+
modulepath that modules were loaded from.
|
11
|
+
|
12
|
+
If you're having issues with loading targets or target configuration, you
|
13
|
+
can see the list of resolved Bolt target names by running `bolt inventory
|
14
|
+
show` on *nix systems or `Get-BoltInventory` in PowerShell. To see the
|
15
|
+
resolved configuration for each target, run the command with the `--detail` or
|
16
|
+
`-Detail` options.
|
17
|
+
|
18
|
+
Lastly, if you're having trouble loading Bolt content you can use `bolt
|
19
|
+
module show` on *nix systems or `Get-BoltModule` in PowerShell to see the list
|
20
|
+
of loaded modules, including where they were loaded from. You can also use
|
21
|
+
`bolt task show` or `Get-BoltTask` to list loaded tasks, and `bolt plan show`
|
22
|
+
or `Get-BoltPlan` to list loaded plans.
|
23
|
+
|
24
|
+
Visit the linked documentation for more in-depth troubleshooting help for
|
25
|
+
specific issues.
|
26
|
+
|
27
|
+
DOCUMENTATION
|
28
|
+
https://pup.pt/bolt-troubleshooting
|
data/guides/inventory.txt
CHANGED
@@ -14,6 +14,11 @@ DESCRIPTION
|
|
14
14
|
project configuration file named 'bolt-project.yaml' alongside the inventory
|
15
15
|
file.
|
16
16
|
|
17
|
+
When Bolt loads inventory, it loads the entire inventory, not just the
|
18
|
+
groups and targets specified on the command line. If you've defined a
|
19
|
+
target in multiple groups, this might result in target configuration that
|
20
|
+
is different than expected.
|
21
|
+
|
17
22
|
DOCUMENTATION
|
18
23
|
https://pup.pt/bolt-inventory
|
19
24
|
https://pup.pt/bolt-inventory-reference
|
data/lib/bolt/applicator.rb
CHANGED
@@ -306,11 +306,12 @@ module Bolt
|
|
306
306
|
Puppet.lookup(:current_environment).override_with(modulepath: @plugin_dirs).modules.each do |mod|
|
307
307
|
search_dirs = yield mod
|
308
308
|
|
309
|
-
|
309
|
+
tar_dir = Pathname.new(mod.name) # goes great with fish
|
310
|
+
mod_dir = Pathname.new(mod.path)
|
310
311
|
files = Find.find(*search_dirs).select { |file| File.file?(file) }
|
311
312
|
|
312
313
|
files.each do |file|
|
313
|
-
tar_path = Pathname.new(file).relative_path_from(
|
314
|
+
tar_path = tar_dir + Pathname.new(file).relative_path_from(mod_dir)
|
314
315
|
@logger.trace("Packing plugin #{file} to #{tar_path}")
|
315
316
|
stat = File.stat(file)
|
316
317
|
content = File.binread(file)
|
@@ -67,7 +67,7 @@ module Bolt
|
|
67
67
|
{ flags: OPTIONS[:global] + %w[format],
|
68
68
|
banner: GUIDE_HELP }
|
69
69
|
when 'lookup'
|
70
|
-
{ flags: ACTION_OPTS + %w[hiera-config],
|
70
|
+
{ flags: ACTION_OPTS + %w[hiera-config plan-hierarchy],
|
71
71
|
banner: LOOKUP_HELP }
|
72
72
|
when 'module'
|
73
73
|
case action
|
@@ -105,6 +105,15 @@ module Bolt
|
|
105
105
|
{ flags: OPTIONS[:global],
|
106
106
|
banner: PLAN_HELP }
|
107
107
|
end
|
108
|
+
when 'plugin'
|
109
|
+
case action
|
110
|
+
when 'show'
|
111
|
+
{ flags: OPTIONS[:global] + %w[color format modulepath project],
|
112
|
+
banner: PLUGIN_SHOW_HELP }
|
113
|
+
else
|
114
|
+
{ flags: OPTIONS[:global],
|
115
|
+
banner: PLUGIN_HELP }
|
116
|
+
end
|
108
117
|
when 'project'
|
109
118
|
case action
|
110
119
|
when 'init'
|
@@ -192,6 +201,7 @@ module Bolt
|
|
192
201
|
module Manage Bolt project modules
|
193
202
|
lookup Look up a value with Hiera
|
194
203
|
plan Convert, create, show, and run Bolt plans
|
204
|
+
plugin Show available plugins
|
195
205
|
project Create and migrate Bolt projects
|
196
206
|
script Upload a local script and run it remotely
|
197
207
|
secret Create encryption keys and encrypt and decrypt values
|
@@ -407,7 +417,7 @@ module Bolt
|
|
407
417
|
lookup
|
408
418
|
|
409
419
|
#{colorize(:cyan, 'Usage')}
|
410
|
-
bolt lookup <key> {--targets TARGETS | --query QUERY | --rerun FILTER}
|
420
|
+
bolt lookup <key> {--targets TARGETS | --query QUERY | --rerun FILTER | --plan-hierarchy}
|
411
421
|
[options]
|
412
422
|
|
413
423
|
#{colorize(:cyan, 'Description')}
|
@@ -418,6 +428,7 @@ module Bolt
|
|
418
428
|
|
419
429
|
#{colorize(:cyan, 'Examples')}
|
420
430
|
bolt lookup password --targets servers
|
431
|
+
bolt lookup password --plan-hierarchy variable=value
|
421
432
|
HELP
|
422
433
|
|
423
434
|
MODULE_HELP = <<~HELP
|
@@ -608,6 +619,37 @@ module Bolt
|
|
608
619
|
bolt plan show aggregate::count
|
609
620
|
HELP
|
610
621
|
|
622
|
+
PLUGIN_HELP = <<~HELP
|
623
|
+
#{colorize(:cyan, 'Name')}
|
624
|
+
plugin
|
625
|
+
|
626
|
+
#{colorize(:cyan, 'Usage')}
|
627
|
+
bolt plugin <action> [options]
|
628
|
+
|
629
|
+
#{colorize(:cyan, 'Description')}
|
630
|
+
Show available plugins.
|
631
|
+
|
632
|
+
#{colorize(:cyan, 'Documentation')}
|
633
|
+
Learn more about Bolt plugins at https://pup.pt/bolt-plugins.
|
634
|
+
|
635
|
+
#{colorize(:cyan, 'Actions')}
|
636
|
+
show Show available plugins
|
637
|
+
HELP
|
638
|
+
|
639
|
+
PLUGIN_SHOW_HELP = <<~HELP
|
640
|
+
#{colorize(:cyan, 'Name')}
|
641
|
+
show
|
642
|
+
|
643
|
+
#{colorize(:cyan, 'Usage')}
|
644
|
+
bolt plugin show [options]
|
645
|
+
|
646
|
+
#{colorize(:cyan, 'Description')}
|
647
|
+
Show available plugins.
|
648
|
+
|
649
|
+
#{colorize(:cyan, 'Documentation')}
|
650
|
+
Learn more about Bolt plugins at https://pup.pt/bolt-plugins.
|
651
|
+
HELP
|
652
|
+
|
611
653
|
PROJECT_HELP = <<~HELP
|
612
654
|
#{colorize(:cyan, 'Name')}
|
613
655
|
project
|
@@ -988,6 +1030,11 @@ module Bolt
|
|
988
1030
|
@options[:resolve] = resolve
|
989
1031
|
end
|
990
1032
|
|
1033
|
+
separator "\n#{self.class.colorize(:cyan, 'Lookup options')}"
|
1034
|
+
define('--plan-hierarchy', 'Look up a value with Hiera in the context of a specific plan.') do |_|
|
1035
|
+
@options[:plan_hierarchy] = true
|
1036
|
+
end
|
1037
|
+
|
991
1038
|
separator "\n#{self.class.colorize(:cyan, 'Plan options')}"
|
992
1039
|
define('--pp', 'Create a new Puppet language plan.') do |_|
|
993
1040
|
@options[:puppet] = true
|
@@ -996,8 +1043,8 @@ module Bolt
|
|
996
1043
|
separator "\n#{self.class.colorize(:cyan, 'Display options')}"
|
997
1044
|
define('--filter FILTER', 'Filter tasks and plans by a matching substring.') do |filter|
|
998
1045
|
unless /^[a-z0-9_:]+$/.match(filter)
|
999
|
-
msg = "Illegal characters in filter string '#{filter}'. Filters
|
1000
|
-
|
1046
|
+
msg = "Illegal characters in filter string '#{filter}'. Filters can "\
|
1047
|
+
"only include lowercase letters, numbers, underscores, and colons."
|
1001
1048
|
raise Bolt::CLIError, msg
|
1002
1049
|
end
|
1003
1050
|
@options[:filter] = filter
|
data/lib/bolt/cli.rb
CHANGED
@@ -42,6 +42,7 @@ module Bolt
|
|
42
42
|
'lookup' => %w[],
|
43
43
|
'module' => %w[add generate-types install show],
|
44
44
|
'plan' => %w[show run convert new],
|
45
|
+
'plugin' => %w[show],
|
45
46
|
'project' => %w[init migrate],
|
46
47
|
'script' => %w[run],
|
47
48
|
'secret' => %w[encrypt decrypt createkeys],
|
@@ -153,7 +154,6 @@ module Bolt
|
|
153
154
|
options[:subcommand] = nil unless COMMANDS.include?(options[:subcommand])
|
154
155
|
|
155
156
|
if Bolt::Util.first_run?
|
156
|
-
FileUtils.mkdir_p(Bolt::Util.first_runs_free.dirname)
|
157
157
|
FileUtils.touch(Bolt::Util.first_runs_free)
|
158
158
|
|
159
159
|
if options[:subcommand].nil? && $stdout.isatty
|
@@ -355,12 +355,18 @@ module Bolt
|
|
355
355
|
"the project, run '#{command} #{options[:object]}'."
|
356
356
|
end
|
357
357
|
|
358
|
-
if
|
358
|
+
if !%w[file script lookup].include?(options[:subcommand]) &&
|
359
359
|
!options[:leftovers].empty?
|
360
360
|
raise Bolt::CLIError,
|
361
361
|
"Unknown argument(s) #{options[:leftovers].join(', ')}"
|
362
362
|
end
|
363
363
|
|
364
|
+
target_opts = options.keys.select { |opt| TARGETING_OPTIONS.include?(opt) }
|
365
|
+
if options[:subcommand] == 'lookup' &&
|
366
|
+
target_opts.any? && options[:plan_hierarchy]
|
367
|
+
raise Bolt::CLIError, "The 'lookup' command accepts either targeting option OR --plan-hierarchy."
|
368
|
+
end
|
369
|
+
|
364
370
|
if options[:noop] &&
|
365
371
|
!(options[:subcommand] == 'task' && options[:action] == 'run') && options[:subcommand] != 'apply'
|
366
372
|
raise Bolt::CLIError,
|
@@ -433,10 +439,11 @@ module Bolt
|
|
433
439
|
end
|
434
440
|
|
435
441
|
# Initialize inventory and targets. Errors here are better to catch early.
|
436
|
-
# options[:target_args] will contain a string/array version of the
|
442
|
+
# options[:target_args] will contain a string/array version of the targeting options this is passed to plans
|
437
443
|
# options[:targets] will contain a resolved set of Target objects
|
438
444
|
unless %w[guide module project secret].include?(options[:subcommand]) ||
|
439
|
-
%w[convert new show].include?(options[:action])
|
445
|
+
%w[convert new show].include?(options[:action]) ||
|
446
|
+
options[:plan_hierarchy]
|
440
447
|
update_targets(options)
|
441
448
|
end
|
442
449
|
|
@@ -488,6 +495,8 @@ module Bolt
|
|
488
495
|
list_groups
|
489
496
|
when 'module'
|
490
497
|
list_modules
|
498
|
+
when 'plugin'
|
499
|
+
list_plugins
|
491
500
|
end
|
492
501
|
return 0
|
493
502
|
when 'convert'
|
@@ -517,7 +526,13 @@ module Bolt
|
|
517
526
|
code = Bolt::ProjectManager.new(config, outputter, pal).migrate
|
518
527
|
end
|
519
528
|
when 'lookup'
|
520
|
-
|
529
|
+
plan_vars = Hash[options[:leftovers].map { |a| a.split('=', 2) }]
|
530
|
+
# Validate functions verifies one of these was passed
|
531
|
+
if options[:targets]
|
532
|
+
code = lookup(options[:object], options[:targets], plan_vars: plan_vars)
|
533
|
+
elsif options[:plan_hierarchy]
|
534
|
+
code = plan_lookup(options[:object], plan_vars: plan_vars)
|
535
|
+
end
|
521
536
|
when 'plan'
|
522
537
|
case options[:action]
|
523
538
|
when 'new'
|
@@ -631,7 +646,7 @@ module Bolt
|
|
631
646
|
end
|
632
647
|
|
633
648
|
def list_tasks
|
634
|
-
tasks = filter_content(pal.
|
649
|
+
tasks = filter_content(pal.list_tasks_with_cache(filter_content: true), options[:filter])
|
635
650
|
outputter.print_tasks(tasks, pal.user_modulepath)
|
636
651
|
end
|
637
652
|
|
@@ -695,10 +710,19 @@ module Bolt
|
|
695
710
|
outputter.print_groups(inventory.group_names.sort, inventory.source, config.default_inventoryfile)
|
696
711
|
end
|
697
712
|
|
713
|
+
# Looks up a value with Hiera as if in a plan outside an apply block, using
|
714
|
+
# provided variable values for interpolations
|
715
|
+
#
|
716
|
+
def plan_lookup(key, plan_vars: {})
|
717
|
+
result = pal.plan_hierarchy_lookup(key, plan_vars: plan_vars)
|
718
|
+
outputter.print_plan_lookup(result)
|
719
|
+
0
|
720
|
+
end
|
721
|
+
|
698
722
|
# Looks up a value with Hiera, using targets as the contexts to perform the
|
699
|
-
# look ups in.
|
723
|
+
# look ups in. This should return the same value as a lookup in an apply block.
|
700
724
|
#
|
701
|
-
def lookup(key, targets)
|
725
|
+
def lookup(key, targets, plan_vars: {})
|
702
726
|
executor = Bolt::Executor.new(
|
703
727
|
config.concurrency,
|
704
728
|
analytics,
|
@@ -707,7 +731,7 @@ module Bolt
|
|
707
731
|
config.future
|
708
732
|
)
|
709
733
|
|
710
|
-
executor.subscribe(outputter) if
|
734
|
+
executor.subscribe(outputter) if config.format == 'human'
|
711
735
|
executor.subscribe(log_outputter)
|
712
736
|
executor.publish_event(type: :plan_start, plan: nil)
|
713
737
|
|
@@ -717,7 +741,7 @@ module Bolt
|
|
717
741
|
targets,
|
718
742
|
inventory,
|
719
743
|
executor,
|
720
|
-
|
744
|
+
plan_vars: plan_vars
|
721
745
|
)
|
722
746
|
end
|
723
747
|
|
@@ -828,6 +852,10 @@ module Bolt
|
|
828
852
|
outputter.print_module_list(pal.list_modules)
|
829
853
|
end
|
830
854
|
|
855
|
+
def list_plugins
|
856
|
+
outputter.print_plugin_list(plugins.list_plugins, pal.user_modulepath)
|
857
|
+
end
|
858
|
+
|
831
859
|
def generate_types
|
832
860
|
# generate_types will surface a nice error with helpful message if it fails
|
833
861
|
pal.generate_types(cache: true)
|
data/lib/bolt/config/options.rb
CHANGED
@@ -279,7 +279,8 @@ module Bolt
|
|
279
279
|
"modules" => {
|
280
280
|
description: "A list of module dependencies for the project. Each dependency is a map of data specifying "\
|
281
281
|
"the module to install. To install the project's module dependencies, run the `bolt module "\
|
282
|
-
"install` command."
|
282
|
+
"install` command. For more information about specifying modules, see [the "\
|
283
|
+
"documentation](https://pup.pt/bolt-module-specs).",
|
283
284
|
type: Array,
|
284
285
|
items: {
|
285
286
|
type: [Hash, String],
|
@@ -235,7 +235,8 @@ module Bolt
|
|
235
235
|
"private-key" => {
|
236
236
|
type: [Hash, String],
|
237
237
|
description: "Either the path to the private key file to use for authentication, or "\
|
238
|
-
|
238
|
+
"a hash with the key `key-data` and the contents of the private key. Note that "\
|
239
|
+
"the key cannot be encrypted if using the `key-data` hash.",
|
239
240
|
required: ["key-data"],
|
240
241
|
properties: {
|
241
242
|
"key-data" => {
|
data/lib/bolt/error.rb
CHANGED
@@ -105,6 +105,16 @@ module Bolt
|
|
105
105
|
end
|
106
106
|
end
|
107
107
|
|
108
|
+
class FutureTimeoutError < Bolt::Error
|
109
|
+
def initialize(name, timeout)
|
110
|
+
details = {
|
111
|
+
'future' => name
|
112
|
+
}
|
113
|
+
message = "Future '#{name}' timed out after #{timeout} seconds."
|
114
|
+
super(message, 'bolt/future-timeout-error', details)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
108
118
|
class ParallelFailure < Bolt::Error
|
109
119
|
def initialize(results, failed_indices)
|
110
120
|
details = {
|
@@ -162,7 +172,7 @@ module Bolt
|
|
162
172
|
|
163
173
|
class InvalidParallelResult < Error
|
164
174
|
def initialize(result_str, file, line)
|
165
|
-
super("
|
175
|
+
super("Background block returned an invalid result: #{result_str}",
|
166
176
|
'bolt/invalid-plan-result',
|
167
177
|
{ 'file' => file,
|
168
178
|
'line' => line,
|
data/lib/bolt/executor.rb
CHANGED
@@ -7,10 +7,11 @@ require 'logging'
|
|
7
7
|
require 'pathname'
|
8
8
|
require 'set'
|
9
9
|
require 'bolt/analytics'
|
10
|
-
require 'bolt/result'
|
11
10
|
require 'bolt/config'
|
12
|
-
require 'bolt/
|
11
|
+
require 'bolt/fiber_executor'
|
13
12
|
require 'bolt/puppetdb'
|
13
|
+
require 'bolt/result'
|
14
|
+
require 'bolt/result_set'
|
14
15
|
# Load transports
|
15
16
|
require 'bolt/transport/docker'
|
16
17
|
require 'bolt/transport/local'
|
@@ -20,7 +21,6 @@ require 'bolt/transport/podman'
|
|
20
21
|
require 'bolt/transport/remote'
|
21
22
|
require 'bolt/transport/ssh'
|
22
23
|
require 'bolt/transport/winrm'
|
23
|
-
require 'bolt/yarn'
|
24
24
|
|
25
25
|
module Bolt
|
26
26
|
TRANSPORTS = {
|
@@ -35,7 +35,7 @@ module Bolt
|
|
35
35
|
}.freeze
|
36
36
|
|
37
37
|
class Executor
|
38
|
-
attr_reader :noop, :transports, :
|
38
|
+
attr_reader :noop, :transports, :future
|
39
39
|
attr_accessor :run_as
|
40
40
|
|
41
41
|
def initialize(concurrency = 1,
|
@@ -66,7 +66,6 @@ module Bolt
|
|
66
66
|
|
67
67
|
@noop = noop
|
68
68
|
@run_as = nil
|
69
|
-
@in_parallel = false
|
70
69
|
@future = future
|
71
70
|
@pool = if concurrency > 0
|
72
71
|
Concurrent::ThreadPoolExecutor.new(name: 'exec', max_threads: concurrency)
|
@@ -77,6 +76,7 @@ module Bolt
|
|
77
76
|
|
78
77
|
@concurrency = concurrency
|
79
78
|
@warn_concurrency = modified_concurrency
|
79
|
+
@fiber_executor = Bolt::FiberExecutor.new
|
80
80
|
end
|
81
81
|
|
82
82
|
def transport(transport)
|
@@ -242,6 +242,10 @@ module Bolt
|
|
242
242
|
@analytics&.event('Plan', plan_function, label: label)
|
243
243
|
end
|
244
244
|
|
245
|
+
def report_noop_mode(noop)
|
246
|
+
@analytics&.event('Task', 'noop', label: (!!noop).to_s)
|
247
|
+
end
|
248
|
+
|
245
249
|
def report_apply(statement_count, resource_counts)
|
246
250
|
data = { statement_count: statement_count }
|
247
251
|
|
@@ -373,83 +377,62 @@ module Bolt
|
|
373
377
|
plan.call_by_name_with_scope(scope, params, true)
|
374
378
|
end
|
375
379
|
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
current_scope = scope.effective_symtable(true)
|
384
|
-
until current_scope.nil?
|
385
|
-
current_scope.instance_variable_get(:@symbols)&.each_pair { |k, v| local[k] = v }
|
386
|
-
current_scope = current_scope.parent
|
387
|
-
end
|
388
|
-
newscope.push_ephemerals([local])
|
389
|
-
|
390
|
-
begin
|
391
|
-
result = catch(:return) do
|
392
|
-
args = { block.parameters[0][1].to_s => object }
|
393
|
-
block.closure.call_by_name_with_scope(newscope, args, true)
|
394
|
-
end
|
395
|
-
|
396
|
-
# If we got a return from the block, get it's value
|
397
|
-
# Otherwise the result is the last line from the block
|
398
|
-
result = result.value if result.is_a?(Puppet::Pops::Evaluator::Return)
|
380
|
+
# Call into FiberExecutor to avoid this class getting
|
381
|
+
# overloaded while also minimizing the Puppet lookups needed from plan
|
382
|
+
# functions
|
383
|
+
#
|
384
|
+
def create_future(scope: nil, name: nil, &block)
|
385
|
+
@fiber_executor.create_future(scope: scope, name: name, &block)
|
386
|
+
end
|
399
387
|
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
end
|
388
|
+
def plan_complete?
|
389
|
+
@fiber_executor.plan_complete?
|
390
|
+
end
|
404
391
|
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
e.cause
|
409
|
-
else
|
410
|
-
raise e
|
411
|
-
end
|
412
|
-
end
|
413
|
-
end
|
392
|
+
def round_robin
|
393
|
+
@fiber_executor.round_robin
|
394
|
+
end
|
414
395
|
|
415
|
-
|
396
|
+
def in_parallel?
|
397
|
+
@fiber_executor.in_parallel?
|
416
398
|
end
|
417
399
|
|
418
|
-
def
|
419
|
-
|
420
|
-
when :node_result
|
421
|
-
@thread_completed = true
|
422
|
-
end
|
400
|
+
def wait(futures, **opts)
|
401
|
+
@fiber_executor.wait(futures, **opts)
|
423
402
|
end
|
424
403
|
|
425
|
-
def
|
426
|
-
|
427
|
-
|
428
|
-
@in_parallel = true
|
429
|
-
publish_event(type: :stop_spin)
|
404
|
+
def plan_futures
|
405
|
+
@fiber_executor.plan_futures
|
406
|
+
end
|
430
407
|
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
skein.delete(yarn)
|
442
|
-
end
|
443
|
-
end
|
408
|
+
# Execute a plan function concurrently. This function accepts the executor
|
409
|
+
# function to be run and the parameters to pass to it, and returns the
|
410
|
+
# result of running the executor function.
|
411
|
+
#
|
412
|
+
def run_in_thread
|
413
|
+
require 'concurrent'
|
414
|
+
require 'fiber'
|
415
|
+
future = Concurrent::Future.execute do
|
416
|
+
yield
|
417
|
+
end
|
444
418
|
|
445
|
-
|
446
|
-
|
419
|
+
# Used to track how often we resume the same executor function
|
420
|
+
still_running = 0
|
421
|
+
# While the thread is still running
|
422
|
+
while future.incomplete?
|
423
|
+
# If the Fiber gets resumed, increment the resume tracker. This means
|
424
|
+
# the tracker starts at 1 since it needs to increment before yielding,
|
425
|
+
# since it can't yield then increment.
|
426
|
+
still_running += 1
|
427
|
+
# If the Fiber has been resumed before, still_running will be 2 or
|
428
|
+
# more. Yield different values for when the same Fiber is resumed
|
429
|
+
# multiple times and when it's resumed the first time in order to know
|
430
|
+
# if progress was made in the plan.
|
431
|
+
Fiber.yield(still_running < 2 ? :something_happened : :returned_immediately)
|
447
432
|
end
|
448
433
|
|
449
|
-
|
450
|
-
|
451
|
-
unsubscribe(self, [:node_result])
|
452
|
-
results
|
434
|
+
# Once the thread completes, return the result.
|
435
|
+
future.value || future.reason
|
453
436
|
end
|
454
437
|
|
455
438
|
class TimeoutError < RuntimeError; end
|
@@ -519,7 +502,7 @@ module Bolt
|
|
519
502
|
# coupled with the orchestrator transport since the transport behaves
|
520
503
|
# differently when a plan is running. In order to limit how much this
|
521
504
|
# pollutes the transport API we only handle the orchestrator transport here.
|
522
|
-
# Since we
|
505
|
+
# Since we call this function without resolving targets this will result
|
523
506
|
# in the orchestrator transport always being initialized during plan runs.
|
524
507
|
# For now that's ok.
|
525
508
|
#
|