bolt 2.42.0 → 3.3.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.

Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/Puppetfile +21 -19
  3. data/bolt-modules/boltlib/lib/puppet/functions/add_facts.rb +1 -1
  4. data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +25 -0
  5. data/bolt-modules/boltlib/lib/puppet/functions/parallelize.rb +6 -8
  6. data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +2 -2
  7. data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +27 -5
  8. data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +1 -1
  9. data/bolt-modules/boltlib/lib/puppet/functions/wait_until_available.rb +7 -3
  10. data/bolt-modules/file/lib/puppet/functions/file/read.rb +3 -2
  11. data/lib/bolt/analytics.rb +3 -2
  12. data/lib/bolt/applicator.rb +11 -1
  13. data/lib/bolt/apply_result.rb +1 -1
  14. data/lib/bolt/bolt_option_parser.rb +9 -116
  15. data/lib/bolt/catalog.rb +10 -29
  16. data/lib/bolt/cli.rb +90 -154
  17. data/lib/bolt/config.rb +66 -239
  18. data/lib/bolt/config/options.rb +79 -102
  19. data/lib/bolt/config/transport/local.rb +1 -0
  20. data/lib/bolt/config/transport/lxd.rb +21 -0
  21. data/lib/bolt/config/transport/options.rb +9 -2
  22. data/lib/bolt/config/transport/orch.rb +1 -0
  23. data/lib/bolt/executor.rb +23 -6
  24. data/lib/bolt/inventory.rb +1 -1
  25. data/lib/bolt/inventory/group.rb +7 -4
  26. data/lib/bolt/logger.rb +123 -11
  27. data/lib/bolt/module_installer.rb +6 -4
  28. data/lib/bolt/module_installer/puppetfile.rb +2 -2
  29. data/lib/bolt/module_installer/resolver.rb +59 -14
  30. data/lib/bolt/module_installer/specs/forge_spec.rb +10 -4
  31. data/lib/bolt/module_installer/specs/git_spec.rb +19 -4
  32. data/lib/bolt/outputter/human.rb +56 -17
  33. data/lib/bolt/outputter/json.rb +16 -16
  34. data/lib/bolt/outputter/rainbow.rb +3 -3
  35. data/lib/bolt/pal.rb +95 -15
  36. data/lib/bolt/pal/yaml_plan.rb +9 -4
  37. data/lib/bolt/pal/yaml_plan/evaluator.rb +5 -153
  38. data/lib/bolt/pal/yaml_plan/step.rb +91 -52
  39. data/lib/bolt/pal/yaml_plan/step/command.rb +16 -16
  40. data/lib/bolt/pal/yaml_plan/step/download.rb +15 -16
  41. data/lib/bolt/pal/yaml_plan/step/eval.rb +11 -11
  42. data/lib/bolt/pal/yaml_plan/step/message.rb +13 -4
  43. data/lib/bolt/pal/yaml_plan/step/plan.rb +19 -15
  44. data/lib/bolt/pal/yaml_plan/step/resources.rb +82 -21
  45. data/lib/bolt/pal/yaml_plan/step/script.rb +32 -17
  46. data/lib/bolt/pal/yaml_plan/step/task.rb +19 -16
  47. data/lib/bolt/pal/yaml_plan/step/upload.rb +16 -17
  48. data/lib/bolt/pal/yaml_plan/transpiler.rb +2 -1
  49. data/lib/bolt/plan_creator.rb +1 -1
  50. data/lib/bolt/plugin.rb +2 -2
  51. data/lib/bolt/plugin/cache.rb +7 -7
  52. data/lib/bolt/plugin/module.rb +0 -23
  53. data/lib/bolt/plugin/puppet_connect_data.rb +77 -0
  54. data/lib/bolt/plugin/puppetdb.rb +1 -1
  55. data/lib/bolt/project.rb +54 -81
  56. data/lib/bolt/project_manager.rb +5 -4
  57. data/lib/bolt/project_manager/module_migrator.rb +7 -6
  58. data/lib/bolt/rerun.rb +1 -1
  59. data/lib/bolt/result.rb +6 -1
  60. data/lib/bolt/shell.rb +16 -0
  61. data/lib/bolt/shell/bash.rb +57 -25
  62. data/lib/bolt/shell/bash/tmpdir.rb +6 -3
  63. data/lib/bolt/shell/powershell.rb +33 -10
  64. data/lib/bolt/shell/powershell/snippets.rb +37 -150
  65. data/lib/bolt/task.rb +2 -2
  66. data/lib/bolt/transport/base.rb +0 -9
  67. data/lib/bolt/transport/docker.rb +1 -125
  68. data/lib/bolt/transport/docker/connection.rb +86 -161
  69. data/lib/bolt/transport/local.rb +1 -9
  70. data/lib/bolt/transport/lxd.rb +26 -0
  71. data/lib/bolt/transport/lxd/connection.rb +99 -0
  72. data/lib/bolt/transport/orch/connection.rb +1 -1
  73. data/lib/bolt/transport/ssh.rb +1 -2
  74. data/lib/bolt/transport/ssh/connection.rb +2 -2
  75. data/lib/bolt/transport/winrm/connection.rb +1 -1
  76. data/lib/bolt/validator.rb +2 -2
  77. data/lib/bolt/version.rb +1 -1
  78. data/lib/bolt_server/config.rb +1 -1
  79. data/lib/bolt_server/transport_app.rb +61 -32
  80. data/lib/bolt_spec/bolt_context.rb +9 -4
  81. data/lib/bolt_spec/plans.rb +1 -109
  82. data/lib/bolt_spec/plans/action_stubs.rb +1 -1
  83. data/lib/bolt_spec/plans/mock_executor.rb +4 -0
  84. data/libexec/bolt_catalog +1 -1
  85. data/modules/aggregate/plans/count.pp +21 -0
  86. data/modules/aggregate/plans/targets.pp +21 -0
  87. data/modules/puppet_connect/plans/test_input_data.pp +67 -0
  88. data/modules/puppetdb_fact/plans/init.pp +10 -0
  89. metadata +13 -9
  90. data/modules/aggregate/plans/nodes.pp +0 -36
