bolt 3.5.0 → 3.8.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 +3 -3
- data/bolt-modules/boltlib/lib/puppet/datatypes/applyresult.rb +26 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/containerresult.rb +27 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/resourceinstance.rb +43 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/result.rb +29 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/resultset.rb +34 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/target.rb +55 -0
- data/bolt-modules/boltlib/lib/puppet/functions/add_to_group.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/parallelize.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_command.rb +66 -0
- data/bolt-modules/boltlib/lib/puppet/functions/remove_from_group.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +5 -1
- data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +5 -1
- data/bolt-modules/boltlib/lib/puppet/functions/write_file.rb +1 -0
- data/bolt-modules/ctrl/lib/puppet/functions/ctrl/do_until.rb +2 -0
- data/bolt-modules/file/lib/puppet/functions/file/exists.rb +9 -3
- data/bolt-modules/file/lib/puppet/functions/file/read.rb +6 -2
- data/bolt-modules/file/lib/puppet/functions/file/readable.rb +8 -3
- data/guides/guide.txt +17 -0
- data/guides/links.txt +13 -0
- data/guides/targets.txt +29 -0
- data/guides/transports.txt +23 -0
- data/lib/bolt/analytics.rb +4 -8
- data/lib/bolt/applicator.rb +1 -1
- data/lib/bolt/bolt_option_parser.rb +351 -225
- data/lib/bolt/catalog.rb +2 -1
- data/lib/bolt/cli.rb +122 -55
- data/lib/bolt/config.rb +11 -7
- data/lib/bolt/config/options.rb +41 -9
- data/lib/bolt/config/transport/podman.rb +33 -0
- data/lib/bolt/executor.rb +15 -11
- data/lib/bolt/inventory.rb +5 -4
- data/lib/bolt/inventory/inventory.rb +3 -2
- data/lib/bolt/module_installer/specs/git_spec.rb +10 -6
- data/lib/bolt/outputter/human.rb +194 -79
- data/lib/bolt/outputter/json.rb +10 -4
- data/lib/bolt/pal.rb +45 -0
- data/lib/bolt/pal/yaml_plan/step.rb +4 -2
- data/lib/bolt/plan_creator.rb +2 -2
- data/lib/bolt/plugin.rb +13 -11
- data/lib/bolt/puppetdb/client.rb +54 -0
- data/lib/bolt/result.rb +5 -0
- data/lib/bolt/shell/bash.rb +23 -10
- data/lib/bolt/transport/docker.rb +1 -1
- data/lib/bolt/transport/docker/connection.rb +10 -6
- data/lib/bolt/transport/podman.rb +19 -0
- data/lib/bolt/transport/podman/connection.rb +98 -0
- data/lib/bolt/transport/ssh/connection.rb +3 -6
- data/lib/bolt/util.rb +71 -0
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/transport_app.rb +3 -0
- data/lib/bolt_spec/plans/mock_executor.rb +2 -1
- metadata +10 -2
data/lib/bolt/catalog.rb
CHANGED
@@ -65,7 +65,8 @@ module Bolt
|
|
65
65
|
puppet_overrides = {
|
66
66
|
bolt_pdb_client: pdb_client,
|
67
67
|
bolt_inventory: inv,
|
68
|
-
bolt_project: bolt_project
|
68
|
+
bolt_project: bolt_project,
|
69
|
+
future: request['future']
|
69
70
|
}
|
70
71
|
|
71
72
|
# Facts will be set by the catalog compiler, so we need to ensure
|
data/lib/bolt/cli.rb
CHANGED
@@ -33,20 +33,23 @@ module Bolt
|
|
33
33
|
|
34
34
|
class CLI
|
35
35
|
COMMANDS = {
|
36
|
-
'
|
37
|
-
'
|
38
|
-
'
|
39
|
-
'
|
40
|
-
'
|
41
|
-
'secret' => %w[encrypt decrypt createkeys],
|
36
|
+
'apply' => %w[],
|
37
|
+
'command' => %w[run],
|
38
|
+
'file' => %w[download upload],
|
39
|
+
'group' => %w[show],
|
40
|
+
'guide' => %w[],
|
42
41
|
'inventory' => %w[show],
|
43
|
-
'
|
44
|
-
'
|
45
|
-
'
|
46
|
-
'
|
47
|
-
'
|
42
|
+
'lookup' => %w[],
|
43
|
+
'module' => %w[add generate-types install show],
|
44
|
+
'plan' => %w[show run convert new],
|
45
|
+
'project' => %w[init migrate],
|
46
|
+
'script' => %w[run],
|
47
|
+
'secret' => %w[encrypt decrypt createkeys],
|
48
|
+
'task' => %w[show run]
|
48
49
|
}.freeze
|
49
50
|
|
51
|
+
TARGETING_OPTIONS = %i[query rerun targets].freeze
|
52
|
+
|
50
53
|
attr_reader :config, :options
|
51
54
|
|
52
55
|
def initialize(argv)
|
@@ -262,7 +265,7 @@ module Bolt
|
|
262
265
|
end
|
263
266
|
|
264
267
|
def update_targets(options)
|
265
|
-
target_opts = options.keys.select { |opt|
|
268
|
+
target_opts = options.keys.select { |opt| TARGETING_OPTIONS.include?(opt) }
|
266
269
|
target_string = "'--targets', '--rerun', or '--query'"
|
267
270
|
if target_opts.length > 1
|
268
271
|
raise Bolt::CLIError, "Only one targeting option #{target_string} can be specified"
|
@@ -324,6 +327,10 @@ module Bolt
|
|
324
327
|
raise Bolt::CLIError, "a manifest file or --execute is required"
|
325
328
|
end
|
326
329
|
|
330
|
+
if options[:subcommand] == 'lookup' && !options[:object]
|
331
|
+
raise Bolt::CLIError, "Must specify a key to look up"
|
332
|
+
end
|
333
|
+
|
327
334
|
if options[:subcommand] == 'command' && (!options[:object] || options[:object].empty?)
|
328
335
|
raise Bolt::CLIError, "Must specify a command to run"
|
329
336
|
end
|
@@ -509,6 +516,8 @@ module Bolt
|
|
509
516
|
when 'migrate'
|
510
517
|
code = Bolt::ProjectManager.new(config, outputter, pal).migrate
|
511
518
|
end
|
519
|
+
when 'lookup'
|
520
|
+
code = lookup(options[:object], options[:targets])
|
512
521
|
when 'plan'
|
513
522
|
case options[:action]
|
514
523
|
when 'new'
|
@@ -541,7 +550,11 @@ module Bolt
|
|
541
550
|
end
|
542
551
|
code = apply_manifest(options[:code], options[:targets], options[:object], options[:noop])
|
543
552
|
else
|
544
|
-
executor = Bolt::Executor.new(config.concurrency,
|
553
|
+
executor = Bolt::Executor.new(config.concurrency,
|
554
|
+
analytics,
|
555
|
+
options[:noop],
|
556
|
+
config.modified_concurrency,
|
557
|
+
config.future)
|
545
558
|
targets = options[:targets]
|
546
559
|
|
547
560
|
results = nil
|
@@ -557,7 +570,8 @@ module Bolt
|
|
557
570
|
when 'command'
|
558
571
|
executor.run_command(targets, options[:object], executor_opts)
|
559
572
|
when 'script'
|
560
|
-
script_path = find_file(options[:object])
|
573
|
+
script_path = find_file(options[:object], executor.future&.fetch('file_paths', false))
|
574
|
+
validate_file('script', script_path)
|
561
575
|
executor.run_script(targets, script_path, options[:leftovers], executor_opts)
|
562
576
|
when 'task'
|
563
577
|
pal.run_task(options[:object],
|
@@ -582,8 +596,9 @@ module Bolt
|
|
582
596
|
dest = File.expand_path(dest, Dir.pwd)
|
583
597
|
executor.download_file(targets, src, dest, executor_opts)
|
584
598
|
when 'upload'
|
585
|
-
|
586
|
-
|
599
|
+
src_path = find_file(src, executor.future&.fetch('file_paths', false))
|
600
|
+
validate_file('source file', src_path, true)
|
601
|
+
executor.upload_file(targets, src_path, dest, executor_opts)
|
587
602
|
end
|
588
603
|
end
|
589
604
|
end
|
@@ -630,8 +645,39 @@ module Bolt
|
|
630
645
|
end
|
631
646
|
|
632
647
|
def list_targets
|
633
|
-
|
648
|
+
if options.keys.any? { |key| TARGETING_OPTIONS.include?(key) }
|
649
|
+
target_flag = true
|
650
|
+
else
|
651
|
+
options[:targets] = 'all'
|
652
|
+
end
|
653
|
+
|
654
|
+
outputter.print_targets(
|
655
|
+
group_targets_by_source,
|
656
|
+
inventory.source,
|
657
|
+
config.default_inventoryfile,
|
658
|
+
target_flag
|
659
|
+
)
|
660
|
+
end
|
661
|
+
|
662
|
+
def show_targets
|
663
|
+
if options.keys.any? { |key| TARGETING_OPTIONS.include?(key) }
|
664
|
+
target_flag = true
|
665
|
+
else
|
666
|
+
options[:targets] = 'all'
|
667
|
+
end
|
634
668
|
|
669
|
+
outputter.print_target_info(
|
670
|
+
group_targets_by_source,
|
671
|
+
inventory.source,
|
672
|
+
config.default_inventoryfile,
|
673
|
+
target_flag
|
674
|
+
)
|
675
|
+
end
|
676
|
+
|
677
|
+
# Returns a hash of targets sorted by those that are found in the
|
678
|
+
# inventory and those that are provided on the command line.
|
679
|
+
#
|
680
|
+
private def group_targets_by_source
|
635
681
|
# Retrieve the known group and target names. This needs to be done before
|
636
682
|
# updating targets, as that will add adhoc targets to the inventory.
|
637
683
|
known_names = inventory.target_names
|
@@ -642,22 +688,43 @@ module Bolt
|
|
642
688
|
known_names.include?(target.name)
|
643
689
|
end
|
644
690
|
|
645
|
-
|
646
|
-
inventory: inventory_targets,
|
647
|
-
adhoc: adhoc_targets
|
648
|
-
}
|
649
|
-
|
650
|
-
outputter.print_targets(target_list, inventoryfile)
|
691
|
+
{ inventory: inventory_targets, adhoc: adhoc_targets }
|
651
692
|
end
|
652
693
|
|
653
|
-
def
|
654
|
-
|
655
|
-
outputter.print_target_info(options[:targets])
|
694
|
+
def list_groups
|
695
|
+
outputter.print_groups(inventory.group_names.sort, inventory.source, config.default_inventoryfile)
|
656
696
|
end
|
657
697
|
|
658
|
-
|
659
|
-
|
660
|
-
|
698
|
+
# Looks up a value with Hiera, using targets as the contexts to perform the
|
699
|
+
# look ups in.
|
700
|
+
#
|
701
|
+
def lookup(key, targets)
|
702
|
+
executor = Bolt::Executor.new(
|
703
|
+
config.concurrency,
|
704
|
+
analytics,
|
705
|
+
options[:noop],
|
706
|
+
config.modified_concurrency,
|
707
|
+
config.future
|
708
|
+
)
|
709
|
+
|
710
|
+
executor.subscribe(outputter) if options.fetch(:format, 'human') == 'human'
|
711
|
+
executor.subscribe(log_outputter)
|
712
|
+
executor.publish_event(type: :plan_start, plan: nil)
|
713
|
+
|
714
|
+
results = outputter.spin do
|
715
|
+
pal.lookup(
|
716
|
+
key,
|
717
|
+
targets,
|
718
|
+
inventory,
|
719
|
+
executor,
|
720
|
+
config.concurrency
|
721
|
+
)
|
722
|
+
end
|
723
|
+
|
724
|
+
executor.shutdown
|
725
|
+
outputter.print_result_set(results)
|
726
|
+
|
727
|
+
results.ok ? 0 : 1
|
661
728
|
end
|
662
729
|
|
663
730
|
def run_plan(plan_name, plan_arguments, nodes, options)
|
@@ -688,7 +755,11 @@ module Bolt
|
|
688
755
|
plan_context = { plan_name: plan_name,
|
689
756
|
params: plan_arguments }
|
690
757
|
|
691
|
-
executor = Bolt::Executor.new(config.concurrency,
|
758
|
+
executor = Bolt::Executor.new(config.concurrency,
|
759
|
+
analytics,
|
760
|
+
options[:noop],
|
761
|
+
config.modified_concurrency,
|
762
|
+
config.future)
|
692
763
|
if %w[human rainbow].include?(options.fetch(:format, 'human'))
|
693
764
|
executor.subscribe(outputter)
|
694
765
|
else
|
@@ -724,7 +795,11 @@ module Bolt
|
|
724
795
|
Bolt::Logger.warn("empty_manifest", message)
|
725
796
|
end
|
726
797
|
|
727
|
-
executor = Bolt::Executor.new(config.concurrency,
|
798
|
+
executor = Bolt::Executor.new(config.concurrency,
|
799
|
+
analytics,
|
800
|
+
noop,
|
801
|
+
config.modified_concurrency,
|
802
|
+
config.future)
|
728
803
|
executor.subscribe(outputter) if options.fetch(:format, 'human') == 'human'
|
729
804
|
executor.subscribe(log_outputter)
|
730
805
|
# apply logging looks like plan logging, so tell the outputter we're in a
|
@@ -809,15 +884,10 @@ module Bolt
|
|
809
884
|
#
|
810
885
|
def assert_project_file(project)
|
811
886
|
unless project.project_file?
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
else
|
817
|
-
command = Bolt::Util.powershell? ? 'New-BoltProject' : 'bolt project init'
|
818
|
-
"Could not find project configuration file #{project.project_file}, unable "\
|
819
|
-
"to install modules. To create a Bolt project, run '#{command}'."
|
820
|
-
end
|
887
|
+
command = Bolt::Util.powershell? ? 'New-BoltProject' : 'bolt project init'
|
888
|
+
|
889
|
+
msg = "Could not find project configuration file #{project.project_file}, unable "\
|
890
|
+
"to install modules. To create a Bolt project, run '#{command}'."
|
821
891
|
|
822
892
|
raise Bolt::Error.new(msg, 'bolt/missing-project-config-error')
|
823
893
|
end
|
@@ -863,7 +933,7 @@ module Bolt
|
|
863
933
|
|
864
934
|
# Display the list of available Bolt guides.
|
865
935
|
def list_topics
|
866
|
-
outputter.print_topics(guides.keys)
|
936
|
+
outputter.print_topics(guides.keys - ['guide'])
|
867
937
|
0
|
868
938
|
end
|
869
939
|
|
@@ -900,20 +970,17 @@ module Bolt
|
|
900
970
|
# the path is a Puppet file path and looks for the file in a module's files
|
901
971
|
# directory.
|
902
972
|
#
|
903
|
-
def find_file(path)
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
973
|
+
def find_file(path, future_file_paths)
|
974
|
+
return path if File.exist?(path) || Pathname.new(path).absolute?
|
975
|
+
modulepath = Bolt::Config::Modulepath.new(config.modulepath)
|
976
|
+
modules = Bolt::Module.discover(modulepath.full_modulepath, config.project)
|
977
|
+
mod, file = path.split(File::SEPARATOR, 2)
|
978
|
+
|
979
|
+
if modules[mod]
|
980
|
+
@logger.debug("Did not find file at #{File.expand_path(path)}, checking in module '#{mod}'")
|
981
|
+
found = Bolt::Util.find_file_in_module(modules[mod].path, file || "", future_file_paths)
|
982
|
+
path = found.nil? ? File.join(modules[mod].path, 'files', file) : found
|
913
983
|
end
|
914
|
-
|
915
|
-
Bolt::Util.validate_file('script', path)
|
916
|
-
|
917
984
|
path
|
918
985
|
end
|
919
986
|
|
@@ -935,7 +1002,7 @@ module Bolt
|
|
935
1002
|
|
936
1003
|
def analytics
|
937
1004
|
@analytics ||= begin
|
938
|
-
client = Bolt::Analytics.build_client
|
1005
|
+
client = Bolt::Analytics.build_client(config.analytics)
|
939
1006
|
client.bundled_content = bundled_content
|
940
1007
|
client
|
941
1008
|
end
|
data/lib/bolt/config.rb
CHANGED
@@ -169,6 +169,7 @@ module Bolt
|
|
169
169
|
@config_files = []
|
170
170
|
|
171
171
|
default_data = {
|
172
|
+
'analytics' => true,
|
172
173
|
'apply-settings' => {},
|
173
174
|
'color' => true,
|
174
175
|
'compile-concurrency' => Etc.nprocessors,
|
@@ -263,6 +264,8 @@ module Bolt
|
|
263
264
|
# Disabled warnings are concatenated
|
264
265
|
when 'disable-warnings'
|
265
266
|
val1.concat(val2)
|
267
|
+
when 'analytics'
|
268
|
+
val1 && val2
|
266
269
|
# All other values are overwritten
|
267
270
|
else
|
268
271
|
val2
|
@@ -328,13 +331,6 @@ module Bolt
|
|
328
331
|
end
|
329
332
|
|
330
333
|
def validate
|
331
|
-
if @data['future']
|
332
|
-
Bolt::Logger.warn(
|
333
|
-
"future_option",
|
334
|
-
"Configuration option 'future' no longer exposes future behavior."
|
335
|
-
)
|
336
|
-
end
|
337
|
-
|
338
334
|
if @data['modulepath']&.include?(@project.managed_moduledir.to_s)
|
339
335
|
raise Bolt::ValidationError,
|
340
336
|
"Found invalid path in modulepath: #{@project.managed_moduledir}. This path "\
|
@@ -395,6 +391,10 @@ module Bolt
|
|
395
391
|
@data['format'] = value
|
396
392
|
end
|
397
393
|
|
394
|
+
def future
|
395
|
+
@data['future']
|
396
|
+
end
|
397
|
+
|
398
398
|
def trace
|
399
399
|
@data['trace']
|
400
400
|
end
|
@@ -459,6 +459,10 @@ module Bolt
|
|
459
459
|
Set.new(@project.disable_warnings + @data['disable-warnings'])
|
460
460
|
end
|
461
461
|
|
462
|
+
def analytics
|
463
|
+
@data['analytics']
|
464
|
+
end
|
465
|
+
|
462
466
|
# Check if there is a case-insensitive match to the path
|
463
467
|
def check_path_case(type, paths)
|
464
468
|
return if paths.nil?
|
data/lib/bolt/config/options.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'bolt/config/transport/
|
4
|
-
require 'bolt/config/transport/winrm'
|
5
|
-
require 'bolt/config/transport/orch'
|
3
|
+
require 'bolt/config/transport/docker'
|
6
4
|
require 'bolt/config/transport/local'
|
7
5
|
require 'bolt/config/transport/lxd'
|
8
|
-
require 'bolt/config/transport/
|
6
|
+
require 'bolt/config/transport/orch'
|
7
|
+
require 'bolt/config/transport/podman'
|
9
8
|
require 'bolt/config/transport/remote'
|
9
|
+
require 'bolt/config/transport/ssh'
|
10
|
+
require 'bolt/config/transport/winrm'
|
10
11
|
|
11
12
|
module Bolt
|
12
13
|
class Config
|
@@ -14,13 +15,14 @@ module Bolt
|
|
14
15
|
# Transport config classes. Used to load default transport config which
|
15
16
|
# gets passed along to the inventory.
|
16
17
|
TRANSPORT_CONFIG = {
|
17
|
-
'
|
18
|
-
'winrm' => Bolt::Config::Transport::WinRM,
|
19
|
-
'pcp' => Bolt::Config::Transport::Orch,
|
18
|
+
'docker' => Bolt::Config::Transport::Docker,
|
20
19
|
'local' => Bolt::Config::Transport::Local,
|
21
20
|
'lxd' => Bolt::Config::Transport::LXD,
|
22
|
-
'
|
23
|
-
'
|
21
|
+
'pcp' => Bolt::Config::Transport::Orch,
|
22
|
+
'podman' => Bolt::Config::Transport::Podman,
|
23
|
+
'remote' => Bolt::Config::Transport::Remote,
|
24
|
+
'ssh' => Bolt::Config::Transport::SSH,
|
25
|
+
'winrm' => Bolt::Config::Transport::WinRM
|
24
26
|
}.freeze
|
25
27
|
|
26
28
|
# Plugin definition. This is used by the JSON schemas to indicate that an option
|
@@ -55,6 +57,13 @@ module Bolt
|
|
55
57
|
# Definitions used to validate config options.
|
56
58
|
# https://github.com/puppetlabs/bolt/blob/main/schemas/README.md
|
57
59
|
OPTIONS = {
|
60
|
+
"analytics" => {
|
61
|
+
description: "Whether to disable analytics. Setting this option to 'false' in the system-wide "\
|
62
|
+
"or user-level configuration will disable analytics for all projects, even if this "\
|
63
|
+
"option is set to 'true' at the project level.",
|
64
|
+
type: [TrueClass, FalseClass],
|
65
|
+
_example: false
|
66
|
+
},
|
58
67
|
"apply-settings" => {
|
59
68
|
description: "A map of Puppet settings to use when applying Puppet code using the `apply` "\
|
60
69
|
"plan function or the `bolt apply` command.",
|
@@ -133,6 +142,20 @@ module Bolt
|
|
133
142
|
_example: "json",
|
134
143
|
_default: "human"
|
135
144
|
},
|
145
|
+
"future" => {
|
146
|
+
description: "Enable new Bolt features that may include breaking changes.",
|
147
|
+
type: Hash,
|
148
|
+
properties: {
|
149
|
+
"file_paths" => {
|
150
|
+
description: "Load scripts from the `scripts/` directory of a module",
|
151
|
+
type: [TrueClass, FalseClass],
|
152
|
+
_example: true,
|
153
|
+
_default: false
|
154
|
+
}
|
155
|
+
},
|
156
|
+
_plugin: false,
|
157
|
+
_example: { 'file_paths' => true }
|
158
|
+
},
|
136
159
|
"hiera-config" => {
|
137
160
|
description: "The path to the Hiera configuration file.",
|
138
161
|
type: String,
|
@@ -497,6 +520,12 @@ module Bolt
|
|
497
520
|
_plugin: true,
|
498
521
|
_example: { "job-poll-interval" => 15, "job-poll-timeout" => 30 }
|
499
522
|
},
|
523
|
+
"podman" => {
|
524
|
+
description: "A map of configuration options for the podman transport.",
|
525
|
+
type: Hash,
|
526
|
+
_plugin: true,
|
527
|
+
_example: { "cleanup" => false, "tmpdir" => "/mount/tmp" }
|
528
|
+
},
|
500
529
|
"remote" => {
|
501
530
|
description: "A map of configuration options for the remote transport.",
|
502
531
|
type: Hash,
|
@@ -532,6 +561,7 @@ module Bolt
|
|
532
561
|
|
533
562
|
# Options that are available in a bolt-defaults.yaml file
|
534
563
|
DEFAULTS_OPTIONS = %w[
|
564
|
+
analytics
|
535
565
|
color
|
536
566
|
compile-concurrency
|
537
567
|
concurrency
|
@@ -551,12 +581,14 @@ module Bolt
|
|
551
581
|
|
552
582
|
# Options that are available in a bolt-project.yaml file
|
553
583
|
PROJECT_OPTIONS = %w[
|
584
|
+
analytics
|
554
585
|
apply-settings
|
555
586
|
color
|
556
587
|
compile-concurrency
|
557
588
|
concurrency
|
558
589
|
disable-warnings
|
559
590
|
format
|
591
|
+
future
|
560
592
|
hiera-config
|
561
593
|
log
|
562
594
|
modulepath
|