bolt 2.20.0 → 2.24.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 +3 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +6 -0
- data/bolt-modules/ctrl/lib/puppet/functions/ctrl/do_until.rb +12 -6
- data/bolt-modules/dir/lib/puppet/functions/dir/children.rb +35 -0
- data/bolt-modules/out/lib/puppet/functions/out/message.rb +1 -1
- data/exe/bolt +1 -0
- data/guides/inventory.txt +19 -0
- data/guides/project.txt +22 -0
- data/lib/bolt/analytics.rb +5 -5
- data/lib/bolt/applicator.rb +4 -3
- data/lib/bolt/bolt_option_parser.rb +75 -25
- data/lib/bolt/catalog.rb +9 -1
- data/lib/bolt/cli.rb +226 -73
- data/lib/bolt/config.rb +7 -0
- data/lib/bolt/config/options.rb +4 -4
- data/lib/bolt/executor.rb +16 -8
- data/lib/bolt/inventory/group.rb +3 -3
- data/lib/bolt/logger.rb +3 -4
- data/lib/bolt/module.rb +2 -1
- data/lib/bolt/outputter.rb +56 -0
- data/lib/bolt/outputter/human.rb +10 -9
- data/lib/bolt/outputter/json.rb +11 -4
- data/lib/bolt/outputter/logger.rb +2 -2
- data/lib/bolt/outputter/rainbow.rb +15 -0
- data/lib/bolt/pal.rb +5 -9
- data/lib/bolt/pal/yaml_plan/evaluator.rb +4 -0
- data/lib/bolt/pal/yaml_plan/step.rb +14 -1
- data/lib/bolt/pal/yaml_plan/step/message.rb +30 -0
- data/lib/bolt/pal/yaml_plan/transpiler.rb +11 -3
- data/lib/bolt/plugin/prompt.rb +3 -3
- data/lib/bolt/project.rb +6 -4
- data/lib/bolt/project_migrate.rb +138 -0
- data/lib/bolt/shell/bash.rb +7 -7
- data/lib/bolt/transport/docker/connection.rb +9 -9
- data/lib/bolt/transport/local/connection.rb +2 -2
- data/lib/bolt/transport/orch.rb +3 -3
- data/lib/bolt/transport/ssh/connection.rb +5 -5
- data/lib/bolt/transport/ssh/exec_connection.rb +4 -4
- data/lib/bolt/transport/winrm/connection.rb +17 -8
- data/lib/bolt/util.rb +1 -1
- data/lib/bolt/util/puppet_log_level.rb +4 -3
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/base_config.rb +1 -1
- data/lib/bolt_server/pe/pal.rb +1 -1
- data/lib/bolt_server/transport_app.rb +76 -0
- data/lib/bolt_spec/plans.rb +1 -1
- data/lib/bolt_spec/plans/action_stubs.rb +1 -1
- data/libexec/apply_catalog.rb +2 -2
- data/libexec/bolt_catalog +1 -1
- data/libexec/custom_facts.rb +1 -1
- data/libexec/query_resources.rb +1 -1
- data/modules/secure_env_vars/plans/init.pp +20 -0
- metadata +8 -2
data/lib/bolt/catalog.rb
CHANGED
@@ -76,7 +76,15 @@ module Bolt
|
|
76
76
|
target = request['target']
|
77
77
|
plan_vars = shadow_vars('plan', request['plan_vars'], target['facts'])
|
78
78
|
target_vars = shadow_vars('target', target['variables'], target['facts'])
|
79
|
-
|
79
|
+
|
80
|
+
# Merge plan vars with target vars, while maintaining the order of the plan
|
81
|
+
# vars. It's critical that the order of plan vars is not changed, as Puppet
|
82
|
+
# will deserialize the variables in the order they appear. Variables may
|
83
|
+
# contain local references to variables that appear earlier in a plan. If
|
84
|
+
# these variables are moved before the variable they reference, Puppet will
|
85
|
+
# be unable to deserialize the data and raise an error.
|
86
|
+
topscope_vars = target_vars.reject { |k, _v| plan_vars.key?(k) }.merge(plan_vars)
|
87
|
+
|
80
88
|
env_conf = { modulepath: request['modulepath'],
|
81
89
|
facts: target['facts'],
|
82
90
|
variables: topscope_vars }
|
data/lib/bolt/cli.rb
CHANGED
@@ -20,6 +20,7 @@ require 'bolt/logger'
|
|
20
20
|
require 'bolt/outputter'
|
21
21
|
require 'bolt/puppetdb'
|
22
22
|
require 'bolt/plugin'
|
23
|
+
require 'bolt/project_migrate'
|
23
24
|
require 'bolt/pal'
|
24
25
|
require 'bolt/target'
|
25
26
|
require 'bolt/version'
|
@@ -31,14 +32,15 @@ module Bolt
|
|
31
32
|
COMMANDS = { 'command' => %w[run],
|
32
33
|
'script' => %w[run],
|
33
34
|
'task' => %w[show run],
|
34
|
-
'plan' => %w[show run convert],
|
35
|
+
'plan' => %w[show run convert new],
|
35
36
|
'file' => %w[download upload],
|
36
37
|
'puppetfile' => %w[install show-modules generate-types],
|
37
38
|
'secret' => %w[encrypt decrypt createkeys],
|
38
39
|
'inventory' => %w[show],
|
39
40
|
'group' => %w[show],
|
40
41
|
'project' => %w[init migrate],
|
41
|
-
'apply' => %w[]
|
42
|
+
'apply' => %w[],
|
43
|
+
'guide' => %w[] }.freeze
|
42
44
|
|
43
45
|
attr_reader :config, :options
|
44
46
|
|
@@ -258,6 +260,13 @@ module Bolt
|
|
258
260
|
"Option '--noop' may only be specified when running a task or applying manifest code"
|
259
261
|
end
|
260
262
|
|
263
|
+
if options[:env_vars]
|
264
|
+
unless %w[command script].include?(options[:subcommand]) && options[:action] == 'run'
|
265
|
+
raise Bolt::CLIError,
|
266
|
+
"Option '--env-var' may only be specified when running a command or script"
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
261
270
|
if options[:subcommand] == 'apply' && (options[:object] && options[:code])
|
262
271
|
raise Bolt::CLIError, "--execute is unsupported when specifying a manifest file"
|
263
272
|
end
|
@@ -276,6 +285,10 @@ module Bolt
|
|
276
285
|
raise Bolt::CLIError, "Must specify a value to #{options[:action]}"
|
277
286
|
end
|
278
287
|
|
288
|
+
if options[:subcommand] == 'plan' && options[:action] == 'new' && !options[:object]
|
289
|
+
raise Bolt::CLIError, "Must specify a plan name."
|
290
|
+
end
|
291
|
+
|
279
292
|
if options.key?(:debug) && options.key?(:log)
|
280
293
|
raise Bolt::CLIError, "Only one of '--debug' or '--log-level' may be specified"
|
281
294
|
end
|
@@ -343,19 +356,11 @@ module Bolt
|
|
343
356
|
# Initialize inventory and targets. Errors here are better to catch early.
|
344
357
|
# options[:target_args] will contain a string/array version of the targetting options this is passed to plans
|
345
358
|
# options[:targets] will contain a resolved set of Target objects
|
346
|
-
unless options[:subcommand]
|
347
|
-
options[:
|
348
|
-
options[:subcommand] == 'project' ||
|
349
|
-
options[:action] == 'show' ||
|
350
|
-
options[:action] == 'convert'
|
359
|
+
unless %w[project puppetfile secret guide].include?(options[:subcommand]) ||
|
360
|
+
%w[convert new show].include?(options[:action])
|
351
361
|
update_targets(options)
|
352
362
|
end
|
353
363
|
|
354
|
-
if options[:action] == 'convert'
|
355
|
-
convert_plan(options[:object])
|
356
|
-
return 0
|
357
|
-
end
|
358
|
-
|
359
364
|
screen = "#{options[:subcommand]}_#{options[:action]}"
|
360
365
|
# submit a different screen for `bolt task show` and `bolt task show foo`
|
361
366
|
if options[:action] == 'show' && options[:object]
|
@@ -407,6 +412,9 @@ module Bolt
|
|
407
412
|
when 'show-modules'
|
408
413
|
list_modules
|
409
414
|
return 0
|
415
|
+
when 'convert'
|
416
|
+
pal.convert_plan(options[:object])
|
417
|
+
return 0
|
410
418
|
end
|
411
419
|
|
412
420
|
message = 'There may be processes left executing on some nodes.'
|
@@ -416,15 +424,28 @@ module Bolt
|
|
416
424
|
end
|
417
425
|
|
418
426
|
case options[:subcommand]
|
427
|
+
when 'guide'
|
428
|
+
code = if options[:object]
|
429
|
+
show_guide(options[:object])
|
430
|
+
else
|
431
|
+
list_topics
|
432
|
+
end
|
419
433
|
when 'project'
|
420
434
|
case options[:action]
|
421
435
|
when 'init'
|
422
436
|
code = initialize_project
|
423
437
|
when 'migrate'
|
424
|
-
|
438
|
+
inv = config.inventoryfile
|
439
|
+
path = config.project.path
|
440
|
+
code = Bolt::ProjectMigrate.new(path, outputter, inv).migrate_project
|
425
441
|
end
|
426
442
|
when 'plan'
|
427
|
-
|
443
|
+
case options[:action]
|
444
|
+
when 'new'
|
445
|
+
code = new_plan(options[:object])
|
446
|
+
when 'run'
|
447
|
+
code = run_plan(options[:object], options[:task_options], options[:target_args], options)
|
448
|
+
end
|
428
449
|
when 'puppetfile'
|
429
450
|
case options[:action]
|
430
451
|
when 'generate-types'
|
@@ -450,6 +471,7 @@ module Bolt
|
|
450
471
|
elapsed_time = Benchmark.realtime do
|
451
472
|
executor_opts = {}
|
452
473
|
executor_opts[:description] = options[:description] if options.key?(:description)
|
474
|
+
executor_opts[:env_vars] = options[:env_vars] if options.key?(:env_vars)
|
453
475
|
executor.subscribe(outputter)
|
454
476
|
executor.subscribe(log_outputter)
|
455
477
|
results =
|
@@ -514,7 +536,7 @@ module Bolt
|
|
514
536
|
tasks = pal.list_tasks
|
515
537
|
tasks.select! { |task| task.first.include?(options[:filter]) } if options[:filter]
|
516
538
|
tasks.select! { |task| config.project.tasks.include?(task.first) } unless config.project.tasks.nil?
|
517
|
-
outputter.print_tasks(tasks, pal.
|
539
|
+
outputter.print_tasks(tasks, pal.user_modulepath)
|
518
540
|
end
|
519
541
|
|
520
542
|
def show_plan(plan_name)
|
@@ -525,7 +547,7 @@ module Bolt
|
|
525
547
|
plans = pal.list_plans
|
526
548
|
plans.select! { |plan| plan.first.include?(options[:filter]) } if options[:filter]
|
527
549
|
plans.select! { |plan| config.project.plans.include?(plan.first) } unless config.project.plans.nil?
|
528
|
-
outputter.print_plans(plans, pal.
|
550
|
+
outputter.print_plans(plans, pal.user_modulepath)
|
529
551
|
end
|
530
552
|
|
531
553
|
def list_targets
|
@@ -543,6 +565,118 @@ module Bolt
|
|
543
565
|
outputter.print_groups(groups)
|
544
566
|
end
|
545
567
|
|
568
|
+
def new_plan(plan_name)
|
569
|
+
@logger.warn("Command 'bolt plan new' is experimental and subject to changes.")
|
570
|
+
|
571
|
+
if config.project.name.nil?
|
572
|
+
raise Bolt::Error.new(
|
573
|
+
"Project directory '#{config.project.path}' is not a named project. Unable to create "\
|
574
|
+
"a project-level plan. To name a project, set the 'name' key in the 'bolt-project.yaml' "\
|
575
|
+
"configuration file.",
|
576
|
+
"bolt/unnamed-project-error"
|
577
|
+
)
|
578
|
+
end
|
579
|
+
|
580
|
+
if plan_name !~ Bolt::Module::CONTENT_NAME_REGEX
|
581
|
+
message = <<~MESSAGE.chomp
|
582
|
+
Invalid plan name '#{plan_name}'. Plan names are composed of one or more name segments
|
583
|
+
separated by double colons '::'.
|
584
|
+
|
585
|
+
Each name segment must begin with a lowercase letter, and may only include lowercase
|
586
|
+
letters, digits, and underscores.
|
587
|
+
|
588
|
+
Examples of valid plan names:
|
589
|
+
- #{config.project.name}
|
590
|
+
- #{config.project.name}::my_plan
|
591
|
+
MESSAGE
|
592
|
+
|
593
|
+
raise Bolt::ValidationError, message
|
594
|
+
end
|
595
|
+
|
596
|
+
prefix, *name_segments, basename = plan_name.split('::')
|
597
|
+
|
598
|
+
# If the plan name is just the project name, then create an 'init' plan.
|
599
|
+
# Otherwise, use the last name segment for the plan's filename.
|
600
|
+
basename ||= 'init'
|
601
|
+
|
602
|
+
unless prefix == config.project.name
|
603
|
+
message = "First segment of plan name '#{plan_name}' must match project name '#{config.project.name}'. "\
|
604
|
+
"Did you mean '#{config.project.name}::#{plan_name}'?"
|
605
|
+
|
606
|
+
raise Bolt::ValidationError, message
|
607
|
+
end
|
608
|
+
|
609
|
+
dir_path = config.project.plans_path.join(*name_segments)
|
610
|
+
|
611
|
+
%w[pp yaml].each do |ext|
|
612
|
+
next unless (path = config.project.plans_path + "#{basename}.#{ext}").exist?
|
613
|
+
raise Bolt::Error.new(
|
614
|
+
"A plan with the name '#{plan_name}' already exists at '#{path}', nothing to do.",
|
615
|
+
'bolt/existing-plan-error'
|
616
|
+
)
|
617
|
+
end
|
618
|
+
|
619
|
+
begin
|
620
|
+
FileUtils.mkdir_p(dir_path)
|
621
|
+
rescue Errno::EEXIST => e
|
622
|
+
raise Bolt::Error.new(
|
623
|
+
"#{e.message}; unable to create plan directory '#{dir_path}'",
|
624
|
+
'bolt/existing-file-error'
|
625
|
+
)
|
626
|
+
end
|
627
|
+
|
628
|
+
plan_path = dir_path + "#{basename}.yaml"
|
629
|
+
|
630
|
+
plan_template = <<~PLAN
|
631
|
+
# This is the structure of a simple plan. To learn more about writing
|
632
|
+
# YAML plans, see the documentation: http://pup.pt/bolt-yaml-plans
|
633
|
+
|
634
|
+
# The description sets the description of the plan that will appear
|
635
|
+
# in 'bolt plan show' output.
|
636
|
+
description: A plan created with bolt plan new
|
637
|
+
|
638
|
+
# The parameters key defines the parameters that can be passed to
|
639
|
+
# the plan.
|
640
|
+
parameters:
|
641
|
+
targets:
|
642
|
+
type: TargetSpec
|
643
|
+
description: A list of targets to run actions on
|
644
|
+
default: localhost
|
645
|
+
|
646
|
+
# The steps key defines the actions the plan will take in order.
|
647
|
+
steps:
|
648
|
+
- message: Hello from #{plan_name}
|
649
|
+
- name: command_step
|
650
|
+
command: whoami
|
651
|
+
targets: $targets
|
652
|
+
|
653
|
+
# The return key sets the return value of the plan.
|
654
|
+
return: $command_step
|
655
|
+
PLAN
|
656
|
+
|
657
|
+
begin
|
658
|
+
File.write(plan_path, plan_template)
|
659
|
+
rescue Errno::EACCES => e
|
660
|
+
raise Bolt::FileError.new(
|
661
|
+
"#{e.message}; unable to create plan",
|
662
|
+
plan_path
|
663
|
+
)
|
664
|
+
end
|
665
|
+
|
666
|
+
output = <<~OUTPUT
|
667
|
+
Created plan '#{plan_name}' at '#{plan_path}'
|
668
|
+
|
669
|
+
Show this plan with:
|
670
|
+
bolt plan show #{plan_name}
|
671
|
+
Run this plan with:
|
672
|
+
bolt plan run #{plan_name}
|
673
|
+
OUTPUT
|
674
|
+
|
675
|
+
outputter.print_message(output)
|
676
|
+
|
677
|
+
0
|
678
|
+
end
|
679
|
+
|
546
680
|
def run_plan(plan_name, plan_arguments, nodes, options)
|
547
681
|
unless nodes.empty?
|
548
682
|
if plan_arguments['nodes'] || plan_arguments['targets']
|
@@ -646,8 +780,26 @@ module Bolt
|
|
646
780
|
# Initializes a specified directory as a Bolt project and installs any modules
|
647
781
|
# specified by the user, along with their dependencies
|
648
782
|
def initialize_project
|
649
|
-
|
650
|
-
|
783
|
+
# Dir.pwd will return backslashes on Windows, but Pathname always uses
|
784
|
+
# forward slashes to concatenate paths. This results in paths like
|
785
|
+
# C:\User\Administrator/modules, which fail module install. This ensure
|
786
|
+
# forward slashes in the cwd path.
|
787
|
+
dir = File.expand_path(Dir.pwd)
|
788
|
+
name = options[:object] || File.basename(dir)
|
789
|
+
if name !~ Bolt::Module::MODULE_NAME_REGEX
|
790
|
+
if options[:object]
|
791
|
+
raise Bolt::ValidationError, "The provided project name '#{name}' is invalid; "\
|
792
|
+
"project name must begin with a lowercase letter and can include lowercase "\
|
793
|
+
"letters, numbers, and underscores."
|
794
|
+
else
|
795
|
+
raise Bolt::ValidationError, "The current directory name '#{name}' is an invalid "\
|
796
|
+
"project name. Please specify a name using 'bolt project init <name>'."
|
797
|
+
end
|
798
|
+
end
|
799
|
+
|
800
|
+
project = Pathname.new(dir)
|
801
|
+
old_config = project + 'bolt.yaml'
|
802
|
+
config = project + 'bolt-project.yaml'
|
651
803
|
puppetfile = project + 'Puppetfile'
|
652
804
|
modulepath = [project + 'modules']
|
653
805
|
|
@@ -668,18 +820,24 @@ module Bolt
|
|
668
820
|
|
669
821
|
# Warn the user if the project directory already exists. We don't error here since users
|
670
822
|
# might not have installed any modules yet.
|
823
|
+
# If both bolt.yaml and bolt-project.yaml exist, this will just warn
|
824
|
+
# about bolt-project.yaml and subsequent Bolt actions will warn about
|
825
|
+
# both files existing
|
671
826
|
if config.exist?
|
672
|
-
@logger.warn "Found existing project directory at #{project}"
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
827
|
+
@logger.warn "Found existing project directory at #{project}. Skipping file creation."
|
828
|
+
# This won't get called if bolt-project.yaml exists
|
829
|
+
elsif old_config.exist?
|
830
|
+
@logger.warn "Found existing #{old_config.basename} at #{project}. "\
|
831
|
+
"#{old_config.basename} is deprecated, please rename to #{config.basename}."
|
678
832
|
# Bless the project directory as a...wait for it...project
|
679
|
-
if FileUtils.touch(config)
|
680
|
-
outputter.print_message "Successfully created Bolt project at #{project}"
|
681
833
|
else
|
682
|
-
|
834
|
+
begin
|
835
|
+
content = { 'name' => name }
|
836
|
+
File.write(config.to_path, content.to_yaml)
|
837
|
+
outputter.print_message "Successfully created Bolt project at #{project}"
|
838
|
+
rescue StandardError => e
|
839
|
+
raise Bolt::FileError.new("Could not create bolt-project.yaml at #{project}: #{e.message}", nil)
|
840
|
+
end
|
683
841
|
end
|
684
842
|
|
685
843
|
# Write the generated Puppetfile to the fancy new project
|
@@ -755,49 +913,6 @@ module Bolt
|
|
755
913
|
end
|
756
914
|
end
|
757
915
|
|
758
|
-
def migrate_project
|
759
|
-
inventory_file = config.inventoryfile || config.default_inventoryfile
|
760
|
-
data = Bolt::Util.read_yaml_hash(inventory_file, 'inventory')
|
761
|
-
|
762
|
-
data.delete('version') if data['version'] != 2
|
763
|
-
|
764
|
-
migrated = migrate_group(data)
|
765
|
-
|
766
|
-
ok = File.write(inventory_file, data.to_yaml) if migrated
|
767
|
-
|
768
|
-
result = if migrated && ok
|
769
|
-
"Successfully migrated Bolt project to latest version."
|
770
|
-
elsif !migrated
|
771
|
-
"Bolt project already on latest version. Nothing to do."
|
772
|
-
else
|
773
|
-
"Could not migrate Bolt project to latest version."
|
774
|
-
end
|
775
|
-
outputter.print_message result
|
776
|
-
|
777
|
-
ok ? 0 : 1
|
778
|
-
end
|
779
|
-
|
780
|
-
# Walks an inventory hash and replaces all 'nodes' keys with 'targets' keys
|
781
|
-
# and all 'name' keys nested in a 'targets' hash with 'uri' keys. Data is
|
782
|
-
# modified in place.
|
783
|
-
def migrate_group(group)
|
784
|
-
migrated = false
|
785
|
-
if group.key?('nodes')
|
786
|
-
migrated = true
|
787
|
-
targets = group['nodes'].map do |target|
|
788
|
-
target['uri'] = target.delete('name') if target.is_a?(Hash)
|
789
|
-
target
|
790
|
-
end
|
791
|
-
group.delete('nodes')
|
792
|
-
group['targets'] = targets
|
793
|
-
end
|
794
|
-
(group['groups'] || []).each do |subgroup|
|
795
|
-
migrated_group = migrate_group(subgroup)
|
796
|
-
migrated ||= migrated_group
|
797
|
-
end
|
798
|
-
migrated
|
799
|
-
end
|
800
|
-
|
801
916
|
def install_puppetfile(config, puppetfile, modulepath)
|
802
917
|
require 'r10k/cli'
|
803
918
|
require 'bolt/r10k_log_proxy'
|
@@ -840,8 +955,46 @@ module Bolt
|
|
840
955
|
config.project)
|
841
956
|
end
|
842
957
|
|
843
|
-
|
844
|
-
|
958
|
+
# Collects the list of Bolt guides and maps them to their topics.
|
959
|
+
def guides
|
960
|
+
@guides ||= begin
|
961
|
+
root_path = File.expand_path(File.join(__dir__, '..', '..', 'guides'))
|
962
|
+
files = Dir.children(root_path).sort
|
963
|
+
|
964
|
+
files.each_with_object({}) do |file, guides|
|
965
|
+
next if file !~ /\.txt\z/
|
966
|
+
topic = File.basename(file, '.txt')
|
967
|
+
guides[topic] = File.join(root_path, file)
|
968
|
+
end
|
969
|
+
rescue SystemCallError => e
|
970
|
+
raise Bolt::FileError.new("#{e.message}: unable to load guides directory", root_path)
|
971
|
+
end
|
972
|
+
end
|
973
|
+
|
974
|
+
# Display the list of available Bolt guides.
|
975
|
+
def list_topics
|
976
|
+
outputter.print_topics(guides.keys)
|
977
|
+
0
|
978
|
+
end
|
979
|
+
|
980
|
+
# Display a specific Bolt guide.
|
981
|
+
def show_guide(topic)
|
982
|
+
if guides[topic]
|
983
|
+
analytics.event('Guide', 'known_topic', label: topic)
|
984
|
+
|
985
|
+
begin
|
986
|
+
guide = File.read(guides[topic])
|
987
|
+
rescue SystemCallError => e
|
988
|
+
raise Bolt::FileError("#{e.message}: unable to load guide page", filepath)
|
989
|
+
end
|
990
|
+
|
991
|
+
outputter.print_guide(guide, topic)
|
992
|
+
else
|
993
|
+
analytics.event('Guide', 'unknown_topic', label: topic)
|
994
|
+
outputter.print_message("Did not find guide for topic '#{topic}'.\n\n")
|
995
|
+
list_topics
|
996
|
+
end
|
997
|
+
0
|
845
998
|
end
|
846
999
|
|
847
1000
|
def validate_file(type, path, allow_dir = false)
|
@@ -908,7 +1061,7 @@ module Bolt
|
|
908
1061
|
msg = <<~MSG.chomp
|
909
1062
|
Loaded configuration from: '#{config.config_files.join("', '")}'
|
910
1063
|
MSG
|
911
|
-
@logger.
|
1064
|
+
@logger.info(msg)
|
912
1065
|
end
|
913
1066
|
|
914
1067
|
# Gem installs include the aggregate, canary, and puppetdb_fact modules, while
|
data/lib/bolt/config.rb
CHANGED
@@ -213,6 +213,13 @@ module Bolt
|
|
213
213
|
'transport' => 'ssh'
|
214
214
|
}
|
215
215
|
|
216
|
+
if project.path.directory?
|
217
|
+
default_data['log']['bolt-debug.log'] = {
|
218
|
+
'level' => 'debug',
|
219
|
+
'append' => false
|
220
|
+
}
|
221
|
+
end
|
222
|
+
|
216
223
|
loaded_data = config_data.each_with_object([]) do |data, acc|
|
217
224
|
@warnings.concat(data[:warnings]) if data[:warnings].any?
|
218
225
|
@deprecations.concat(data[:deprecations]) if data[:deprecations].any?
|