data/lib/bolt/catalog.rb CHANGED
@@ -76,31 +76,27 @@ module Bolt
76
76
  # is the only way to log a message that will make it back to Bolt
77
77
  # to be printed.
78
78
  target = request['target']
79
- plan_vars = shadow_vars('plan', request['plan_vars'], target['facts'])
80
- target_vars = shadow_vars('target', target['variables'], target['facts'])
81
79
 
82
- # Merge plan vars with target vars, while maintaining the order of the plan
83
- # vars. It's critical that the order of plan vars is not changed, as Puppet
84
- # will deserialize the variables in the order they appear. Variables may
85
- # contain local references to variables that appear earlier in a plan. If
86
- # these variables are moved before the variable they reference, Puppet will
87
- # be unable to deserialize the data and raise an error.
88
- topscope_vars = target_vars.reject { |k, _v| plan_vars.key?(k) }.merge(plan_vars)
80
+ variables = {
81
+ variables: request['plan_vars'],
82
+ target_variables: target['variables']
83
+ }
89
84
 
90
- env_conf = { modulepath: request['modulepath'],
91
- facts: target['facts'],
92
- variables: topscope_vars }
85
+ env_conf = {
86
+ modulepath: request['modulepath'],
87
+ facts: target['facts']
88
+ }
93
89
 
94
90
  puppet_settings = {
95
91
  node_name_value: target['name'],
96
- hiera_config: request['hiera_config']
92
+ hiera_config: request['hiera_config']
97
93
  }
98
94
 
99
95
  with_puppet_settings(puppet_settings) do
100
96
  Puppet::Pal.in_tmp_environment('bolt_catalog', **env_conf) do |pal|
101
97
  Puppet.override(puppet_overrides) do
102
98
  Puppet.lookup(:pal_current_node).trusted_data = target['trusted']
103
- pal.with_catalog_compiler do |compiler|
99
+ pal.with_catalog_compiler(**variables) do |compiler|
104
100
  options = request['puppet_config'] || {}
