bolt 2.32.0 → 2.36.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 +6 -6
- data/bolt-modules/boltlib/lib/puppet/datatypes/applyresult.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/catch_errors.rb +1 -3
- data/bolt-modules/boltlib/lib/puppet/functions/download_file.rb +17 -6
- data/bolt-modules/boltlib/lib/puppet/functions/facts.rb +6 -0
- data/bolt-modules/boltlib/lib/puppet/functions/parallelize.rb +56 -0
- data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb +2 -2
- data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +24 -6
- data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +27 -8
- data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +21 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_task_with.rb +18 -1
- data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +24 -6
- data/guides/logging.txt +18 -0
- data/lib/bolt/analytics.rb +27 -8
- data/lib/bolt/apply_result.rb +3 -3
- data/lib/bolt/bolt_option_parser.rb +43 -15
- data/lib/bolt/cli.rb +79 -227
- data/lib/bolt/config.rb +131 -52
- data/lib/bolt/config/options.rb +46 -8
- data/lib/bolt/config/transport/base.rb +10 -19
- data/lib/bolt/config/transport/local.rb +0 -7
- data/lib/bolt/config/transport/options.rb +1 -1
- data/lib/bolt/config/transport/ssh.rb +8 -14
- data/lib/bolt/config/validator.rb +231 -0
- data/lib/bolt/error.rb +37 -3
- data/lib/bolt/executor.rb +103 -17
- data/lib/bolt/inventory/group.rb +2 -1
- data/lib/bolt/module_installer.rb +2 -1
- data/lib/bolt/module_installer/specs/forge_spec.rb +5 -4
- data/lib/bolt/module_installer/specs/git_spec.rb +4 -3
- data/lib/bolt/outputter/human.rb +21 -9
- data/lib/bolt/outputter/rainbow.rb +1 -1
- data/lib/bolt/pal.rb +48 -30
- data/lib/bolt/pal/yaml_plan.rb +11 -2
- data/lib/bolt/pal/yaml_plan/evaluator.rb +23 -1
- data/lib/bolt/pal/yaml_plan/loader.rb +14 -9
- data/lib/bolt/plan_creator.rb +160 -0
- data/lib/bolt/plugin.rb +1 -8
- data/lib/bolt/project.rb +30 -36
- data/lib/bolt/project_manager.rb +199 -0
- data/lib/bolt/{project_migrator/config.rb → project_manager/config_migrator.rb} +43 -5
- data/lib/bolt/{project_migrator/inventory.rb → project_manager/inventory_migrator.rb} +5 -5
- data/lib/bolt/{project_migrator/base.rb → project_manager/migrator.rb} +2 -2
- data/lib/bolt/{project_migrator/modules.rb → project_manager/module_migrator.rb} +3 -3
- data/lib/bolt/puppetdb/client.rb +3 -2
- data/lib/bolt/puppetdb/config.rb +9 -8
- data/lib/bolt/result.rb +23 -11
- data/lib/bolt/shell/bash.rb +12 -7
- data/lib/bolt/shell/powershell.rb +12 -7
- data/lib/bolt/task/run.rb +1 -1
- data/lib/bolt/transport/base.rb +18 -18
- data/lib/bolt/transport/docker.rb +23 -6
- data/lib/bolt/transport/orch.rb +23 -19
- data/lib/bolt/transport/orch/connection.rb +10 -3
- data/lib/bolt/transport/remote.rb +3 -3
- data/lib/bolt/transport/simple.rb +6 -6
- data/lib/bolt/transport/ssh/exec_connection.rb +6 -2
- data/lib/bolt/util.rb +19 -7
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt/yarn.rb +23 -0
- data/lib/bolt_server/base_config.rb +3 -1
- data/lib/bolt_server/config.rb +3 -1
- data/lib/bolt_server/file_cache.rb +2 -0
- data/lib/bolt_server/schemas/partials/task.json +2 -2
- data/lib/bolt_server/transport_app.rb +42 -11
- data/lib/bolt_spec/plans/action_stubs/command_stub.rb +1 -1
- data/lib/bolt_spec/plans/action_stubs/script_stub.rb +1 -1
- data/lib/bolt_spec/plans/mock_executor.rb +9 -6
- data/libexec/apply_catalog.rb +1 -1
- data/libexec/custom_facts.rb +1 -1
- data/libexec/query_resources.rb +1 -1
- metadata +12 -14
- data/lib/bolt/project_migrator.rb +0 -80
- data/modules/secure_env_vars/plans/init.pp +0 -20
data/lib/bolt/apply_result.rb
CHANGED
@@ -96,9 +96,9 @@ module Bolt
|
|
96
96
|
@target = target
|
97
97
|
@value = {}
|
98
98
|
@action = 'apply'
|
99
|
-
value['report'] = report if report
|
100
|
-
value['_error'] = error if error
|
101
|
-
value['_output'] = metrics_message if metrics_message
|
99
|
+
@value['report'] = report if report
|
100
|
+
@value['_error'] = error if error
|
101
|
+
@value['_output'] = metrics_message if metrics_message
|
102
102
|
end
|
103
103
|
|
104
104
|
def event_metrics
|
@@ -6,11 +6,12 @@ require 'optparse'
|
|
6
6
|
|
7
7
|
module Bolt
|
8
8
|
class BoltOptionParser < OptionParser
|
9
|
+
PROJECT_PATHS = %w[project configfile boltdir].freeze
|
9
10
|
OPTIONS = { inventory: %w[targets query rerun description],
|
10
11
|
authentication: %w[user password password-prompt private-key host-key-check ssl ssl-verify],
|
11
12
|
escalation: %w[run-as sudo-password sudo-password-prompt sudo-executable],
|
12
13
|
run_context: %w[concurrency inventoryfile save-rerun cleanup],
|
13
|
-
global_config_setters: %w[modulepath
|
14
|
+
global_config_setters: PROJECT_PATHS + %w[modulepath],
|
14
15
|
transports: %w[transport connect-timeout tty native-ssh ssh-command copy-command],
|
15
16
|
display: %w[format color verbose trace],
|
16
17
|
global: %w[help version debug log-level] }.freeze
|
@@ -46,7 +47,8 @@ module Bolt
|
|
46
47
|
when 'inventory'
|
47
48
|
case action
|
48
49
|
when 'show'
|
49
|
-
{ flags: OPTIONS[:inventory] + OPTIONS[:global] +
|
50
|
+
{ flags: OPTIONS[:inventory] + OPTIONS[:global] +
|
51
|
+
PROJECT_PATHS + %w[format inventoryfile detail],
|
50
52
|
banner: INVENTORY_SHOW_HELP }
|
51
53
|
else
|
52
54
|
{ flags: OPTIONS[:global],
|
@@ -55,7 +57,7 @@ module Bolt
|
|
55
57
|
when 'group'
|
56
58
|
case action
|
57
59
|
when 'show'
|
58
|
-
{ flags: OPTIONS[:global] + %w[format inventoryfile
|
60
|
+
{ flags: OPTIONS[:global] + PROJECT_PATHS + %w[format inventoryfile],
|
59
61
|
banner: GROUP_SHOW_HELP }
|
60
62
|
else
|
61
63
|
{ flags: OPTIONS[:global],
|
@@ -67,13 +69,13 @@ module Bolt
|
|
67
69
|
when 'module'
|
68
70
|
case action
|
69
71
|
when 'add'
|
70
|
-
{ flags: OPTIONS[:global] +
|
72
|
+
{ flags: OPTIONS[:global] + PROJECT_PATHS,
|
71
73
|
banner: MODULE_ADD_HELP }
|
72
74
|
when 'generate-types'
|
73
75
|
{ flags: OPTIONS[:global] + OPTIONS[:global_config_setters],
|
74
76
|
banner: MODULE_GENERATETYPES_HELP }
|
75
77
|
when 'install'
|
76
|
-
{ flags: OPTIONS[:global] + %w[
|
78
|
+
{ flags: OPTIONS[:global] + PROJECT_PATHS + %w[force resolve],
|
77
79
|
banner: MODULE_INSTALL_HELP }
|
78
80
|
when 'show'
|
79
81
|
{ flags: OPTIONS[:global] + OPTIONS[:global_config_setters],
|
@@ -88,7 +90,7 @@ module Bolt
|
|
88
90
|
{ flags: OPTIONS[:global] + OPTIONS[:global_config_setters],
|
89
91
|
banner: PLAN_CONVERT_HELP }
|
90
92
|
when 'new'
|
91
|
-
{ flags: OPTIONS[:global] + %w[
|
93
|
+
{ flags: OPTIONS[:global] + PROJECT_PATHS + %w[pp],
|
92
94
|
banner: PLAN_NEW_HELP }
|
93
95
|
when 'run'
|
94
96
|
{ flags: ACTION_OPTS + %w[params compile-concurrency tmpdir hiera-config],
|
@@ -106,7 +108,7 @@ module Bolt
|
|
106
108
|
{ flags: OPTIONS[:global] + %w[modules],
|
107
109
|
banner: PROJECT_INIT_HELP }
|
108
110
|
when 'migrate'
|
109
|
-
{ flags: OPTIONS[:global] + %w[inventoryfile
|
111
|
+
{ flags: OPTIONS[:global] + PROJECT_PATHS + %w[inventoryfile],
|
110
112
|
banner: PROJECT_MIGRATE_HELP }
|
111
113
|
else
|
112
114
|
{ flags: OPTIONS[:global],
|
@@ -793,7 +795,10 @@ module Bolt
|
|
793
795
|
@options[:noop] = true
|
794
796
|
end
|
795
797
|
define('--description DESCRIPTION',
|
796
|
-
'Description to use for the job') do |description|
|
798
|
+
'Deprecated. Description to use for the job') do |description|
|
799
|
+
msg = "Command line option '--description' is deprecated, and will be "\
|
800
|
+
"removed in Bolt 3.0."
|
801
|
+
@deprecations << { type: 'Using --description', msg: msg }
|
797
802
|
@options[:description] = description
|
798
803
|
end
|
799
804
|
define('--params PARAMETERS',
|
@@ -873,13 +878,25 @@ module Bolt
|
|
873
878
|
File.expand_path(moduledir)
|
874
879
|
end
|
875
880
|
end
|
876
|
-
define('--
|
877
|
-
'Specify what project to load config from (default:
|
881
|
+
define('--boltdir PATH',
|
882
|
+
'Deprecated. Specify what project to load config from (default:',
|
883
|
+
'autodiscovered from current working dir)') do |path|
|
884
|
+
msg = "Command line option '--boltdir' is deprecated, use '--project' instead."
|
885
|
+
@deprecations << { type: 'Using --boltdir', msg: msg }
|
878
886
|
@options[:boltdir] = path
|
879
887
|
end
|
888
|
+
define('--project PATH',
|
889
|
+
'Path to load the Bolt project from (default: autodiscovered from current dir)') do |path|
|
890
|
+
@options[:project] = path
|
891
|
+
end
|
880
892
|
define('--configfile PATH',
|
881
|
-
'Specify where to load config from (default:
|
882
|
-
'Directory containing bolt.yaml will be
|
893
|
+
'Deprecated. Specify where to load config from (default:',
|
894
|
+
'~/.puppetlabs/bolt/bolt.yaml). Directory containing bolt.yaml will be',
|
895
|
+
'used as the project directory.') do |path|
|
896
|
+
msg = "Command line option '--configfile' is deprecated, and " \
|
897
|
+
"will be removed in Bolt 3.0. Use '--project' and provide the "\
|
898
|
+
"directory path instead."
|
899
|
+
@deprecations << { type: 'Using --configfile', msg: msg }
|
883
900
|
@options[:configfile] = path
|
884
901
|
end
|
885
902
|
define('--hiera-config PATH',
|
@@ -891,12 +908,18 @@ module Bolt
|
|
891
908
|
if ENV.include?(Bolt::Inventory::ENVIRONMENT_VAR)
|
892
909
|
raise Bolt::CLIError, "Cannot pass inventory file when #{Bolt::Inventory::ENVIRONMENT_VAR} is set"
|
893
910
|
end
|
894
|
-
@options[:inventoryfile] =
|
911
|
+
@options[:inventoryfile] = File.expand_path(path)
|
895
912
|
end
|
896
913
|
define('--puppetfile PATH',
|
897
|
-
'Specify a Puppetfile to use when installing modules.
|
914
|
+
'Deprecated. Specify a Puppetfile to use when installing modules.',
|
915
|
+
' (default: ~/.puppetlabs/bolt/Puppetfile)',
|
898
916
|
'Modules are installed in the current project.') do |path|
|
899
|
-
|
917
|
+
command = Bolt::Util.powershell? ? 'Update-BoltProject' : 'bolt project migrate'
|
918
|
+
msg = "Command line option '--puppetfile' is deprecated, and will be removed "\
|
919
|
+
"in Bolt 3.0. You can migrate to using the new module management "\
|
920
|
+
"workflow using '#{command}'."
|
921
|
+
@deprecations << { type: 'Using --puppetfile', msg: msg }
|
922
|
+
@options[:puppetfile_path] = File.expand_path(path)
|
900
923
|
end
|
901
924
|
define('--[no-]save-rerun', 'Whether to update the rerun file after this command.') do |save|
|
902
925
|
@options[:'save-rerun'] = save
|
@@ -945,6 +968,11 @@ module Bolt
|
|
945
968
|
@options[:resolve] = resolve
|
946
969
|
end
|
947
970
|
|
971
|
+
separator "\nPLAN OPTIONS"
|
972
|
+
define('--pp', 'Create a new Puppet language plan.') do |pp|
|
973
|
+
@options[:puppet] = pp
|
974
|
+
end
|
975
|
+
|
948
976
|
separator "\nDISPLAY OPTIONS"
|
949
977
|
define('--filter FILTER', 'Filter tasks and plans by a matching substring') do |filter|
|
950
978
|
unless /^[a-z0-9_:]+$/.match(filter)
|
data/lib/bolt/cli.rb
CHANGED
@@ -15,20 +15,22 @@ require 'bolt/config'
|
|
15
15
|
require 'bolt/error'
|
16
16
|
require 'bolt/executor'
|
17
17
|
require 'bolt/inventory'
|
18
|
-
require 'bolt/rerun'
|
19
18
|
require 'bolt/logger'
|
19
|
+
require 'bolt/module_installer'
|
20
20
|
require 'bolt/outputter'
|
21
|
-
require 'bolt/puppetdb'
|
22
|
-
require 'bolt/plugin'
|
23
|
-
require 'bolt/project_migrator'
|
24
21
|
require 'bolt/pal'
|
22
|
+
require 'bolt/plan_creator'
|
23
|
+
require 'bolt/plugin'
|
24
|
+
require 'bolt/project_manager'
|
25
|
+
require 'bolt/puppetdb'
|
26
|
+
require 'bolt/rerun'
|
27
|
+
require 'bolt/secret'
|
25
28
|
require 'bolt/target'
|
26
29
|
require 'bolt/version'
|
27
|
-
require 'bolt/secret'
|
28
|
-
require 'bolt/module_installer'
|
29
30
|
|
30
31
|
module Bolt
|
31
32
|
class CLIExit < StandardError; end
|
33
|
+
|
32
34
|
class CLI
|
33
35
|
COMMANDS = {
|
34
36
|
'command' => %w[run],
|
@@ -163,8 +165,9 @@ module Bolt
|
|
163
165
|
elsif options[:configfile]
|
164
166
|
Bolt::Config.from_file(options[:configfile], options)
|
165
167
|
else
|
166
|
-
|
167
|
-
|
168
|
+
cli_flag = options[:project] || options[:boltdir]
|
169
|
+
project = if cli_flag
|
170
|
+
dir = Pathname.new(cli_flag)
|
168
171
|
if (dir + Bolt::Project::BOLTDIR_NAME).directory?
|
169
172
|
Bolt::Project.create_project(dir + Bolt::Project::BOLTDIR_NAME)
|
170
173
|
else
|
@@ -196,10 +199,6 @@ module Bolt
|
|
196
199
|
|
197
200
|
warn_inventory_overrides_cli(options)
|
198
201
|
|
199
|
-
# Assert whether the puppetfile/module commands are available depending
|
200
|
-
# on whether 'modules' is configured.
|
201
|
-
assert_puppetfile_or_module_command(config.project.modules)
|
202
|
-
|
203
202
|
options
|
204
203
|
rescue Bolt::Error => e
|
205
204
|
outputter.fatal_error(e)
|
@@ -228,9 +227,9 @@ module Bolt
|
|
228
227
|
|
229
228
|
def validate(options)
|
230
229
|
unless COMMANDS.include?(options[:subcommand])
|
230
|
+
command = Bolt::Util.powershell? ? 'Get-Command -Module PuppetBolt' : 'bolt help'
|
231
231
|
raise Bolt::CLIError,
|
232
|
-
"
|
233
|
-
"#{COMMANDS.keys.join(', ')}"
|
232
|
+
"'#{options[:subcommand]}' is not a Bolt command. See '#{command}'."
|
234
233
|
end
|
235
234
|
|
236
235
|
actions = COMMANDS[options[:subcommand]]
|
@@ -285,8 +284,9 @@ module Bolt
|
|
285
284
|
end
|
286
285
|
|
287
286
|
if options[:subcommand] == 'module' && options[:action] == 'install' && options[:object]
|
287
|
+
command = Bolt::Util.powershell? ? 'Add-BoltModule -Module' : 'bolt module add'
|
288
288
|
raise Bolt::CLIError, "Invalid argument '#{options[:object]}'. To add a new module to "\
|
289
|
-
"the project, run '
|
289
|
+
"the project, run '#{command} #{options[:object]}'."
|
290
290
|
end
|
291
291
|
|
292
292
|
if options[:subcommand] != 'file' && options[:subcommand] != 'script' &&
|
@@ -295,7 +295,7 @@ module Bolt
|
|
295
295
|
"Unknown argument(s) #{options[:leftovers].join(', ')}"
|
296
296
|
end
|
297
297
|
|
298
|
-
if options
|
298
|
+
if options.slice(:boltdir, :configfile, :project).length > 1
|
299
299
|
raise Bolt::CLIError, "Only one of '--boltdir', '--project', or '--configfile' may be specified"
|
300
300
|
end
|
301
301
|
|
@@ -342,15 +342,10 @@ module Bolt
|
|
342
342
|
def warn_inventory_overrides_cli(opts)
|
343
343
|
inventory_source = if ENV[Bolt::Inventory::ENVIRONMENT_VAR]
|
344
344
|
Bolt::Inventory::ENVIRONMENT_VAR
|
345
|
-
elsif config.inventoryfile
|
345
|
+
elsif config.inventoryfile
|
346
346
|
config.inventoryfile
|
347
|
-
|
348
|
-
|
349
|
-
Bolt::Util.file_stat(config.default_inventoryfile)
|
350
|
-
config.default_inventoryfile
|
351
|
-
rescue Errno::ENOENT
|
352
|
-
nil
|
353
|
-
end
|
347
|
+
elsif File.exist?(config.default_inventoryfile)
|
348
|
+
config.default_inventoryfile
|
354
349
|
end
|
355
350
|
|
356
351
|
inventory_cli_opts = %i[authentication escalation transports].each_with_object([]) do |key, acc|
|
@@ -394,7 +389,7 @@ module Bolt
|
|
394
389
|
output_format: config.format,
|
395
390
|
# For continuity
|
396
391
|
boltdir_type: config.project.type
|
397
|
-
}
|
392
|
+
}.merge!(analytics.plan_counts(config.project.plans_path))
|
398
393
|
|
399
394
|
# Only include target and inventory info for commands that take a targets
|
400
395
|
# list. This avoids loading inventory for commands that don't need it.
|
@@ -458,14 +453,22 @@ module Bolt
|
|
458
453
|
when 'project'
|
459
454
|
case options[:action]
|
460
455
|
when 'init'
|
461
|
-
code =
|
456
|
+
code = Bolt::ProjectManager.new(config, outputter, pal)
|
457
|
+
.create(Dir.pwd, options[:object], options[:modules])
|
462
458
|
when 'migrate'
|
463
|
-
code = Bolt::
|
459
|
+
code = Bolt::ProjectManager.new(config, outputter, pal).migrate
|
464
460
|
end
|
465
461
|
when 'plan'
|
466
462
|
case options[:action]
|
467
463
|
when 'new'
|
468
|
-
|
464
|
+
plan_name = options[:object]
|
465
|
+
|
466
|
+
# If this passes validation, it will return the path to the plan to create
|
467
|
+
Bolt::PlanCreator.validate_input(config.project, plan_name)
|
468
|
+
code = Bolt::PlanCreator.create_plan(config.project.plans_path,
|
469
|
+
plan_name,
|
470
|
+
outputter,
|
471
|
+
options[:puppet])
|
469
472
|
when 'run'
|
470
473
|
code = run_plan(options[:object], options[:task_options], options[:target_args], options)
|
471
474
|
end
|
@@ -568,10 +571,15 @@ module Bolt
|
|
568
571
|
outputter.print_task_info(pal.get_task(task_name))
|
569
572
|
end
|
570
573
|
|
574
|
+
# Filters a list of content by matching substring.
|
575
|
+
#
|
576
|
+
private def filter_content(content, filter)
|
577
|
+
return content unless content && filter
|
578
|
+
content.select { |name,| name.include?(filter) }
|
579
|
+
end
|
580
|
+
|
571
581
|
def list_tasks
|
572
|
-
tasks = pal.list_tasks
|
573
|
-
tasks.select! { |task| task.first.include?(options[:filter]) } if options[:filter]
|
574
|
-
tasks.select! { |task| config.project.tasks.include?(task.first) } unless config.project.tasks.nil?
|
582
|
+
tasks = filter_content(pal.list_tasks(filter_content: true), options[:filter])
|
575
583
|
outputter.print_tasks(tasks, pal.user_modulepath)
|
576
584
|
end
|
577
585
|
|
@@ -580,9 +588,7 @@ module Bolt
|
|
580
588
|
end
|
581
589
|
|
582
590
|
def list_plans
|
583
|
-
plans = pal.list_plans
|
584
|
-
plans.select! { |plan| plan.first.include?(options[:filter]) } if options[:filter]
|
585
|
-
plans.select! { |plan| config.project.plans.include?(plan.first) } unless config.project.plans.nil?
|
591
|
+
plans = filter_content(pal.list_plans(filter_content: true), options[:filter])
|
586
592
|
outputter.print_plans(plans, pal.user_modulepath)
|
587
593
|
end
|
588
594
|
|
@@ -617,118 +623,6 @@ module Bolt
|
|
617
623
|
outputter.print_groups(groups)
|
618
624
|
end
|
619
625
|
|
620
|
-
def new_plan(plan_name)
|
621
|
-
@logger.warn("Command 'bolt plan new' is experimental and subject to changes.")
|
622
|
-
|
623
|
-
if config.project.name.nil?
|
624
|
-
raise Bolt::Error.new(
|
625
|
-
"Project directory '#{config.project.path}' is not a named project. Unable to create "\
|
626
|
-
"a project-level plan. To name a project, set the 'name' key in the 'bolt-project.yaml' "\
|
627
|
-
"configuration file.",
|
628
|
-
"bolt/unnamed-project-error"
|
629
|
-
)
|
630
|
-
end
|
631
|
-
|
632
|
-
if plan_name !~ Bolt::Module::CONTENT_NAME_REGEX
|
633
|
-
message = <<~MESSAGE.chomp
|
634
|
-
Invalid plan name '#{plan_name}'. Plan names are composed of one or more name segments
|
635
|
-
separated by double colons '::'.
|
636
|
-
|
637
|
-
Each name segment must begin with a lowercase letter, and may only include lowercase
|
638
|
-
letters, digits, and underscores.
|
639
|
-
|
640
|
-
Examples of valid plan names:
|
641
|
-
- #{config.project.name}
|
642
|
-
- #{config.project.name}::my_plan
|
643
|
-
MESSAGE
|
644
|
-
|
645
|
-
raise Bolt::ValidationError, message
|
646
|
-
end
|
647
|
-
|
648
|
-
prefix, *name_segments, basename = plan_name.split('::')
|
649
|
-
|
650
|
-
# If the plan name is just the project name, then create an 'init' plan.
|
651
|
-
# Otherwise, use the last name segment for the plan's filename.
|
652
|
-
basename ||= 'init'
|
653
|
-
|
654
|
-
unless prefix == config.project.name
|
655
|
-
message = "First segment of plan name '#{plan_name}' must match project name '#{config.project.name}'. "\
|
656
|
-
"Did you mean '#{config.project.name}::#{plan_name}'?"
|
657
|
-
|
658
|
-
raise Bolt::ValidationError, message
|
659
|
-
end
|
660
|
-
|
661
|
-
dir_path = config.project.plans_path.join(*name_segments)
|
662
|
-
|
663
|
-
%w[pp yaml].each do |ext|
|
664
|
-
next unless (path = config.project.plans_path + "#{basename}.#{ext}").exist?
|
665
|
-
raise Bolt::Error.new(
|
666
|
-
"A plan with the name '#{plan_name}' already exists at '#{path}', nothing to do.",
|
667
|
-
'bolt/existing-plan-error'
|
668
|
-
)
|
669
|
-
end
|
670
|
-
|
671
|
-
begin
|
672
|
-
FileUtils.mkdir_p(dir_path)
|
673
|
-
rescue Errno::EEXIST => e
|
674
|
-
raise Bolt::Error.new(
|
675
|
-
"#{e.message}; unable to create plan directory '#{dir_path}'",
|
676
|
-
'bolt/existing-file-error'
|
677
|
-
)
|
678
|
-
end
|
679
|
-
|
680
|
-
plan_path = dir_path + "#{basename}.yaml"
|
681
|
-
|
682
|
-
plan_template = <<~PLAN
|
683
|
-
# This is the structure of a simple plan. To learn more about writing
|
684
|
-
# YAML plans, see the documentation: http://pup.pt/bolt-yaml-plans
|
685
|
-
|
686
|
-
# The description sets the description of the plan that will appear
|
687
|
-
# in 'bolt plan show' output.
|
688
|
-
description: A plan created with bolt plan new
|
689
|
-
|
690
|
-
# The parameters key defines the parameters that can be passed to
|
691
|
-
# the plan.
|
692
|
-
parameters:
|
693
|
-
targets:
|
694
|
-
type: TargetSpec
|
695
|
-
description: A list of targets to run actions on
|
696
|
-
default: localhost
|
697
|
-
|
698
|
-
# The steps key defines the actions the plan will take in order.
|
699
|
-
steps:
|
700
|
-
- message: Hello from #{plan_name}
|
701
|
-
- name: command_step
|
702
|
-
command: whoami
|
703
|
-
targets: $targets
|
704
|
-
|
705
|
-
# The return key sets the return value of the plan.
|
706
|
-
return: $command_step
|
707
|
-
PLAN
|
708
|
-
|
709
|
-
begin
|
710
|
-
File.write(plan_path, plan_template)
|
711
|
-
rescue Errno::EACCES => e
|
712
|
-
raise Bolt::FileError.new(
|
713
|
-
"#{e.message}; unable to create plan",
|
714
|
-
plan_path
|
715
|
-
)
|
716
|
-
end
|
717
|
-
|
718
|
-
output = <<~OUTPUT
|
719
|
-
Created plan '#{plan_name}' at '#{plan_path}'
|
720
|
-
|
721
|
-
Show this plan with:
|
722
|
-
bolt plan show #{plan_name}
|
723
|
-
Run this plan with:
|
724
|
-
bolt plan run #{plan_name}
|
725
|
-
OUTPUT
|
726
|
-
|
727
|
-
outputter.print_message(output)
|
728
|
-
|
729
|
-
0
|
730
|
-
end
|
731
|
-
|
732
626
|
def run_plan(plan_name, plan_arguments, nodes, options)
|
733
627
|
unless nodes.empty?
|
734
628
|
if plan_arguments['nodes'] || plan_arguments['targets']
|
@@ -820,88 +714,22 @@ module Bolt
|
|
820
714
|
end
|
821
715
|
|
822
716
|
def list_modules
|
717
|
+
assert_puppetfile_or_module_command(config.project.modules)
|
823
718
|
outputter.print_module_list(pal.list_modules)
|
824
719
|
end
|
825
720
|
|
826
721
|
def generate_types
|
722
|
+
assert_puppetfile_or_module_command(config.project.modules)
|
827
723
|
# generate_types will surface a nice error with helpful message if it fails
|
828
724
|
pal.generate_types
|
829
725
|
0
|
830
726
|
end
|
831
727
|
|
832
|
-
# Initializes a specified directory as a Bolt project and installs any modules
|
833
|
-
# specified by the user, along with their dependencies
|
834
|
-
def initialize_project
|
835
|
-
# Dir.pwd will return backslashes on Windows, but Pathname always uses
|
836
|
-
# forward slashes to concatenate paths. This results in paths like
|
837
|
-
# C:\User\Administrator/modules, which fail module install. This ensure
|
838
|
-
# forward slashes in the cwd path.
|
839
|
-
dir = File.expand_path(Dir.pwd)
|
840
|
-
name = options[:object] || File.basename(dir)
|
841
|
-
if name !~ Bolt::Module::MODULE_NAME_REGEX
|
842
|
-
if options[:object]
|
843
|
-
raise Bolt::ValidationError, "The provided project name '#{name}' is invalid; "\
|
844
|
-
"project name must begin with a lowercase letter and can include lowercase "\
|
845
|
-
"letters, numbers, and underscores."
|
846
|
-
else
|
847
|
-
raise Bolt::ValidationError, "The current directory name '#{name}' is an invalid "\
|
848
|
-
"project name. Please specify a name using 'bolt project init <name>'."
|
849
|
-
end
|
850
|
-
end
|
851
|
-
|
852
|
-
project = Pathname.new(dir)
|
853
|
-
old_config = project + 'bolt.yaml'
|
854
|
-
config = project + 'bolt-project.yaml'
|
855
|
-
puppetfile = project + 'Puppetfile'
|
856
|
-
moduledir = project + 'modules'
|
857
|
-
|
858
|
-
# Warn the user if the project directory already exists. We don't error
|
859
|
-
# here since users might not have installed any modules yet. If both
|
860
|
-
# bolt.yaml and bolt-project.yaml exist, this will just warn about
|
861
|
-
# bolt-project.yaml and subsequent Bolt actions will warn about both files
|
862
|
-
# existing.
|
863
|
-
if config.exist?
|
864
|
-
@logger.warn "Found existing project directory at #{project}. Skipping file creation."
|
865
|
-
elsif old_config.exist?
|
866
|
-
@logger.warn "Found existing #{old_config.basename} at #{project}. "\
|
867
|
-
"#{old_config.basename} is deprecated, please rename to #{config.basename}."
|
868
|
-
end
|
869
|
-
|
870
|
-
# If modules were specified, first check if there is already a Puppetfile
|
871
|
-
# at the project directory, erroring if there is. If there is no
|
872
|
-
# Puppetfile, install the specified modules. The module installer will
|
873
|
-
# resolve dependencies, generate a Puppetfile, and install the modules.
|
874
|
-
if options[:modules]
|
875
|
-
if puppetfile.exist?
|
876
|
-
raise Bolt::CLIError,
|
877
|
-
"Found existing Puppetfile at #{puppetfile}, unable to initialize "\
|
878
|
-
"project with modules."
|
879
|
-
end
|
880
|
-
|
881
|
-
installer = Bolt::ModuleInstaller.new(outputter, pal)
|
882
|
-
installer.install(options[:modules], puppetfile, moduledir)
|
883
|
-
end
|
884
|
-
|
885
|
-
# If either bolt.yaml or bolt-project.yaml exist, the user has already
|
886
|
-
# been warned and we can just finish project creation. Otherwise, create a
|
887
|
-
# bolt-project.yaml with the project name in it.
|
888
|
-
unless config.exist? || old_config.exist?
|
889
|
-
begin
|
890
|
-
content = { 'name' => name }
|
891
|
-
File.write(config.to_path, content.to_yaml)
|
892
|
-
outputter.print_message "Successfully created Bolt project at #{project}"
|
893
|
-
rescue StandardError => e
|
894
|
-
raise Bolt::FileError.new("Could not create bolt-project.yaml at #{project}: #{e.message}", nil)
|
895
|
-
end
|
896
|
-
end
|
897
|
-
|
898
|
-
0
|
899
|
-
end
|
900
|
-
|
901
728
|
# Installs modules declared in the project configuration file.
|
902
729
|
#
|
903
730
|
def install_project_modules(project, force, resolve)
|
904
731
|
assert_project_file(project)
|
732
|
+
assert_puppetfile_or_module_command(project.modules)
|
905
733
|
|
906
734
|
unless project.modules
|
907
735
|
outputter.print_message "Project configuration file #{project.project_file} does not "\
|
@@ -923,6 +751,7 @@ module Bolt
|
|
923
751
|
#
|
924
752
|
def add_project_module(name, project)
|
925
753
|
assert_project_file(project)
|
754
|
+
assert_puppetfile_or_module_command(project.modules)
|
926
755
|
|
927
756
|
modules = project.modules || []
|
928
757
|
installer = Bolt::ModuleInstaller.new(outputter, pal)
|
@@ -940,11 +769,13 @@ module Bolt
|
|
940
769
|
def assert_project_file(project)
|
941
770
|
unless project.project_file?
|
942
771
|
msg = if project.config_file.exist?
|
772
|
+
command = Bolt::Util.powershell? ? 'Update-BoltProject' : 'bolt project migrate'
|
943
773
|
"Detected Bolt configuration file #{project.config_file}, unable to install "\
|
944
|
-
"modules. To update to a project configuration file, run '
|
774
|
+
"modules. To update to a project configuration file, run '#{command}'."
|
945
775
|
else
|
776
|
+
command = Bolt::Util.powershell? ? 'New-BoltProject' : 'bolt project init'
|
946
777
|
"Could not find project configuration file #{project.project_file}, unable "\
|
947
|
-
"to install modules. To create a Bolt project, run '
|
778
|
+
"to install modules. To create a Bolt project, run '#{command}'."
|
948
779
|
end
|
949
780
|
|
950
781
|
raise Bolt::Error.new(msg, 'bolt/missing-project-config-error')
|
@@ -953,10 +784,12 @@ module Bolt
|
|
953
784
|
|
954
785
|
# Loads a Puppetfile and installs its modules.
|
955
786
|
#
|
956
|
-
def install_puppetfile(
|
787
|
+
def install_puppetfile(puppetfile_config, puppetfile, moduledir)
|
788
|
+
assert_puppetfile_or_module_command(config.project.modules)
|
789
|
+
|
957
790
|
outputter.print_message("Installing modules from Puppetfile")
|
958
791
|
installer = Bolt::ModuleInstaller.new(outputter, pal)
|
959
|
-
ok = installer.install_puppetfile(puppetfile, moduledir,
|
792
|
+
ok = installer.install_puppetfile(puppetfile, moduledir, puppetfile_config)
|
960
793
|
ok ? 0 : 1
|
961
794
|
end
|
962
795
|
|
@@ -964,17 +797,36 @@ module Bolt
|
|
964
797
|
# modules being configured.
|
965
798
|
#
|
966
799
|
def assert_puppetfile_or_module_command(modules)
|
800
|
+
if Bolt::Util.powershell?
|
801
|
+
case options[:action]
|
802
|
+
when 'generate-types'
|
803
|
+
old_command = 'Register-BoltPuppetfileTypes'
|
804
|
+
new_command = 'Register-BoltModuleTypes'
|
805
|
+
when 'install'
|
806
|
+
old_command = 'Install-BoltPuppetfile'
|
807
|
+
new_command = 'Install-BoltModule'
|
808
|
+
when 'show', 'show-modules'
|
809
|
+
old_command = 'Get-BoltPuppetfileModules'
|
810
|
+
new_command = 'Get-BoltModule'
|
811
|
+
end
|
812
|
+
else
|
813
|
+
old_command = "bolt puppetfile #{options[:action]}"
|
814
|
+
new_command = if options[:action] == 'show-modules'
|
815
|
+
'bolt module show'
|
816
|
+
else
|
817
|
+
"bolt module #{options[:action]}"
|
818
|
+
end
|
819
|
+
end
|
820
|
+
|
967
821
|
if modules && options[:subcommand] == 'puppetfile'
|
968
822
|
raise Bolt::CLIError,
|
969
|
-
"Unable to use command '
|
970
|
-
"
|
971
|
-
"instead. For a list of available actions for the 'module' command, run "\
|
972
|
-
"'bolt module --help'."
|
823
|
+
"Unable to use command '#{old_command}' when 'modules' is configured in "\
|
824
|
+
"bolt-project.yaml. Use '#{new_command}' instead."
|
973
825
|
elsif modules.nil? && options[:subcommand] == 'module'
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
826
|
+
msg = "Unable to use command '#{new_command}' when 'modules' is not configured in "\
|
827
|
+
"bolt-project.yaml. "
|
828
|
+
msg += "Use '#{old_command}' instead." if options[:action] != 'add'
|
829
|
+
raise Bolt::CLIError, msg
|
978
830
|
end
|
979
831
|
end
|
980
832
|
|