bolt 2.40.1 → 3.0.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.
- checksums.yaml +4 -4
- data/Puppetfile +17 -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 +58 -157
- 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 +93 -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/shell/bash.rb +1 -1
- data/lib/bolt/shell/bash/tmpdir.rb +4 -1
- data/lib/bolt/shell/powershell.rb +3 -4
- data/lib/bolt/shell/powershell/snippets.rb +9 -149
- data/lib/bolt/task.rb +1 -1
- data/lib/bolt/transport/docker/connection.rb +2 -2
- 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/schemas/partials/task.json +1 -1
- data/lib/bolt_server/transport_app.rb +3 -2
- 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 +31 -0
- data/modules/puppetdb_fact/plans/init.pp +10 -0
- metadata +27 -18
- 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)
|
@@ -212,12 +197,14 @@ module Bolt
|
|
212
197
|
|
213
198
|
private def validate_ps_version
|
214
199
|
if Bolt::Util.powershell?
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
200
|
+
command = "powershell.exe -NoProfile -NonInteractive -NoLogo -ExecutionPolicy "\
|
201
|
+
"Bypass -Command $PSVersionTable.PSVersion.Major"
|
202
|
+
stdout, _stderr, _status = Open3.capture3(command)
|
203
|
+
|
204
|
+
return unless !stdout.empty? && stdout.to_i < 3
|
205
|
+
|
206
|
+
msg = "Detected PowerShell 2 on controller. PowerShell 2 is unsupported."
|
207
|
+
Bolt::Logger.deprecation_warning("powershell_2_controller", msg)
|
221
208
|
end
|
222
209
|
end
|
223
210
|
|
@@ -311,10 +298,6 @@ module Bolt
|
|
311
298
|
"Unknown argument(s) #{options[:leftovers].join(', ')}"
|
312
299
|
end
|
313
300
|
|
314
|
-
if options.slice(:boltdir, :configfile, :project).length > 1
|
315
|
-
raise Bolt::CLIError, "Only one of '--boltdir', '--project', or '--configfile' may be specified"
|
316
|
-
end
|
317
|
-
|
318
301
|
if options[:noop] &&
|
319
302
|
!(options[:subcommand] == 'task' && options[:action] == 'run') && options[:subcommand] != 'apply'
|
320
303
|
raise Bolt::CLIError,
|
@@ -327,10 +310,6 @@ module Bolt
|
|
327
310
|
"Option '--env-var' may only be specified when running a command or script"
|
328
311
|
end
|
329
312
|
end
|
330
|
-
|
331
|
-
if options.key?(:debug) && options.key?(:log)
|
332
|
-
raise Bolt::CLIError, "Only one of '--debug' or '--log-level' may be specified"
|
333
|
-
end
|
334
313
|
end
|
335
314
|
|
336
315
|
def handle_parser_errors
|
@@ -373,7 +352,10 @@ module Bolt
|
|
373
352
|
conflicting_options = Set.new(opts.keys.map(&:to_s)).intersection(inventory_cli_opts)
|
374
353
|
|
375
354
|
if inventory_source && conflicting_options.any?
|
376
|
-
|
355
|
+
Bolt::Logger.warn(
|
356
|
+
"cli_overrides",
|
357
|
+
"CLI arguments #{conflicting_options.to_a} may be overridden by Inventory: #{inventory_source}"
|
358
|
+
)
|
377
359
|
end
|
378
360
|
end
|
379
361
|
|
@@ -390,7 +372,7 @@ module Bolt
|
|
390
372
|
# Initialize inventory and targets. Errors here are better to catch early.
|
391
373
|
# options[:target_args] will contain a string/array version of the targetting options this is passed to plans
|
392
374
|
# options[:targets] will contain a resolved set of Target objects
|
393
|
-
unless %w[guide module project
|
375
|
+
unless %w[guide module project secret].include?(options[:subcommand]) ||
|
394
376
|
%w[convert new show].include?(options[:action])
|
395
377
|
update_targets(options)
|
396
378
|
end
|
@@ -445,9 +427,6 @@ module Bolt
|
|
445
427
|
list_modules
|
446
428
|
end
|
447
429
|
return 0
|
448
|
-
when 'show-modules'
|
449
|
-
list_modules
|
450
|
-
return 0
|
451
430
|
when 'convert'
|
452
431
|
pal.convert_plan(options[:object])
|
453
432
|
return 0
|
@@ -497,17 +476,6 @@ module Bolt
|
|
497
476
|
when 'generate-types'
|
498
477
|
code = generate_types
|
499
478
|
end
|
500
|
-
when 'puppetfile'
|
501
|
-
case options[:action]
|
502
|
-
when 'generate-types'
|
503
|
-
code = generate_types
|
504
|
-
when 'install'
|
505
|
-
code = install_puppetfile(
|
506
|
-
config.puppetfile_config,
|
507
|
-
config.puppetfile,
|
508
|
-
config.modulepath.first
|
509
|
-
)
|
510
|
-
end
|
511
479
|
when 'secret'
|
512
480
|
code = Bolt::Secret.execute(plugins, outputter, options)
|
513
481
|
when 'apply'
|
@@ -525,7 +493,6 @@ module Bolt
|
|
525
493
|
|
526
494
|
elapsed_time = Benchmark.realtime do
|
527
495
|
executor_opts = {}
|
528
|
-
executor_opts[:description] = options[:description] if options.key?(:description)
|
529
496
|
executor_opts[:env_vars] = options[:env_vars] if options.key?(:env_vars)
|
530
497
|
executor.subscribe(outputter)
|
531
498
|
executor.subscribe(log_outputter)
|
@@ -538,15 +505,11 @@ module Bolt
|
|
538
505
|
validate_file('script', script)
|
539
506
|
executor.run_script(targets, script, options[:leftovers], executor_opts)
|
540
507
|
when 'task'
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
inventory,
|
547
|
-
options[:description])
|
548
|
-
end
|
549
|
-
r
|
508
|
+
pal.run_task(options[:object],
|
509
|
+
targets,
|
510
|
+
options[:task_options],
|
511
|
+
executor,
|
512
|
+
inventory)
|
550
513
|
when 'file'
|
551
514
|
src = options[:object]
|
552
515
|
dest = options[:leftovers].first
|
@@ -607,7 +570,7 @@ module Bolt
|
|
607
570
|
end
|
608
571
|
|
609
572
|
def list_plans
|
610
|
-
plans = filter_content(pal.
|
573
|
+
plans = filter_content(pal.list_plans_with_cache(filter_content: true), options[:filter])
|
611
574
|
outputter.print_plans(plans, pal.user_modulepath)
|
612
575
|
end
|
613
576
|
|
@@ -659,7 +622,7 @@ module Bolt
|
|
659
622
|
if node_param && target_param
|
660
623
|
msg = "Plan parameters include both 'nodes' and 'targets' with type 'TargetSpec', " \
|
661
624
|
"neither will populated with the value for --nodes or --targets."
|
662
|
-
|
625
|
+
Bolt::Logger.warn("nodes_targets_parameters", msg)
|
663
626
|
elsif node_param
|
664
627
|
plan_arguments['nodes'] = nodes.join(',')
|
665
628
|
elsif target_param
|
@@ -669,7 +632,6 @@ module Bolt
|
|
669
632
|
|
670
633
|
plan_context = { plan_name: plan_name,
|
671
634
|
params: plan_arguments }
|
672
|
-
plan_context[:description] = options[:description] if options[:description]
|
673
635
|
|
674
636
|
executor = Bolt::Executor.new(config.concurrency, analytics, options[:noop], config.modified_concurrency)
|
675
637
|
if %w[human rainbow].include?(options.fetch(:format, 'human'))
|
@@ -681,9 +643,7 @@ module Bolt
|
|
681
643
|
|
682
644
|
executor.subscribe(log_outputter)
|
683
645
|
executor.start_plan(plan_context)
|
684
|
-
result =
|
685
|
-
pal.run_plan(plan_name, plan_arguments, executor, inventory, puppetdb_client)
|
686
|
-
end
|
646
|
+
result = pal.run_plan(plan_name, plan_arguments, executor, inventory, puppetdb_client)
|
687
647
|
|
688
648
|
# If a non-bolt exception bubbles up the plan won't get finished
|
689
649
|
executor.finish_plan(result)
|
@@ -706,7 +666,7 @@ module Bolt
|
|
706
666
|
"about defining and declaring classes and types in the Puppet documentation at "\
|
707
667
|
"https://puppet.com/docs/puppet/latest/lang_classes.html and "\
|
708
668
|
"https://puppet.com/docs/puppet/latest/lang_defined_types.html"
|
709
|
-
|
669
|
+
Bolt::Logger.warn("empty_manifest", message)
|
710
670
|
end
|
711
671
|
|
712
672
|
executor = Bolt::Executor.new(config.concurrency, analytics, noop, config.modified_concurrency)
|
@@ -735,14 +695,12 @@ module Bolt
|
|
735
695
|
end
|
736
696
|
|
737
697
|
def list_modules
|
738
|
-
assert_puppetfile_or_module_command(config.project.modules)
|
739
698
|
outputter.print_module_list(pal.list_modules)
|
740
699
|
end
|
741
700
|
|
742
701
|
def generate_types
|
743
|
-
assert_puppetfile_or_module_command(config.project.modules)
|
744
702
|
# generate_types will surface a nice error with helpful message if it fails
|
745
|
-
pal.generate_types
|
703
|
+
pal.generate_types(cache: true)
|
746
704
|
0
|
747
705
|
end
|
748
706
|
|
@@ -750,27 +708,19 @@ module Bolt
|
|
750
708
|
#
|
751
709
|
def install_project_modules(project, config, force, resolve)
|
752
710
|
assert_project_file(project)
|
753
|
-
assert_puppetfile_or_module_command(project.modules)
|
754
711
|
|
755
|
-
|
756
|
-
outputter.print_message
|
757
|
-
|
758
|
-
|
759
|
-
end
|
760
|
-
|
761
|
-
if resolve != false && config.any?
|
762
|
-
@logger.warn(
|
763
|
-
"Detected configuration for 'module-install'. This configuration is currently "\
|
764
|
-
"only supported when installing modules, not when resolving module dependencies. "\
|
765
|
-
"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."
|
766
716
|
)
|
717
|
+
return 0
|
767
718
|
end
|
768
719
|
|
769
|
-
modules = project.modules || []
|
770
720
|
installer = Bolt::ModuleInstaller.new(outputter, pal)
|
771
721
|
|
772
722
|
ok = outputter.spin do
|
773
|
-
installer.install(modules,
|
723
|
+
installer.install(project.modules,
|
774
724
|
project.puppetfile,
|
775
725
|
project.managed_moduledir,
|
776
726
|
config,
|
@@ -785,22 +735,12 @@ module Bolt
|
|
785
735
|
#
|
786
736
|
def add_project_module(name, project, config)
|
787
737
|
assert_project_file(project)
|
788
|
-
assert_puppetfile_or_module_command(project.modules)
|
789
|
-
|
790
|
-
if config.any?
|
791
|
-
@logger.warn(
|
792
|
-
"Detected configuration for 'module-install'. This configuration is currently "\
|
793
|
-
"only supported when installing modules, not when resolving module dependencies. "\
|
794
|
-
"For more information, see https://pup.pt/bolt-module-install"
|
795
|
-
)
|
796
|
-
end
|
797
738
|
|
798
|
-
modules = project.modules || []
|
799
739
|
installer = Bolt::ModuleInstaller.new(outputter, pal)
|
800
740
|
|
801
741
|
ok = outputter.spin do
|
802
742
|
installer.add(name,
|
803
|
-
modules,
|
743
|
+
project.modules,
|
804
744
|
project.puppetfile,
|
805
745
|
project.managed_moduledir,
|
806
746
|
project.project_file,
|
@@ -831,8 +771,6 @@ module Bolt
|
|
831
771
|
# Loads a Puppetfile and installs its modules.
|
832
772
|
#
|
833
773
|
def install_puppetfile(puppetfile_config, puppetfile, moduledir)
|
834
|
-
assert_puppetfile_or_module_command(config.project.modules)
|
835
|
-
|
836
774
|
outputter.print_message("Installing modules from Puppetfile")
|
837
775
|
installer = Bolt::ModuleInstaller.new(outputter, pal)
|
838
776
|
ok = outputter.spin do
|
@@ -842,43 +780,6 @@ module Bolt
|
|
842
780
|
ok ? 0 : 1
|
843
781
|
end
|
844
782
|
|
845
|
-
# Raises an error if the 'puppetfile install' command is deprecated due to
|
846
|
-
# modules being configured.
|
847
|
-
#
|
848
|
-
def assert_puppetfile_or_module_command(modules)
|
849
|
-
if Bolt::Util.powershell?
|
850
|
-
case options[:action]
|
851
|
-
when 'generate-types'
|
852
|
-
old_command = 'Register-BoltPuppetfileTypes'
|
853
|
-
new_command = 'Register-BoltModuleTypes'
|
854
|
-
when 'install'
|
855
|
-
old_command = 'Install-BoltPuppetfile'
|
856
|
-
new_command = 'Install-BoltModule'
|
857
|
-
when 'show', 'show-modules'
|
858
|
-
old_command = 'Get-BoltPuppetfileModules'
|
859
|
-
new_command = 'Get-BoltModule'
|
860
|
-
end
|
861
|
-
else
|
862
|
-
old_command = "bolt puppetfile #{options[:action]}"
|
863
|
-
new_command = if options[:action] == 'show-modules'
|
864
|
-
'bolt module show'
|
865
|
-
else
|
866
|
-
"bolt module #{options[:action]}"
|
867
|
-
end
|
868
|
-
end
|
869
|
-
|
870
|
-
if modules && options[:subcommand] == 'puppetfile'
|
871
|
-
raise Bolt::CLIError,
|
872
|
-
"Unable to use command '#{old_command}' when 'modules' is configured in "\
|
873
|
-
"bolt-project.yaml. Use '#{new_command}' instead."
|
874
|
-
elsif modules.nil? && options[:subcommand] == 'module'
|
875
|
-
msg = "Unable to use command '#{new_command}' when 'modules' is not configured in "\
|
876
|
-
"bolt-project.yaml. "
|
877
|
-
msg += "Use '#{old_command}' instead." if options[:action] != 'add'
|
878
|
-
raise Bolt::CLIError, msg
|
879
|
-
end
|
880
|
-
end
|
881
|
-
|
882
783
|
def pal
|
883
784
|
@pal ||= Bolt::PAL.new(Bolt::Config::Modulepath.new(config.modulepath),
|
884
785
|
config.hiera_config,
|
@@ -975,7 +876,7 @@ module Bolt
|
|
975
876
|
set the BOLT_GEM environment variable.
|
976
877
|
MSG
|
977
878
|
|
978
|
-
|
879
|
+
Bolt::Logger.warn("gem_install", msg)
|
979
880
|
end
|
980
881
|
|
981
882
|
# We only need to enumerate bundled content when running a task or plan
|
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
|
|