105
101
  # Configure language strictness in the CatalogCompiler. We want Bolt to be able
106
102
  # to compile most Puppet 4+ manifests, so we default to allowing deprecated functions.
@@ -119,21 +115,6 @@ module Bolt
119
115
  end
120
116
  end
121
117
 
122
- # Warn and remove variables that will be shadowed by facts of the same
123
- # name, which are set in scope earlier.
124
- def shadow_vars(type, vars, facts)
125
- collisions, valid = vars.partition do |k, _|
126
- facts.include?(k)
127
- end
128
- if collisions.any?
129
- names = collisions.map { |k, _| "$#{k}" }.join(', ')
130
- plural = collisions.length == 1 ? '' : 's'
131
- Puppet.warning("#{type.capitalize} variable#{plural} #{names} will be overridden by fact#{plural} " \
132
- "of the same name in the apply block")
133
- end
134
- valid.to_h
135
- end
136
-
137
118
  def build_program(code)
138
119
  ast = Puppet::Pops::Serialization::FromDataConverter.convert(code)
139
120
 
data/lib/bolt/cli.rb CHANGED
@@ -33,19 +33,18 @@ module Bolt
33
33
 
34
34
  class CLI
35
35
  COMMANDS = {
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
- 'puppetfile' => %w[install show-modules generate-types],
42
- 'secret' => %w[encrypt decrypt createkeys],
43
- 'inventory' => %w[show],
44
- 'group' => %w[show],
45
- 'project' => %w[init migrate],
46
- 'module' => %w[add generate-types install show],
47
- 'apply' => %w[],
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
- @config = if ENV['BOLT_PROJECT']
163
- project = Bolt::Project.create_project(ENV['BOLT_PROJECT'], 'environment')
164
- Bolt::Config.from_project(project, options)
165
- elsif options[:configfile]
166
- Bolt::Config.from_file(options[:configfile], options)
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
- cli_flag = options[:project] || options[:boltdir]
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,17 @@ 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)
178
+ Bolt::Logger.stream = config.stream
189
179
  Bolt::Logger.analytics = analytics
180
+ Bolt::Logger.flush_queue
190
181
 
191
182
  # Logger must be configured before checking path case and project file, otherwise logs will not display
192
183
  config.check_path_case('modulepath', config.modulepath)
193
184
  config.project.check_deprecated_file
194
185
 
195
- # Log messages created during parser and config initialization
196
- config.logs.each { |log| @logger.send(log.keys[0], log.values[0]) }
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)
186
+ if options[:clear_cache] && File.exist?(config.project.plugin_cache_file)
187
+ FileUtils.rm(config.project.plugin_cache_file)
202
188
  end
203
189
 
204
190
  warn_inventory_overrides_cli(options)
@@ -218,9 +204,8 @@ module Bolt
218
204
 
219
205
  return unless !stdout.empty? && stdout.to_i < 3
220
206
 
221
- msg = "Detected PowerShell 2 on controller. PowerShell 2 is deprecated and "\
222
- "support will be removed in Bolt 3.0."
223
- Bolt::Logger.deprecation_warning("PowerShell 2 controller", msg)
207
+ msg = "Detected PowerShell 2 on controller. PowerShell 2 is unsupported."
208
+ Bolt::Logger.deprecation_warning("powershell_2_controller", msg)
224
209
  end
225
210
  end
226
211
 
@@ -228,7 +213,7 @@ module Bolt
228
213
  target_opts = options.keys.select { |opt| %i[query rerun targets].include?(opt) }
229
214
  target_string = "'--targets', '--rerun', or '--query'"
230
215
  if target_opts.length > 1
231
- raise Bolt::CLIError, "Only one targeting option #{target_string} may be specified"
216
+ raise Bolt::CLIError, "Only one targeting option #{target_string} can be specified"
232
217
  elsif target_opts.empty? && options[:subcommand] != 'plan'
233
218
  raise Bolt::CLIError, "Command requires a targeting option: #{target_string}"
234
219
  end
