bolt 2.40.2 → 3.1.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 +19 -17
- data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +25 -0
- data/bolt-modules/boltlib/lib/puppet/functions/parallelize.rb +6 -8
- data/bolt-modules/boltlib/lib/puppet/functions/wait_until_available.rb +7 -3
- data/lib/bolt/analytics.rb +3 -2
- data/lib/bolt/applicator.rb +11 -1
- data/lib/bolt/bolt_option_parser.rb +3 -113
- data/lib/bolt/catalog.rb +10 -29
- data/lib/bolt/cli.rb +54 -155
- data/lib/bolt/config.rb +62 -239
- data/lib/bolt/config/options.rb +58 -97
- data/lib/bolt/config/transport/local.rb +1 -0
- data/lib/bolt/config/transport/options.rb +8 -1
- data/lib/bolt/config/transport/orch.rb +1 -0
- data/lib/bolt/executor.rb +15 -5
- data/lib/bolt/inventory.rb +3 -2
- data/lib/bolt/inventory/group.rb +35 -4
- data/lib/bolt/inventory/inventory.rb +1 -1
- data/lib/bolt/logger.rb +115 -11
- data/lib/bolt/module.rb +10 -2
- data/lib/bolt/module_installer.rb +4 -2
- data/lib/bolt/module_installer/resolver.rb +65 -12
- data/lib/bolt/module_installer/specs/forge_spec.rb +8 -2
- data/lib/bolt/module_installer/specs/git_spec.rb +17 -2
- data/lib/bolt/outputter/human.rb +9 -5
- data/lib/bolt/outputter/json.rb +16 -16
- data/lib/bolt/outputter/rainbow.rb +3 -3
- data/lib/bolt/pal.rb +94 -14
- data/lib/bolt/pal/yaml_plan.rb +8 -2
- data/lib/bolt/pal/yaml_plan/evaluator.rb +7 -19
- data/lib/bolt/pal/yaml_plan/step.rb +3 -24
- data/lib/bolt/pal/yaml_plan/step/upload.rb +2 -2
- data/lib/bolt/pal/yaml_plan/transpiler.rb +6 -1
- data/lib/bolt/plugin.rb +3 -3
- data/lib/bolt/plugin/cache.rb +7 -7
- data/lib/bolt/plugin/module.rb +0 -23
- data/lib/bolt/plugin/puppet_connect_data.rb +77 -0
- data/lib/bolt/plugin/puppetdb.rb +1 -1
- data/lib/bolt/project.rb +54 -81
- data/lib/bolt/project_manager.rb +4 -3
- data/lib/bolt/project_manager/module_migrator.rb +6 -5
- data/lib/bolt/rerun.rb +1 -1
- data/lib/bolt/result.rb +6 -1
- data/lib/bolt/shell/bash.rb +9 -4
- data/lib/bolt/shell/bash/tmpdir.rb +4 -1
- data/lib/bolt/shell/powershell.rb +9 -5
- data/lib/bolt/shell/powershell/snippets.rb +37 -150
- data/lib/bolt/task.rb +1 -1
- data/lib/bolt/transport/base.rb +0 -9
- data/lib/bolt/transport/docker.rb +1 -125
- data/lib/bolt/transport/docker/connection.rb +86 -161
- data/lib/bolt/transport/local.rb +1 -9
- data/lib/bolt/transport/orch/connection.rb +1 -1
- data/lib/bolt/transport/ssh.rb +1 -2
- data/lib/bolt/transport/ssh/connection.rb +1 -1
- data/lib/bolt/validator.rb +2 -2
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/config.rb +1 -1
- data/lib/bolt_server/transport_app.rb +48 -31
- data/lib/bolt_spec/bolt_context.rb +9 -4
- data/lib/bolt_spec/plans.rb +1 -109
- data/libexec/bolt_catalog +1 -1
- data/modules/aggregate/plans/count.pp +21 -0
- data/modules/aggregate/plans/targets.pp +21 -0
- data/modules/puppet_connect/plans/test_input_data.pp +67 -0
- data/modules/puppetdb_fact/plans/init.pp +10 -0
- metadata +28 -19
- data/modules/aggregate/plans/nodes.pp +0 -36
data/lib/bolt/cli.rb
CHANGED
@@ -33,19 +33,18 @@ module Bolt
|
|
33
33
|
|
34
34
|
class CLI
|
35
35
|
COMMANDS = {
|
36
|
-
'command'
|
37
|
-
'script'
|
38
|
-
'task'
|
39
|
-
'plan'
|
40
|
-
'file'
|
41
|
-
'
|
42
|
-
'
|
43
|
-
'
|
44
|
-
'
|
45
|
-
'
|
46
|
-
'
|
47
|
-
'
|
48
|
-
'guide' => %w[]
|
36
|
+
'command' => %w[run],
|
37
|
+
'script' => %w[run],
|
38
|
+
'task' => %w[show run],
|
39
|
+
'plan' => %w[show run convert new],
|
40
|
+
'file' => %w[download upload],
|
41
|
+
'secret' => %w[encrypt decrypt createkeys],
|
42
|
+
'inventory' => %w[show],
|
43
|
+
'group' => %w[show],
|
44
|
+
'project' => %w[init migrate],
|
45
|
+
'module' => %w[add generate-types install show],
|
46
|
+
'apply' => %w[],
|
47
|
+
'guide' => %w[]
|
49
48
|
}.freeze
|
50
49
|
|
51
50
|
attr_reader :config, :options
|
@@ -147,10 +146,6 @@ module Bolt
|
|
147
146
|
end
|
148
147
|
|
149
148
|
validate(options)
|
150
|
-
|
151
|
-
# Deprecation warnings can't be issued until after config is loaded, so
|
152
|
-
# store them for later.
|
153
|
-
@parser_deprecations = parser.deprecations
|
154
149
|
rescue Bolt::Error => e
|
155
150
|
fatal_error(e)
|
156
151
|
raise e
|
@@ -159,25 +154,19 @@ module Bolt
|
|
159
154
|
# Loads the project and configuration. All errors that are raised here are not
|
160
155
|
# handled by the outputter, as it relies on config being loaded.
|
161
156
|
def load_config
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
Bolt::
|
157
|
+
project = if ENV['BOLT_PROJECT']
|
158
|
+
Bolt::Project.create_project(ENV['BOLT_PROJECT'], 'environment')
|
159
|
+
elsif options[:project]
|
160
|
+
dir = Pathname.new(options[:project])
|
161
|
+
if (dir + Bolt::Project::BOLTDIR_NAME).directory?
|
162
|
+
Bolt::Project.create_project(dir + Bolt::Project::BOLTDIR_NAME)
|
163
|
+
else
|
164
|
+
Bolt::Project.create_project(dir)
|
165
|
+
end
|
167
166
|
else
|
168
|
-
|
169
|
-
project = if cli_flag
|
170
|
-
dir = Pathname.new(cli_flag)
|
171
|
-
if (dir + Bolt::Project::BOLTDIR_NAME).directory?
|
172
|
-
Bolt::Project.create_project(dir + Bolt::Project::BOLTDIR_NAME)
|
173
|
-
else
|
174
|
-
Bolt::Project.create_project(dir)
|
175
|
-
end
|
176
|
-
else
|
177
|
-
Bolt::Project.find_boltdir(Dir.pwd)
|
178
|
-
end
|
179
|
-
Bolt::Config.from_project(project, options)
|
167
|
+
Bolt::Project.find_boltdir(Dir.pwd)
|
180
168
|
end
|
169
|
+
@config = Bolt::Config.from_project(project, options)
|
181
170
|
rescue Bolt::Error => e
|
182
171
|
fatal_error(e)
|
183
172
|
raise e
|
@@ -185,20 +174,16 @@ module Bolt
|
|
185
174
|
|
186
175
|
# Completes the setup process by configuring Bolt and log messages
|
187
176
|
def finalize_setup
|
188
|
-
Bolt::Logger.configure(config.log, config.color)
|
177
|
+
Bolt::Logger.configure(config.log, config.color, config.disable_warnings)
|
189
178
|
Bolt::Logger.analytics = analytics
|
179
|
+
Bolt::Logger.flush_queue
|
190
180
|
|
191
181
|
# Logger must be configured before checking path case and project file, otherwise logs will not display
|
192
182
|
config.check_path_case('modulepath', config.modulepath)
|
193
183
|
config.project.check_deprecated_file
|
194
184
|
|
195
|
-
|
196
|
-
|
197
|
-
@parser_deprecations.each { |dep| Bolt::Logger.deprecation_warning(dep[:type], dep[:msg]) }
|
198
|
-
config.deprecations.each { |dep| Bolt::Logger.deprecation_warning(dep[:type], dep[:msg]) }
|
199
|
-
|
200
|
-
if options[:clear_cache] && File.exist?(config.project.cache_file)
|
201
|
-
FileUtils.rm(config.project.cache_file)
|
185
|
+
if options[:clear_cache] && File.exist?(config.project.plugin_cache_file)
|
186
|
+
FileUtils.rm(config.project.plugin_cache_file)
|
202
187
|
end
|
203
188
|
|
204
189
|
warn_inventory_overrides_cli(options)
|
@@ -218,9 +203,8 @@ module Bolt
|
|
218
203
|
|
219
204
|
return unless !stdout.empty? && stdout.to_i < 3
|
220
205
|
|
221
|
-
msg = "Detected PowerShell 2 on controller. PowerShell 2 is
|
222
|
-
|
223
|
-
Bolt::Logger.deprecation_warning("PowerShell 2 controller", msg)
|
206
|
+
msg = "Detected PowerShell 2 on controller. PowerShell 2 is unsupported."
|
207
|
+
Bolt::Logger.deprecation_warning("powershell_2_controller", msg)
|
224
208
|
end
|
225
209
|
end
|
226
210
|
|
@@ -314,10 +298,6 @@ module Bolt
|
|
314
298
|
"Unknown argument(s) #{options[:leftovers].join(', ')}"
|
315
299
|
end
|
316
300
|
|
317
|
-
if options.slice(:boltdir, :configfile, :project).length > 1
|
318
|
-
raise Bolt::CLIError, "Only one of '--boltdir', '--project', or '--configfile' may be specified"
|
319
|
-
end
|
320
|
-
|
321
301
|
if options[:noop] &&
|
322
302
|
!(options[:subcommand] == 'task' && options[:action] == 'run') && options[:subcommand] != 'apply'
|
323
303
|
raise Bolt::CLIError,
|
@@ -330,10 +310,6 @@ module Bolt
|
|
330
310
|
"Option '--env-var' may only be specified when running a command or script"
|
331
311
|
end
|
332
312
|
end
|
333
|
-
|
334
|
-
if options.key?(:debug) && options.key?(:log)
|
335
|
-
raise Bolt::CLIError, "Only one of '--debug' or '--log-level' may be specified"
|
336
|
-
end
|
337
313
|
end
|
338
314
|
|
339
315
|
def handle_parser_errors
|
@@ -376,7 +352,10 @@ module Bolt
|
|
376
352
|
conflicting_options = Set.new(opts.keys.map(&:to_s)).intersection(inventory_cli_opts)
|
377
353
|
|
378
354
|
if inventory_source && conflicting_options.any?
|
379
|
-
|
355
|
+
Bolt::Logger.warn(
|
356
|
+
"cli_overrides",
|
357
|
+
"CLI arguments #{conflicting_options.to_a} may be overridden by Inventory: #{inventory_source}"
|
358
|
+
)
|
380
359
|
end
|
381
360
|
end
|
382
361
|
|
@@ -393,7 +372,7 @@ module Bolt
|
|
393
372
|
# Initialize inventory and targets. Errors here are better to catch early.
|
394
373
|
# options[:target_args] will contain a string/array version of the targetting options this is passed to plans
|
395
374
|
# options[:targets] will contain a resolved set of Target objects
|
396
|
-
unless %w[guide module project
|
375
|
+
unless %w[guide module project secret].include?(options[:subcommand]) ||
|
397
376
|
%w[convert new show].include?(options[:action])
|
398
377
|
update_targets(options)
|
399
378
|
end
|
@@ -448,9 +427,6 @@ module Bolt
|
|
448
427
|
list_modules
|
449
428
|
end
|
450
429
|
return 0
|
451
|
-
when 'show-modules'
|
452
|
-
list_modules
|
453
|
-
return 0
|
454
430
|
when 'convert'
|
455
431
|
pal.convert_plan(options[:object])
|
456
432
|
return 0
|
@@ -500,17 +476,6 @@ module Bolt
|
|
500
476
|
when 'generate-types'
|
501
477
|
code = generate_types
|
502
478
|
end
|
503
|
-
when 'puppetfile'
|
504
|
-
case options[:action]
|
505
|
-
when 'generate-types'
|
506
|
-
code = generate_types
|
507
|
-
when 'install'
|
508
|
-
code = install_puppetfile(
|
509
|
-
config.puppetfile_config,
|
510
|
-
config.puppetfile,
|
511
|
-
config.modulepath.first
|
512
|
-
)
|
513
|
-
end
|
514
479
|
when 'secret'
|
515
480
|
code = Bolt::Secret.execute(plugins, outputter, options)
|
516
481
|
when 'apply'
|
@@ -528,7 +493,6 @@ module Bolt
|
|
528
493
|
|
529
494
|
elapsed_time = Benchmark.realtime do
|
530
495
|
executor_opts = {}
|
531
|
-
executor_opts[:description] = options[:description] if options.key?(:description)
|
532
496
|
executor_opts[:env_vars] = options[:env_vars] if options.key?(:env_vars)
|
533
497
|
executor.subscribe(outputter)
|
534
498
|
executor.subscribe(log_outputter)
|
@@ -541,15 +505,11 @@ module Bolt
|
|
541
505
|
validate_file('script', script)
|
542
506
|
executor.run_script(targets, script, options[:leftovers], executor_opts)
|
543
507
|
when 'task'
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
inventory,
|
550
|
-
options[:description])
|
551
|
-
end
|
552
|
-
r
|
508
|
+
pal.run_task(options[:object],
|
509
|
+
targets,
|
510
|
+
options[:task_options],
|
511
|
+
executor,
|
512
|
+
inventory)
|
553
513
|
when 'file'
|
554
514
|
src = options[:object]
|
555
515
|
dest = options[:leftovers].first
|
@@ -610,7 +570,7 @@ module Bolt
|
|
610
570
|
end
|
611
571
|
|
612
572
|
def list_plans
|
613
|
-
plans = filter_content(pal.
|
573
|
+
plans = filter_content(pal.list_plans_with_cache(filter_content: true), options[:filter])
|
614
574
|
outputter.print_plans(plans, pal.user_modulepath)
|
615
575
|
end
|
616
576
|
|
@@ -662,7 +622,7 @@ module Bolt
|
|
662
622
|
if node_param && target_param
|
663
623
|
msg = "Plan parameters include both 'nodes' and 'targets' with type 'TargetSpec', " \
|
664
624
|
"neither will populated with the value for --nodes or --targets."
|
665
|
-
|
625
|
+
Bolt::Logger.warn("nodes_targets_parameters", msg)
|
666
626
|
elsif node_param
|
667
627
|
plan_arguments['nodes'] = nodes.join(',')
|
668
628
|
elsif target_param
|
@@ -672,7 +632,6 @@ module Bolt
|
|
672
632
|
|
673
633
|
plan_context = { plan_name: plan_name,
|
674
634
|
params: plan_arguments }
|
675
|
-
plan_context[:description] = options[:description] if options[:description]
|
676
635
|
|
677
636
|
executor = Bolt::Executor.new(config.concurrency, analytics, options[:noop], config.modified_concurrency)
|
678
637
|
if %w[human rainbow].include?(options.fetch(:format, 'human'))
|
@@ -684,9 +643,7 @@ module Bolt
|
|
684
643
|
|
685
644
|
executor.subscribe(log_outputter)
|
686
645
|
executor.start_plan(plan_context)
|
687
|
-
result =
|
688
|
-
pal.run_plan(plan_name, plan_arguments, executor, inventory, puppetdb_client)
|
689
|
-
end
|
646
|
+
result = pal.run_plan(plan_name, plan_arguments, executor, inventory, puppetdb_client)
|
690
647
|
|
691
648
|
# If a non-bolt exception bubbles up the plan won't get finished
|
692
649
|
executor.finish_plan(result)
|
@@ -709,7 +666,7 @@ module Bolt
|
|
709
666
|
"about defining and declaring classes and types in the Puppet documentation at "\
|
710
667
|
"https://puppet.com/docs/puppet/latest/lang_classes.html and "\
|
711
668
|
"https://puppet.com/docs/puppet/latest/lang_defined_types.html"
|
712
|
-
|
669
|
+
Bolt::Logger.warn("empty_manifest", message)
|
713
670
|
end
|
714
671
|
|
715
672
|
executor = Bolt::Executor.new(config.concurrency, analytics, noop, config.modified_concurrency)
|
@@ -738,14 +695,12 @@ module Bolt
|
|
738
695
|
end
|
739
696
|
|
740
697
|
def list_modules
|
741
|
-
assert_puppetfile_or_module_command(config.project.modules)
|
742
698
|
outputter.print_module_list(pal.list_modules)
|
743
699
|
end
|
744
700
|
|
745
701
|
def generate_types
|
746
|
-
assert_puppetfile_or_module_command(config.project.modules)
|
747
702
|
# generate_types will surface a nice error with helpful message if it fails
|
748
|
-
pal.generate_types
|
703
|
+
pal.generate_types(cache: true)
|
749
704
|
0
|
750
705
|
end
|
751
706
|
|
@@ -753,27 +708,19 @@ module Bolt
|
|
753
708
|
#
|
754
709
|
def install_project_modules(project, config, force, resolve)
|
755
710
|
assert_project_file(project)
|
756
|
-
assert_puppetfile_or_module_command(project.modules)
|
757
|
-
|
758
|
-
unless project.modules
|
759
|
-
outputter.print_message "Project configuration file #{project.project_file} does not "\
|
760
|
-
"specify any module dependencies. Nothing to do."
|
761
|
-
return 0
|
762
|
-
end
|
763
711
|
|
764
|
-
if resolve != false
|
765
|
-
|
766
|
-
"
|
767
|
-
"
|
768
|
-
"For more information, see https://pup.pt/bolt-module-install"
|
712
|
+
if project.modules.empty? && resolve != false
|
713
|
+
outputter.print_message(
|
714
|
+
"Project configuration file #{project.project_file} does not "\
|
715
|
+
"specify any module dependencies. Nothing to do."
|
769
716
|
)
|
717
|
+
return 0
|
770
718
|
end
|
771
719
|
|
772
|
-
modules = project.modules || []
|
773
720
|
installer = Bolt::ModuleInstaller.new(outputter, pal)
|
774
721
|
|
775
722
|
ok = outputter.spin do
|
776
|
-
installer.install(modules,
|
723
|
+
installer.install(project.modules,
|
777
724
|
project.puppetfile,
|
778
725
|
project.managed_moduledir,
|
779
726
|
config,
|
@@ -788,22 +735,12 @@ module Bolt
|
|
788
735
|
#
|
789
736
|
def add_project_module(name, project, config)
|
790
737
|
assert_project_file(project)
|
791
|
-
assert_puppetfile_or_module_command(project.modules)
|
792
738
|
|
793
|
-
if config.any?
|
794
|
-
@logger.warn(
|
795
|
-
"Detected configuration for 'module-install'. This configuration is currently "\
|
796
|
-
"only supported when installing modules, not when resolving module dependencies. "\
|
797
|
-
"For more information, see https://pup.pt/bolt-module-install"
|
798
|
-
)
|
799
|
-
end
|
800
|
-
|
801
|
-
modules = project.modules || []
|
802
739
|
installer = Bolt::ModuleInstaller.new(outputter, pal)
|
803
740
|
|
804
741
|
ok = outputter.spin do
|
805
742
|
installer.add(name,
|
806
|
-
modules,
|
743
|
+
project.modules,
|
807
744
|
project.puppetfile,
|
808
745
|
project.managed_moduledir,
|
809
746
|
project.project_file,
|
@@ -834,8 +771,6 @@ module Bolt
|
|
834
771
|
# Loads a Puppetfile and installs its modules.
|
835
772
|
#
|
836
773
|
def install_puppetfile(puppetfile_config, puppetfile, moduledir)
|
837
|
-
assert_puppetfile_or_module_command(config.project.modules)
|
838
|
-
|
839
774
|
outputter.print_message("Installing modules from Puppetfile")
|
840
775
|
installer = Bolt::ModuleInstaller.new(outputter, pal)
|
841
776
|
ok = outputter.spin do
|
@@ -845,43 +780,6 @@ module Bolt
|
|
845
780
|
ok ? 0 : 1
|
846
781
|
end
|
847
782
|
|
848
|
-
# Raises an error if the 'puppetfile install' command is deprecated due to
|
849
|
-
# modules being configured.
|
850
|
-
#
|
851
|
-
def assert_puppetfile_or_module_command(modules)
|
852
|
-
if Bolt::Util.powershell?
|
853
|
-
case options[:action]
|
854
|
-
when 'generate-types'
|
855
|
-
old_command = 'Register-BoltPuppetfileTypes'
|
856
|
-
new_command = 'Register-BoltModuleTypes'
|
857
|
-
when 'install'
|
858
|
-
old_command = 'Install-BoltPuppetfile'
|
859
|
-
new_command = 'Install-BoltModule'
|
860
|
-
when 'show', 'show-modules'
|
861
|
-
old_command = 'Get-BoltPuppetfileModules'
|
862
|
-
new_command = 'Get-BoltModule'
|
863
|
-
end
|
864
|
-
else
|
865
|
-
old_command = "bolt puppetfile #{options[:action]}"
|
866
|
-
new_command = if options[:action] == 'show-modules'
|
867
|
-
'bolt module show'
|
868
|
-
else
|
869
|
-
"bolt module #{options[:action]}"
|
870
|
-
end
|
871
|
-
end
|
872
|
-
|
873
|
-
if modules && options[:subcommand] == 'puppetfile'
|
874
|
-
raise Bolt::CLIError,
|
875
|
-
"Unable to use command '#{old_command}' when 'modules' is configured in "\
|
876
|
-
"bolt-project.yaml. Use '#{new_command}' instead."
|
877
|
-
elsif modules.nil? && options[:subcommand] == 'module'
|
878
|
-
msg = "Unable to use command '#{new_command}' when 'modules' is not configured in "\
|
879
|
-
"bolt-project.yaml. "
|
880
|
-
msg += "Use '#{old_command}' instead." if options[:action] != 'add'
|
881
|
-
raise Bolt::CLIError, msg
|
882
|
-
end
|
883
|
-
end
|
884
|
-
|
885
783
|
def pal
|
886
784
|
@pal ||= Bolt::PAL.new(Bolt::Config::Modulepath.new(config.modulepath),
|
887
785
|
config.hiera_config,
|
@@ -978,7 +876,7 @@ module Bolt
|
|
978
876
|
set the BOLT_GEM environment variable.
|
979
877
|
MSG
|
980
878
|
|
981
|
-
|
879
|
+
Bolt::Logger.warn("gem_install", msg)
|
982
880
|
end
|
983
881
|
|
984
882
|
# We only need to enumerate bundled content when running a task or plan
|
@@ -1001,7 +899,8 @@ module Bolt
|
|
1001
899
|
# Gem installs include the aggregate, canary, and puppetdb_fact modules, while
|
1002
900
|
# package installs include modules listed in the Bolt repo Puppetfile
|
1003
901
|
def incomplete_install?
|
1004
|
-
|
902
|
+
builtin_module_list = %w[aggregate canary puppetdb_fact secure_env_vars puppet_connect]
|
903
|
+
(Dir.children(Bolt::Config::Modulepath::MODULES_PATH) - builtin_module_list).empty?
|
1005
904
|
end
|
1006
905
|
|
1007
906
|
# Mimicks the output from Outputter::Human#fatal_error. This should be used to print
|
data/lib/bolt/config.rb
CHANGED
@@ -20,10 +20,9 @@ module Bolt
|
|
20
20
|
class Config
|
21
21
|
include Bolt::Config::Options
|
22
22
|
|
23
|
-
attr_reader :config_files, :
|
23
|
+
attr_reader :config_files, :data, :transports, :project, :modified_concurrency
|
24
24
|
|
25
|
-
|
26
|
-
BOLT_DEFAULTS_NAME = 'bolt-defaults.yaml'
|
25
|
+
DEFAULTS_NAME = 'bolt-defaults.yaml'
|
27
26
|
|
28
27
|
# The default concurrency value that is used when the ulimit is not low (i.e. < 700)
|
29
28
|
DEFAULT_DEFAULT_CONCURRENCY = 100
|
@@ -33,70 +32,9 @@ module Bolt
|
|
33
32
|
end
|
34
33
|
|
35
34
|
def self.from_project(project, overrides = {})
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
conf = if project.project_file == project.config_file
|
40
|
-
project.data
|
41
|
-
else
|
42
|
-
c = Bolt::Util.read_optional_yaml_hash(project.config_file, 'config')
|
43
|
-
|
44
|
-
# Validate the config against the schema. This will raise a single error
|
45
|
-
# with all validation errors.
|
46
|
-
Bolt::Validator.new.tap do |validator|
|
47
|
-
validator.validate(c, bolt_schema, project.config_file.to_s)
|
48
|
-
|
49
|
-
validator.warnings.each { |warning| logs << { warn: warning } }
|
50
|
-
|
51
|
-
validator.deprecations.each do |dep|
|
52
|
-
deprecations << { type: "#{BOLT_CONFIG_NAME} #{dep[:option]}", msg: dep[:message] }
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
logs << { debug: "Loaded configuration from #{project.config_file}" } if File.exist?(project.config_file)
|
57
|
-
c
|
58
|
-
end
|
59
|
-
data = load_defaults(project).push(
|
60
|
-
filepath: project.config_file,
|
61
|
-
data: conf,
|
62
|
-
logs: logs,
|
63
|
-
deprecations: deprecations
|
64
|
-
)
|
65
|
-
|
66
|
-
new(project, data, overrides)
|
67
|
-
end
|
68
|
-
|
69
|
-
def self.from_file(configfile, overrides = {})
|
70
|
-
project = Bolt::Project.create_project(Pathname.new(configfile).expand_path.dirname)
|
71
|
-
logs = []
|
72
|
-
deprecations = []
|
73
|
-
|
74
|
-
conf = if project.project_file == project.config_file
|
75
|
-
project.data
|
76
|
-
else
|
77
|
-
c = Bolt::Util.read_yaml_hash(configfile, 'config')
|
78
|
-
|
79
|
-
# Validate the config against the schema. This will raise a single error
|
80
|
-
# with all validation errors.
|
81
|
-
Bolt::Validator.new.tap do |validator|
|
82
|
-
validator.validate(c, bolt_schema, project.config_file.to_s)
|
83
|
-
|
84
|
-
validator.warnings.each { |warning| logs << { warn: warning } }
|
85
|
-
|
86
|
-
validator.deprecations.each do |dep|
|
87
|
-
deprecations << { type: "#{BOLT_CONFIG_NAME} #{dep[:option]}", msg: dep[:message] }
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
logs << { debug: "Loaded configuration from #{configfile}" }
|
92
|
-
c
|
93
|
-
end
|
94
|
-
|
95
|
-
data = load_defaults(project).push(
|
96
|
-
filepath: configfile,
|
97
|
-
data: conf,
|
98
|
-
logs: logs,
|
99
|
-
deprecations: deprecations
|
35
|
+
data = load_defaults.push(
|
36
|
+
filepath: project.project_file,
|
37
|
+
data: project.data
|
100
38
|
)
|
101
39
|
|
102
40
|
new(project, data, overrides)
|
@@ -115,7 +53,7 @@ module Bolt
|
|
115
53
|
def self.defaults_schema
|
116
54
|
schema = {
|
117
55
|
type: Hash,
|
118
|
-
properties:
|
56
|
+
properties: DEFAULTS_OPTIONS.map { |opt| [opt, _ref: opt] }.to_h,
|
119
57
|
definitions: OPTIONS.merge(transport_definitions)
|
120
58
|
}
|
121
59
|
|
@@ -124,16 +62,6 @@ module Bolt
|
|
124
62
|
schema
|
125
63
|
end
|
126
64
|
|
127
|
-
# Builds the schema for bolt.yaml used by the validator.
|
128
|
-
#
|
129
|
-
def self.bolt_schema
|
130
|
-
{
|
131
|
-
type: Hash,
|
132
|
-
properties: (BOLT_OPTIONS + INVENTORY_OPTIONS.keys).map { |opt| [opt, _ref: opt] }.to_h,
|
133
|
-
definitions: OPTIONS.merge(transport_definitions)
|
134
|
-
}
|
135
|
-
end
|
136
|
-
|
137
65
|
def self.system_path
|
138
66
|
if Bolt::Util.windows?
|
139
67
|
Pathname.new(File.join(ENV['ALLUSERSPROFILE'], 'PuppetLabs', 'bolt', 'etc'))
|
@@ -149,41 +77,31 @@ module Bolt
|
|
149
77
|
end
|
150
78
|
|
151
79
|
# Loads a 'bolt-defaults.yaml' file, which contains default configuration that applies to all
|
152
|
-
# projects. This file does not allow project-specific configuration such as 'hiera-config'
|
153
|
-
#
|
80
|
+
# projects. This file does not allow project-specific configuration such as 'hiera-config'
|
81
|
+
# and nests all default inventory configuration under an 'inventory-config' key.
|
154
82
|
def self.load_bolt_defaults_yaml(dir)
|
155
|
-
filepath = dir +
|
83
|
+
filepath = dir + DEFAULTS_NAME
|
156
84
|
data = Bolt::Util.read_yaml_hash(filepath, 'config')
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
# Warn if 'bolt.yaml' detected in same directory.
|
161
|
-
if File.exist?(bolt_yaml = dir + BOLT_CONFIG_NAME)
|
162
|
-
logs.push(
|
163
|
-
warn: "Detected multiple configuration files: ['#{bolt_yaml}', '#{filepath}']. '#{bolt_yaml}' "\
|
164
|
-
"will be ignored."
|
165
|
-
)
|
166
|
-
end
|
85
|
+
|
86
|
+
Bolt::Logger.debug("Loaded configuration from #{filepath}")
|
167
87
|
|
168
88
|
# Validate the config against the schema. This will raise a single error
|
169
89
|
# with all validation errors.
|
170
90
|
Bolt::Validator.new.tap do |validator|
|
171
91
|
validator.validate(data, defaults_schema, filepath)
|
172
|
-
|
173
|
-
validator.
|
174
|
-
|
175
|
-
validator.deprecations.each do |dep|
|
176
|
-
deprecations << { type: "#{BOLT_DEFAULTS_NAME} #{dep[:option]}", msg: dep[:message] }
|
177
|
-
end
|
92
|
+
validator.warnings.each { |warning| Bolt::Logger.warn(warning[:id], warning[:msg]) }
|
93
|
+
validator.deprecations.each { |dep| Bolt::Logger.deprecate(dep[:id], dep[:msg]) }
|
178
94
|
end
|
179
95
|
|
180
96
|
# Remove project-specific config such as hiera-config, etc.
|
181
|
-
project_config = data.slice(*(
|
97
|
+
project_config = data.slice(*(PROJECT_OPTIONS - DEFAULTS_OPTIONS))
|
182
98
|
|
183
99
|
if project_config.any?
|
184
100
|
data.reject! { |key, _| project_config.include?(key) }
|
185
|
-
|
186
|
-
|
101
|
+
|
102
|
+
Bolt::Logger.warn(
|
103
|
+
"unsupported_project_config",
|
104
|
+
"Unsupported project configuration detected in '#{filepath}': #{project_config.keys}. "\
|
187
105
|
"Project configuration should be set in 'bolt-project.yaml'."
|
188
106
|
)
|
189
107
|
end
|
@@ -193,8 +111,10 @@ module Bolt
|
|
193
111
|
|
194
112
|
if transport_config.any?
|
195
113
|
data.reject! { |key, _| transport_config.include?(key) }
|
196
|
-
|
197
|
-
|
114
|
+
|
115
|
+
Bolt::Logger.warn(
|
116
|
+
"unsupported_inventory_config",
|
117
|
+
"Unsupported inventory configuration detected in '#{filepath}': #{transport_config.keys}. "\
|
198
118
|
"Transport configuration should be set under the 'inventory-config' option or "\
|
199
119
|
"in 'inventory.yaml'."
|
200
120
|
)
|
@@ -219,55 +139,20 @@ module Bolt
|
|
219
139
|
data = data.merge(data.delete('inventory-config'))
|
220
140
|
end
|
221
141
|
|
222
|
-
{ filepath: filepath, data: data
|
223
|
-
end
|
224
|
-
|
225
|
-
# Loads a 'bolt.yaml' file, the legacy configuration file. There's no special munging needed
|
226
|
-
# here since Bolt::Config will just ignore any invalid keys.
|
227
|
-
def self.load_bolt_yaml(dir)
|
228
|
-
filepath = dir + BOLT_CONFIG_NAME
|
229
|
-
data = Bolt::Util.read_yaml_hash(filepath, 'config')
|
230
|
-
logs = [{ debug: "Loaded configuration from #{filepath}" }]
|
231
|
-
deprecations = [{ type: 'Using bolt.yaml for system configuration',
|
232
|
-
msg: "Configuration file #{filepath} is deprecated and will be removed in Bolt 3.0. "\
|
233
|
-
"See https://pup.pt/update-bolt-config for how to update to the latest Bolt practices." }]
|
234
|
-
|
235
|
-
# Validate the config against the schema. This will raise a single error
|
236
|
-
# with all validation errors.
|
237
|
-
Bolt::Validator.new.tap do |validator|
|
238
|
-
validator.validate(data, bolt_schema, filepath)
|
239
|
-
|
240
|
-
validator.warnings.each { |warning| logs << { warn: warning } }
|
241
|
-
|
242
|
-
validator.deprecations.each do |dep|
|
243
|
-
deprecations << { type: "#{BOLT_CONFIG_NAME} #{dep[:option]}", msg: dep[:message] }
|
244
|
-
end
|
245
|
-
end
|
246
|
-
|
247
|
-
{ filepath: filepath, data: data, logs: logs, deprecations: deprecations }
|
142
|
+
{ filepath: filepath, data: data }
|
248
143
|
end
|
249
144
|
|
250
|
-
def self.load_defaults
|
145
|
+
def self.load_defaults
|
251
146
|
confs = []
|
252
147
|
|
253
|
-
# Load system-level config.
|
254
|
-
|
255
|
-
# config file, don't load it a second time.
|
256
|
-
if File.exist?(system_path + BOLT_DEFAULTS_NAME)
|
148
|
+
# Load system-level config.
|
149
|
+
if File.exist?(system_path + DEFAULTS_NAME)
|
257
150
|
confs << load_bolt_defaults_yaml(system_path)
|
258
|
-
elsif File.exist?(system_path + BOLT_CONFIG_NAME) &&
|
259
|
-
(system_path + BOLT_CONFIG_NAME) != project.config_file
|
260
|
-
confs << load_bolt_yaml(system_path)
|
261
151
|
end
|
262
152
|
|
263
|
-
# Load user-level config if there is a homedir.
|
264
|
-
|
265
|
-
|
266
|
-
if File.exist?(user_path + BOLT_DEFAULTS_NAME)
|
267
|
-
confs << load_bolt_defaults_yaml(user_path)
|
268
|
-
elsif File.exist?(user_path + BOLT_CONFIG_NAME)
|
269
|
-
confs << load_bolt_yaml(user_path)
|
270
|
-
end
|
153
|
+
# Load user-level config if there is a homedir.
|
154
|
+
if user_path && File.exist?(user_path + DEFAULTS_NAME)
|
155
|
+
confs << load_bolt_defaults_yaml(user_path)
|
271
156
|
end
|
272
157
|
|
273
158
|
confs
|
@@ -275,33 +160,26 @@ module Bolt
|
|
275
160
|
|
276
161
|
def initialize(project, config_data, overrides = {})
|
277
162
|
unless config_data.is_a?(Array)
|
278
|
-
config_data = [{ filepath: project.
|
279
|
-
data: config_data,
|
280
|
-
logs: [],
|
281
|
-
deprecations: [] }]
|
163
|
+
config_data = [{ filepath: project.project_file, data: config_data }]
|
282
164
|
end
|
283
165
|
|
284
166
|
@logger = Bolt::Logger.logger(self)
|
285
167
|
@project = project
|
286
|
-
@logs = @project.logs.dup
|
287
|
-
@deprecations = @project.deprecations.dup
|
288
168
|
@transports = {}
|
289
169
|
@config_files = []
|
290
170
|
|
291
171
|
default_data = {
|
292
172
|
'apply-settings' => {},
|
293
|
-
'apply_settings' => {},
|
294
173
|
'color' => true,
|
295
174
|
'compile-concurrency' => Etc.nprocessors,
|
296
175
|
'concurrency' => default_concurrency,
|
176
|
+
'disable-warnings' => [],
|
297
177
|
'format' => 'human',
|
298
178
|
'log' => { 'console' => {} },
|
299
179
|
'module-install' => {},
|
300
180
|
'plugin-hooks' => {},
|
301
|
-
'plugin_hooks' => {},
|
302
181
|
'plugins' => {},
|
303
182
|
'puppetdb' => {},
|
304
|
-
'puppetfile' => {},
|
305
183
|
'save-rerun' => true,
|
306
184
|
'spinner' => true,
|
307
185
|
'transport' => 'ssh'
|
@@ -315,9 +193,6 @@ module Bolt
|
|
315
193
|
end
|
316
194
|
|
317
195
|
loaded_data = config_data.each_with_object([]) do |data, acc|
|
318
|
-
@logs.concat(data[:logs]) if data[:logs].any?
|
319
|
-
@deprecations.concat(data[:deprecations]) if data[:deprecations].any?
|
320
|
-
|
321
196
|
if data[:data].any?
|
322
197
|
@config_files.push(data[:filepath])
|
323
198
|
acc.push(data[:data])
|
@@ -347,28 +222,25 @@ module Bolt
|
|
347
222
|
def normalize_overrides(options)
|
348
223
|
opts = options.transform_keys(&:to_s)
|
349
224
|
|
350
|
-
# Pull out config options. We need to add 'transport'
|
351
|
-
# OPTIONS hash but
|
352
|
-
overrides = opts.slice(*OPTIONS.keys, 'transport')
|
225
|
+
# Pull out config options. We need to add 'transport' and 'inventoryfile' as they're
|
226
|
+
# not part of the OPTIONS hash but are valid options that can be set with CLI options
|
227
|
+
overrides = opts.slice(*OPTIONS.keys, 'inventoryfile', 'transport')
|
353
228
|
|
354
229
|
# Pull out transport config options
|
355
230
|
TRANSPORT_CONFIG.each do |transport, config|
|
356
231
|
overrides[transport] = opts.slice(*config.options)
|
357
232
|
end
|
358
233
|
|
359
|
-
# Set console log to debug if in debug mode
|
360
|
-
if options[:debug]
|
361
|
-
overrides['log'] = { 'console' => { 'level' => 'debug' } }
|
362
|
-
end
|
363
|
-
|
364
|
-
if options[:puppetfile_path]
|
365
|
-
@puppetfile = options[:puppetfile_path]
|
366
|
-
end
|
367
|
-
|
368
234
|
overrides['trace'] = opts['trace'] if opts.key?('trace')
|
369
235
|
|
370
|
-
# Validate the overrides
|
371
|
-
|
236
|
+
# Validate the overrides that can have arbitrary values
|
237
|
+
schema = {
|
238
|
+
type: Hash,
|
239
|
+
properties: CLI_OPTIONS.map { |opt| [opt, _ref: opt] }.to_h,
|
240
|
+
definitions: OPTIONS.merge(INVENTORY_OPTIONS)
|
241
|
+
}
|
242
|
+
|
243
|
+
Bolt::Validator.new.validate(overrides.slice(*CLI_OPTIONS), schema, 'command line')
|
372
244
|
|
373
245
|
overrides
|
374
246
|
end
|
@@ -386,8 +258,11 @@ module Bolt
|
|
386
258
|
when *TRANSPORT_CONFIG.keys
|
387
259
|
Bolt::Util.deep_merge(val1, val2)
|
388
260
|
# Hash values are shallow merged
|
389
|
-
when '
|
261
|
+
when 'apply-settings', 'log', 'plugin-hooks', 'puppetdb'
|
390
262
|
val1.merge(val2)
|
263
|
+
# Disabled warnings are concatenated
|
264
|
+
when 'disable-warnings'
|
265
|
+
val1.concat(val2)
|
391
266
|
# All other values are overwritten
|
392
267
|
else
|
393
268
|
val2
|
@@ -423,7 +298,7 @@ module Bolt
|
|
423
298
|
end
|
424
299
|
|
425
300
|
# Filter hashes to only include valid options
|
426
|
-
%w[apply-settings
|
301
|
+
%w[apply-settings module-install].each do |opt|
|
427
302
|
@data[opt] = @data[opt].slice(*OPTIONS.dig(opt, :properties).keys)
|
428
303
|
end
|
429
304
|
end
|
@@ -449,23 +324,18 @@ module Bolt
|
|
449
324
|
|
450
325
|
name = normalize_log(key)
|
451
326
|
acc[name] = val.slice('append', 'level').transform_keys(&:to_sym)
|
452
|
-
|
453
|
-
next unless acc[name][:level] == 'notice'
|
454
|
-
|
455
|
-
@deprecations << {
|
456
|
-
type: 'notice log level',
|
457
|
-
msg: "Log level 'notice' is deprecated and will be removed in Bolt 3.0. Use 'info' instead."
|
458
|
-
}
|
459
327
|
end
|
460
328
|
end
|
461
329
|
|
462
330
|
def validate
|
463
331
|
if @data['future']
|
464
|
-
|
465
|
-
|
332
|
+
Bolt::Logger.warn(
|
333
|
+
"future_option",
|
334
|
+
"Configuration option 'future' no longer exposes future behavior."
|
335
|
+
)
|
466
336
|
end
|
467
337
|
|
468
|
-
if @
|
338
|
+
if @data['modulepath']&.include?(@project.managed_moduledir.to_s)
|
469
339
|
raise Bolt::ValidationError,
|
470
340
|
"Found invalid path in modulepath: #{@project.managed_moduledir}. This path "\
|
471
341
|
"is automatically appended to the modulepath and cannot be configured."
|
@@ -483,25 +353,6 @@ module Bolt
|
|
483
353
|
if File.exist?(default_inventoryfile)
|
484
354
|
Bolt::Util.validate_file('inventory file', default_inventoryfile)
|
485
355
|
end
|
486
|
-
|
487
|
-
# Warn the user how they should be using the 'puppetfile' or
|
488
|
-
# 'module-install' config options. We don't error here since these
|
489
|
-
# settings can be set at the user or system level.
|
490
|
-
if @project.modules && puppetfile_config.any? && module_install.empty?
|
491
|
-
command = Bolt::Util.powershell? ? 'Update-BoltProject' : 'bolt project migrate'
|
492
|
-
@logs << { warn: "Detected configuration for 'puppetfile'. This setting is not "\
|
493
|
-
"used when 'modules' is configured. Use 'module-install' instead. "\
|
494
|
-
"To automatically update your project configuration, run '#{command}'." }
|
495
|
-
elsif @project.modules.nil? && puppetfile_config.empty? && module_install.any?
|
496
|
-
@logs << { warn: "Detected configuration for 'module-install'. This setting is not "\
|
497
|
-
"used when 'modules' is not configured. Use 'puppetfile' instead." }
|
498
|
-
elsif @project.modules && puppetfile_config.any? && module_install.any?
|
499
|
-
@logs << { warn: "Detected configuration for 'puppetfile' and 'module-install'. Using "\
|
500
|
-
"configuration for 'module-install' because 'modules' is also configured." }
|
501
|
-
elsif @project.modules.nil? && puppetfile_config.any? && module_install.any?
|
502
|
-
@logs << { warn: "Detected configuration for 'puppetfile' and 'module-install'. Using "\
|
503
|
-
"configuration for 'puppetfile' because 'modules' is not configured." }
|
504
|
-
end
|
505
356
|
end
|
506
357
|
|
507
358
|
def default_inventoryfile
|
@@ -517,21 +368,15 @@ module Bolt
|
|
517
368
|
end
|
518
369
|
|
519
370
|
def puppetfile
|
520
|
-
@
|
371
|
+
@project.puppetfile
|
521
372
|
end
|
522
373
|
|
523
374
|
def modulepath
|
524
|
-
|
525
|
-
|
526
|
-
if @project.modules
|
527
|
-
path + [@project.managed_moduledir.to_s]
|
528
|
-
else
|
529
|
-
path
|
530
|
-
end
|
375
|
+
(@data['modulepath'] || @project.modulepath) + [@project.managed_moduledir.to_s]
|
531
376
|
end
|
532
377
|
|
533
378
|
def modulepath=(value)
|
534
|
-
@data['modulepath'] = value
|
379
|
+
@data['modulepath'] = Array(value)
|
535
380
|
end
|
536
381
|
|
537
382
|
def plugin_cache
|
@@ -582,27 +427,12 @@ module Bolt
|
|
582
427
|
@data['compile-concurrency']
|
583
428
|
end
|
584
429
|
|
585
|
-
def puppetfile_config
|
586
|
-
@data['puppetfile']
|
587
|
-
end
|
588
|
-
|
589
430
|
def plugins
|
590
431
|
@data['plugins']
|
591
432
|
end
|
592
433
|
|
593
434
|
def plugin_hooks
|
594
|
-
|
595
|
-
Bolt::Logger.warn_once(
|
596
|
-
"plugin-hooks and plugin_hooks set",
|
597
|
-
"Detected configuration for 'plugin-hooks' and 'plugin_hooks'. Bolt will ignore 'plugin_hooks'."
|
598
|
-
)
|
599
|
-
|
600
|
-
@data['plugin-hooks']
|
601
|
-
elsif @data['plugin-hooks'].any?
|
602
|
-
@data['plugin-hooks']
|
603
|
-
else
|
604
|
-
@data['plugin_hooks']
|
605
|
-
end
|
435
|
+
@data['plugin-hooks']
|
606
436
|
end
|
607
437
|
|
608
438
|
def trusted_external
|
@@ -610,18 +440,7 @@ module Bolt
|
|
610
440
|
end
|
611
441
|
|
612
442
|
def apply_settings
|
613
|
-
|
614
|
-
Bolt::Logger.warn_once(
|
615
|
-
"apply-settings and apply_settings set",
|
616
|
-
"Detected configuration for 'apply-settings' and 'apply_settings'. Bolt will ignore 'apply_settings'."
|
617
|
-
)
|
618
|
-
|
619
|
-
@data['apply-settings']
|
620
|
-
elsif @data['apply-settings'].any?
|
621
|
-
@data['apply-settings']
|
622
|
-
else
|
623
|
-
@data['apply_settings']
|
624
|
-
end
|
443
|
+
@data['apply-settings']
|
625
444
|
end
|
626
445
|
|
627
446
|
def transport
|
@@ -632,6 +451,10 @@ module Bolt
|
|
632
451
|
@project.module_install || @data['module-install']
|
633
452
|
end
|
634
453
|
|
454
|
+
def disable_warnings
|
455
|
+
Set.new(@project.disable_warnings + @data['disable-warnings'])
|
456
|
+
end
|
457
|
+
|
635
458
|
# Check if there is a case-insensitive match to the path
|
636
459
|
def check_path_case(type, paths)
|
637
460
|
return if paths.nil?
|
@@ -640,7 +463,7 @@ module Bolt
|
|
640
463
|
if matches.any?
|
641
464
|
msg = "WARNING: Bolt is case sensitive when specifying a #{type}. Did you mean:\n"
|
642
465
|
matches.each { |path| msg += " #{path}\n" }
|
643
|
-
|
466
|
+
Bolt::Logger.warn("path_case", msg)
|
644
467
|
end
|
645
468
|
end
|
646
469
|
|