@@ -265,11 +250,14 @@ module Bolt
265
250
  end
266
251
  end
267
252
 
268
- if %w[task plan].include?(options[:subcommand]) && options[:action] == 'run'
253
+ if %w[task plan script].include?(options[:subcommand]) && options[:action] == 'run'
269
254
  if options[:object].nil?
270
255
  raise Bolt::CLIError, "Must specify a #{options[:subcommand]} to run"
271
256
  end
272
- # This may mean that we parsed a parameter as the object
257
+ end
258
+
259
+ # This may mean that we parsed a parameter as the object
260
+ if %w[task plan].include?(options[:subcommand]) && options[:action] == 'run'
273
261
  unless options[:object] =~ /\A([a-z][a-z0-9_]*)?(::[a-z][a-z0-9_]*)*\Z/
274
262
  raise Bolt::CLIError,
275
263
  "Invalid #{options[:subcommand]} '#{options[:object]}'"
@@ -314,26 +302,18 @@ module Bolt
314
302
  "Unknown argument(s) #{options[:leftovers].join(', ')}"
315
303
  end
316
304
 
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
305
  if options[:noop] &&
322
306
  !(options[:subcommand] == 'task' && options[:action] == 'run') && options[:subcommand] != 'apply'
323
307
  raise Bolt::CLIError,
324
- "Option '--noop' may only be specified when running a task or applying manifest code"
308
+ "Option '--noop' can only be specified when running a task or applying manifest code"
325
309
  end
326
310
 
327
311
  if options[:env_vars]
328
312
  unless %w[command script].include?(options[:subcommand]) && options[:action] == 'run'
329
313
  raise Bolt::CLIError,
330
- "Option '--env-var' may only be specified when running a command or script"
314
+ "Option '--env-var' can only be specified when running a command or script"
331
315
  end
332
316
  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
317
  end
338
318
 
339
319
  def handle_parser_errors
@@ -376,7 +356,10 @@ module Bolt
376
356
  conflicting_options = Set.new(opts.keys.map(&:to_s)).intersection(inventory_cli_opts)
377
357
 
378
358
  if inventory_source && conflicting_options.any?
379
- @logger.warn("CLI arguments #{conflicting_options.to_a} may be overridden by Inventory: #{inventory_source}")
359
+ Bolt::Logger.warn(
360
+ "cli_overrides",
361
+ "CLI arguments #{conflicting_options.to_a} might be overridden by Inventory: #{inventory_source}"
362
+ )
380
363
  end
381
364
  end
382
365
 
@@ -393,7 +376,7 @@ module Bolt
393
376
  # Initialize inventory and targets. Errors here are better to catch early.
394
377
  # options[:target_args] will contain a string/array version of the targetting options this is passed to plans
395
378
  # options[:targets] will contain a resolved set of Target objects
396
- unless %w[guide module project puppetfile secret].include?(options[:subcommand]) ||
379
+ unless %w[guide module project secret].include?(options[:subcommand]) ||
397
380
  %w[convert new show].include?(options[:action])
398
381
  update_targets(options)
399
382
  end
@@ -448,15 +431,12 @@ module Bolt
448
431
  list_modules
449
432
  end
450
433
  return 0
451
- when 'show-modules'
452
- list_modules
453
- return 0
454
434
  when 'convert'
455
435
  pal.convert_plan(options[:object])
456
436
  return 0
457
437
  end
458
438
 
459
- message = 'There may be processes left executing on some nodes.'
439
+ message = 'There might be processes left executing on some nodes.'
460
440
 
461
441
  if %w[task plan].include?(options[:subcommand]) && options[:task_options] && !options[:params_parsed] && pal
462
442
  options[:task_options] = pal.parse_params(options[:subcommand], options[:object], options[:task_options])
@@ -500,17 +480,6 @@ module Bolt
500
480
  when 'generate-types'
501
481
  code = generate_types
502
482
  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
483
  when 'secret'
515
484
  code = Bolt::Secret.execute(plugins, outputter, options)
516
485
  when 'apply'
@@ -528,7 +497,6 @@ module Bolt
528
497
 
529
498
  elapsed_time = Benchmark.realtime do
530
499
  executor_opts = {}
531
- executor_opts[:description] = options[:description] if options.key?(:description)
532
500
  executor_opts[:env_vars] = options[:env_vars] if options.key?(:env_vars)
533
501
  executor.subscribe(outputter)
534
502
  executor.subscribe(log_outputter)
@@ -537,19 +505,14 @@ module Bolt
537
505
  when 'command'
538
506
  executor.run_command(targets, options[:object], executor_opts)
539
507
  when 'script'
540
- script = options[:object]
541
- validate_file('script', script)
542
- executor.run_script(targets, script, options[:leftovers], executor_opts)
508
+ script_path = find_file(options[:object])
509
+ executor.run_script(targets, script_path, options[:leftovers], executor_opts)
543
510
  when 'task'
544
- r = outputter.spin do
545
- pal.run_task(options[:object],
546
- targets,
547
- options[:task_options],
548
- executor,
549
- inventory,
550
- options[:description])
551
- end
552
- r
511
+ pal.run_task(options[:object],
512
+ targets,
513
+ options[:task_options],
514
+ executor,
515
+ inventory)
553
516
  when 'file'
554
517
  src = options[:object]
555
518
  dest = options[:leftovers].first
@@ -610,7 +573,7 @@ module Bolt
610
573
  end
611
574
 
612
575
  def list_plans
613
- plans = filter_content(pal.list_plans(filter_content: true), options[:filter])
576
+ plans = filter_content(pal.list_plans_with_cache(filter_content: true), options[:filter])
614
577
  outputter.print_plans(plans, pal.user_modulepath)
615
578
  end
616
579
 
@@ -650,7 +613,7 @@ module Bolt
650
613
  if plan_arguments['nodes'] || plan_arguments['targets']
651
614
  key = plan_arguments.include?('nodes') ? 'nodes' : 'targets'
652
615
  raise Bolt::CLIError,
653
- "A plan's '#{key}' parameter may be specified using the --#{key} option, but in that " \
616
+ "A plan's '#{key}' parameter can be specified using the --#{key} option, but in that " \
654
617
  "case it must not be specified as a separate #{key}=<value> parameter nor included " \
655
618
  "in the JSON data passed in the --params option"
656
619
  end
@@ -662,7 +625,7 @@ module Bolt
662
625
  if node_param && target_param
663
626
  msg = "Plan parameters include both 'nodes' and 'targets' with type 'TargetSpec', " \
664
627
  "neither will populated with the value for --nodes or --targets."
665
- @logger.warn(msg)
628
+ Bolt::Logger.warn("nodes_targets_parameters", msg)
666
629
  elsif node_param
667
630
  plan_arguments['nodes'] = nodes.join(',')
668
631
  elsif target_param
@@ -672,7 +635,6 @@ module Bolt
672
635
 
673
636
  plan_context = { plan_name: plan_name,
674
637
  params: plan_arguments }
675
- plan_context[:description] = options[:description] if options[:description]
676
638
 
677
639
  executor = Bolt::Executor.new(config.concurrency, analytics, options[:noop], config.modified_concurrency)
678
640
  if %w[human rainbow].include?(options.fetch(:format, 'human'))
@@ -684,9 +646,7 @@ module Bolt
684
646
 
685
647
  executor.subscribe(log_outputter)
686
648
  executor.start_plan(plan_context)
687
- result = outputter.spin do
688
- pal.run_plan(plan_name, plan_arguments, executor, inventory, puppetdb_client)
689
- end
649
+ result = pal.run_plan(plan_name, plan_arguments, executor, inventory, puppetdb_client)
690
650
 
691
651
  # If a non-bolt exception bubbles up the plan won't get finished
692
652
  executor.finish_plan(result)
@@ -709,7 +669,7 @@ module Bolt
709
669
  "about defining and declaring classes and types in the Puppet documentation at "\
710
670
  "https://puppet.com/docs/puppet/latest/lang_classes.html and "\
711
671
  "https://puppet.com/docs/puppet/latest/lang_defined_types.html"
712
- @logger.warn(message)
672
+ Bolt::Logger.warn("empty_manifest", message)
713
673
  end
714
674
 
715
675
  executor = Bolt::Executor.new(config.concurrency, analytics, noop, config.modified_concurrency)
@@ -738,14 +698,12 @@ module Bolt
738
698
  end
739
699
 
740
700
  def list_modules
741
- assert_puppetfile_or_module_command(config.project.modules)
742
701
  outputter.print_module_list(pal.list_modules)
743
702
  end
744
703
 
745
704
  def generate_types
746
- assert_puppetfile_or_module_command(config.project.modules)
747
705
  # generate_types will surface a nice error with helpful message if it fails
748
- pal.generate_types
706
+ pal.generate_types(cache: true)
749
707
  0
750
708
  end
751
709
 
@@ -753,19 +711,19 @@ module Bolt
753
711
  #
754
712
  def install_project_modules(project, config, force, resolve)
755
713
  assert_project_file(project)
756
- assert_puppetfile_or_module_command(project.modules)
757
714
 
758
- unless project.modules
759
- outputter.print_message "Project configuration file #{project.project_file} does not "\
760
- "specify any module dependencies. Nothing to do."
715
+ if project.modules.empty? && resolve != false
716
+ outputter.print_message(
717
+ "Project configuration file #{project.project_file} does not "\
718
+ "specify any module dependencies. Nothing to do."
719
+ )
761
720
  return 0
762
721
  end
763
722
 
764
- modules = project.modules || []
765
723
  installer = Bolt::ModuleInstaller.new(outputter, pal)
766
724
 
767
725
  ok = outputter.spin do
768
- installer.install(modules,
726
+ installer.install(project.modules,
769
727
  project.puppetfile,
770
728
  project.managed_moduledir,
771
729
  config,
@@ -780,14 +738,12 @@ module Bolt
780
738
  #
781
739
  def add_project_module(name, project, config)
782
740
  assert_project_file(project)
783
- assert_puppetfile_or_module_command(project.modules)
784
741
 
785
- modules = project.modules || []
786
742
  installer = Bolt::ModuleInstaller.new(outputter, pal)
787
743
 
788
744
  ok = outputter.spin do
789
745
  installer.add(name,
790
- modules,
746
+ project.modules,
791
747
  project.puppetfile,
792
748
  project.managed_moduledir,
793
749
  project.project_file,
@@ -818,8 +774,6 @@ module Bolt
818
774
  # Loads a Puppetfile and installs its modules.
819
775
  #
820
776
  def install_puppetfile(puppetfile_config, puppetfile, moduledir)
821
- assert_puppetfile_or_module_command(config.project.modules)
822
-
823
777
  outputter.print_message("Installing modules from Puppetfile")
824
778
  installer = Bolt::ModuleInstaller.new(outputter, pal)
825
779
  ok = outputter.spin do
@@ -829,47 +783,6 @@ module Bolt
829
783
  ok ? 0 : 1
830
784
  end
831
785
 
832
- # Raises an error if the 'puppetfile install' command is deprecated due to
833
- # modules being configured.
834
- #
835
- def assert_puppetfile_or_module_command(modules)
836
- if Bolt::Util.powershell?
837
- case options[:action]
838
- when 'generate-types'
839
- old_command = 'Register-BoltPuppetfileTypes'
840
- new_command = 'Register-BoltModuleTypes'
841
- when 'install'
842
- old_command = 'Install-BoltPuppetfile'
843
- new_command = 'Install-BoltModule'
844
- when 'show', 'show-modules'
845
- old_command = 'Get-BoltPuppetfileModules'
846
- new_command = 'Get-BoltModule'
847
- end
848
- else
849
- old_command = "bolt puppetfile #{options[:action]}"
850
- new_command = if options[:action] == 'show-modules'
851
- 'bolt module show'
852
- else
853
- "bolt module #{options[:action]}"
854
- end
855
- end
856
-
857
- if modules && options[:subcommand] == 'puppetfile'
858
- raise Bolt::CLIError,
859
- "Unable to use command '#{old_command}' when 'modules' is configured in "\
860
- "bolt-project.yaml. Use '#{new_command}' instead."
861
- elsif modules.nil? && options[:subcommand] == 'puppetfile'
862
- msg = "Command '#{old_command}' is deprecated and will be removed in Bolt 3.0. Update your project to use "\
863
- "the module management feature. For more information, see https://pup.pt/bolt-module-migrate."
864
- Bolt::Logger.deprecation_warning('puppetfile command', msg)
865
- elsif modules.nil? && options[:subcommand] == 'module'
866
- msg = "Unable to use command '#{new_command}' when 'modules' is not configured in "\
867
- "bolt-project.yaml. "
868
- msg += "Use '#{old_command}' instead." if options[:action] != 'add'
869
- raise Bolt::CLIError, msg
870
- end
871
- end
872
-
873
786
  def pal
874
787
  @pal ||= Bolt::PAL.new(Bolt::Config::Modulepath.new(config.modulepath),
875
788
  config.hiera_config,
@@ -930,6 +843,28 @@ module Bolt
930
843
  Bolt::Util.validate_file(type, path, allow_dir)
931
844
  end
932
845
 
846
+ # Returns the path to a file. If the path is an absolute or relative to
847
+ # a file, and the file exists, returns the path as-is. Otherwise, checks if
848
+ # the path is a Puppet file path and looks for the file in a module's files
849
+ # directory.
850
+ #
851
+ def find_file(path)
852
+ unless File.exist?(path) || Pathname.new(path).absolute?
853
+ modulepath = Bolt::Config::Modulepath.new(config.modulepath)
854
+ modules = Bolt::Module.discover(modulepath.full_modulepath, config.project)
855
+ mod, file = path.split(File::SEPARATOR, 2)
856
+
857
+ if modules[mod]
858
+ @logger.debug("Did not find file at #{File.expand_path(path)}, checking in module '#{mod}'")
859
+ path = File.join(modules[mod].path, 'files', file)
860
+ end
861
+ end
862
+
863
+ Bolt::Util.validate_file('script', path)
864
+
865
+ path
866
+ end
867
+
933
868
  def rerun
934
869
  @rerun ||= Bolt::Rerun.new(config.rerunfile, config.save_rerun)
935
870
  end
@@ -958,7 +893,7 @@ module Bolt
958
893
  # If the bundled content directory is empty, Bolt is likely installed as a gem.
959
894
  if ENV['BOLT_GEM'].nil? && incomplete_install?
960
895
  msg = <<~MSG.chomp
961
- Bolt may be installed as a gem. To use Bolt reliably and with all of its
896
+ Bolt might be installed as a gem. To use Bolt reliably and with all of its
962
897
  dependencies, uninstall the 'bolt' gem and install Bolt as a package:
963
898
  https://puppet.com/docs/bolt/latest/bolt_installing.html
964
899
 
@@ -966,7 +901,7 @@ module Bolt
966
901
  set the BOLT_GEM environment variable.
967
902
  MSG
968
903
 
969
- @logger.warn(msg)
904
+ Bolt::Logger.warn("gem_install", msg)
970
905
  end
971
906
 
972
907
  # We only need to enumerate bundled content when running a task or plan
@@ -989,7 +924,8 @@ module Bolt
989
924
  # Gem installs include the aggregate, canary, and puppetdb_fact modules, while
990
925
  # package installs include modules listed in the Bolt repo Puppetfile
991
926
  def incomplete_install?
992
- (Dir.children(Bolt::Config::Modulepath::MODULES_PATH) - %w[aggregate canary puppetdb_fact secure_env_vars]).empty?
927
+ builtin_module_list = %w[aggregate canary puppetdb_fact secure_env_vars puppet_connect]
928
+ (Dir.children(Bolt::Config::Modulepath::MODULES_PATH) - builtin_module_list).empty?
993
929
  end
994
930
 
995
931
  # Mimicks the output from Outputter::Human#fatal_error. This should be used to print