bolt 2.21.0 → 2.22.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/lib/bolt/bolt_option_parser.rb +21 -3
- data/lib/bolt/catalog.rb +9 -1
- data/lib/bolt/cli.rb +128 -12
- data/lib/bolt/module.rb +2 -1
- data/lib/bolt/project.rb +6 -6
- data/lib/bolt/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 60e995704052fee2778474c532df844e51ca0888017e28c883866e6b61a9678f
|
4
|
+
data.tar.gz: 8133b33137d67ba8880270f4ed20aa8346e13b2aa7ae2b0c390e3fbbba660172
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a057aebe5bd7ce01a8369f3c7a05371f0dab79143cd465f6bd2f0a0ad23fe897fcff6624d03f07ead07b86c888512166232182c294cd1188fcd8fb45b55f463d
|
7
|
+
data.tar.gz: 4c30348d86636398f25568dcd77af25e6eb8e54af5c9ce44125a110b8089c15415a4a051aa8aac066f7404f9ca7faf253dd69e350780ef8d24e34f385c1dd8de
|
@@ -66,6 +66,9 @@ module Bolt
|
|
66
66
|
when 'convert'
|
67
67
|
{ flags: OPTIONS[:global] + OPTIONS[:global_config_setters],
|
68
68
|
banner: PLAN_CONVERT_HELP }
|
69
|
+
when 'new'
|
70
|
+
{ flags: OPTIONS[:global] + %w[configfile project],
|
71
|
+
banner: PLAN_NEW_HELP }
|
69
72
|
when 'run'
|
70
73
|
{ flags: ACTION_OPTS + %w[params compile-concurrency tmpdir hiera-config],
|
71
74
|
banner: PLAN_RUN_HELP }
|
@@ -159,10 +162,10 @@ module Bolt
|
|
159
162
|
SUBCOMMANDS
|
160
163
|
apply Apply Puppet manifest code
|
161
164
|
command Run a command remotely
|
162
|
-
file
|
165
|
+
file Copy files between the controller and targets
|
163
166
|
group Show the list of groups in the inventory
|
164
167
|
inventory Show the list of targets an action would run on
|
165
|
-
plan Convert, show, and run Bolt plans
|
168
|
+
plan Convert, create, show, and run Bolt plans
|
166
169
|
project Create and migrate Bolt projects
|
167
170
|
puppetfile Install and list modules and generate type references
|
168
171
|
script Upload a local script and run it remotely
|
@@ -319,10 +322,11 @@ module Bolt
|
|
319
322
|
bolt plan <action> [parameters] [options]
|
320
323
|
|
321
324
|
DESCRIPTION
|
322
|
-
Convert, show, and run Bolt plans.
|
325
|
+
Convert, create, show, and run Bolt plans.
|
323
326
|
|
324
327
|
ACTIONS
|
325
328
|
convert Convert a YAML plan to a Bolt plan
|
329
|
+
new Create a new plan in the current project
|
326
330
|
run Run a plan on the specified targets
|
327
331
|
show Show available plans and plan documentation
|
328
332
|
HELP
|
@@ -345,6 +349,20 @@ module Bolt
|
|
345
349
|
bolt plan convert path/to/plan/myplan.yaml
|
346
350
|
HELP
|
347
351
|
|
352
|
+
PLAN_NEW_HELP = <<~HELP
|
353
|
+
NAME
|
354
|
+
new
|
355
|
+
|
356
|
+
USAGE
|
357
|
+
bolt plan new <plan> [options]
|
358
|
+
|
359
|
+
DESCRIPTION
|
360
|
+
Create a new plan in the current project.
|
361
|
+
|
362
|
+
EXAMPLES
|
363
|
+
bolt plan new myproject::myplan
|
364
|
+
HELP
|
365
|
+
|
348
366
|
PLAN_RUN_HELP = <<~HELP
|
349
367
|
NAME
|
350
368
|
run
|
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
@@ -31,7 +31,7 @@ module Bolt
|
|
31
31
|
COMMANDS = { 'command' => %w[run],
|
32
32
|
'script' => %w[run],
|
33
33
|
'task' => %w[show run],
|
34
|
-
'plan' => %w[show run convert],
|
34
|
+
'plan' => %w[show run convert new],
|
35
35
|
'file' => %w[download upload],
|
36
36
|
'puppetfile' => %w[install show-modules generate-types],
|
37
37
|
'secret' => %w[encrypt decrypt createkeys],
|
@@ -283,6 +283,10 @@ module Bolt
|
|
283
283
|
raise Bolt::CLIError, "Must specify a value to #{options[:action]}"
|
284
284
|
end
|
285
285
|
|
286
|
+
if options[:subcommand] == 'plan' && options[:action] == 'new' && !options[:object]
|
287
|
+
raise Bolt::CLIError, "Must specify a plan name."
|
288
|
+
end
|
289
|
+
|
286
290
|
if options.key?(:debug) && options.key?(:log)
|
287
291
|
raise Bolt::CLIError, "Only one of '--debug' or '--log-level' may be specified"
|
288
292
|
end
|
@@ -350,19 +354,11 @@ module Bolt
|
|
350
354
|
# Initialize inventory and targets. Errors here are better to catch early.
|
351
355
|
# options[:target_args] will contain a string/array version of the targetting options this is passed to plans
|
352
356
|
# options[:targets] will contain a resolved set of Target objects
|
353
|
-
unless options[:subcommand]
|
354
|
-
options[:
|
355
|
-
options[:subcommand] == 'project' ||
|
356
|
-
options[:action] == 'show' ||
|
357
|
-
options[:action] == 'convert'
|
357
|
+
unless %w[project puppetfile secret].include?(options[:subcommand]) ||
|
358
|
+
%w[convert new show].include?(options[:action])
|
358
359
|
update_targets(options)
|
359
360
|
end
|
360
361
|
|
361
|
-
if options[:action] == 'convert'
|
362
|
-
convert_plan(options[:object])
|
363
|
-
return 0
|
364
|
-
end
|
365
|
-
|
366
362
|
screen = "#{options[:subcommand]}_#{options[:action]}"
|
367
363
|
# submit a different screen for `bolt task show` and `bolt task show foo`
|
368
364
|
if options[:action] == 'show' && options[:object]
|
@@ -414,6 +410,9 @@ module Bolt
|
|
414
410
|
when 'show-modules'
|
415
411
|
list_modules
|
416
412
|
return 0
|
413
|
+
when 'convert'
|
414
|
+
convert_plan(options[:object])
|
415
|
+
return 0
|
417
416
|
end
|
418
417
|
|
419
418
|
message = 'There may be processes left executing on some nodes.'
|
@@ -431,7 +430,12 @@ module Bolt
|
|
431
430
|
code = migrate_project
|
432
431
|
end
|
433
432
|
when 'plan'
|
434
|
-
|
433
|
+
case options[:action]
|
434
|
+
when 'new'
|
435
|
+
code = new_plan(options[:object])
|
436
|
+
when 'run'
|
437
|
+
code = run_plan(options[:object], options[:task_options], options[:target_args], options)
|
438
|
+
end
|
435
439
|
when 'puppetfile'
|
436
440
|
case options[:action]
|
437
441
|
when 'generate-types'
|
@@ -551,6 +555,118 @@ module Bolt
|
|
551
555
|
outputter.print_groups(groups)
|
552
556
|
end
|
553
557
|
|
558
|
+
def new_plan(plan_name)
|
559
|
+
@logger.warn("Command 'bolt plan new' is experimental and subject to changes.")
|
560
|
+
|
561
|
+
if config.project.name.nil?
|
562
|
+
raise Bolt::Error.new(
|
563
|
+
"Project directory '#{config.project.path}' is not a named project. Unable to create "\
|
564
|
+
"a project-level plan. To name a project, set the 'name' key in the 'bolt-project.yaml' "\
|
565
|
+
"configuration file.",
|
566
|
+
"bolt/unnamed-project-error"
|
567
|
+
)
|
568
|
+
end
|
569
|
+
|
570
|
+
if plan_name !~ Bolt::Module::CONTENT_NAME_REGEX
|
571
|
+
message = <<~MESSAGE.chomp
|
572
|
+
Invalid plan name '#{plan_name}'. Plan names are composed of one or more name segments
|
573
|
+
separated by double colons '::'.
|
574
|
+
|
575
|
+
Each name segment must begin with a lowercase letter, and may only include lowercase
|
576
|
+
letters, digits, and underscores.
|
577
|
+
|
578
|
+
Examples of valid plan names:
|
579
|
+
- #{config.project.name}
|
580
|
+
- #{config.project.name}::my_plan
|
581
|
+
MESSAGE
|
582
|
+
|
583
|
+
raise Bolt::ValidationError, message
|
584
|
+
end
|
585
|
+
|
586
|
+
prefix, *name_segments, basename = plan_name.split('::')
|
587
|
+
|
588
|
+
# If the plan name is just the project name, then create an 'init' plan.
|
589
|
+
# Otherwise, use the last name segment for the plan's filename.
|
590
|
+
basename ||= 'init'
|
591
|
+
|
592
|
+
unless prefix == config.project.name
|
593
|
+
message = "First segment of plan name '#{plan_name}' must match project name '#{config.project.name}'. "\
|
594
|
+
"Did you mean '#{config.project.name}::#{plan_name}'?"
|
595
|
+
|
596
|
+
raise Bolt::ValidationError, message
|
597
|
+
end
|
598
|
+
|
599
|
+
dir_path = config.project.plans_path.join(*name_segments)
|
600
|
+
|
601
|
+
%w[pp yaml].each do |ext|
|
602
|
+
next unless (path = config.project.plans_path + "#{basename}.#{ext}").exist?
|
603
|
+
raise Bolt::Error.new(
|
604
|
+
"A plan with the name '#{plan_name}' already exists at '#{path}', nothing to do.",
|
605
|
+
'bolt/existing-plan-error'
|
606
|
+
)
|
607
|
+
end
|
608
|
+
|
609
|
+
begin
|
610
|
+
FileUtils.mkdir_p(dir_path)
|
611
|
+
rescue Errno::EEXIST => e
|
612
|
+
raise Bolt::Error.new(
|
613
|
+
"#{e.message}; unable to create plan directory '#{dir_path}'",
|
614
|
+
'bolt/existing-file-error'
|
615
|
+
)
|
616
|
+
end
|
617
|
+
|
618
|
+
plan_path = dir_path + "#{basename}.yaml"
|
619
|
+
|
620
|
+
plan_template = <<~PLAN
|
621
|
+
# This is the structure of a simple plan. To learn more about writing
|
622
|
+
# YAML plans, see the documentation: http://pup.pt/bolt-yaml-plans
|
623
|
+
|
624
|
+
# The description sets the description of the plan that will appear
|
625
|
+
# in 'bolt plan show' output.
|
626
|
+
description: A plan created with bolt plan new
|
627
|
+
|
628
|
+
# The parameters key defines the parameters that can be passed to
|
629
|
+
# the plan.
|
630
|
+
parameters:
|
631
|
+
targets:
|
632
|
+
type: TargetSpec
|
633
|
+
description: A list of targets to run actions on
|
634
|
+
default: localhost
|
635
|
+
|
636
|
+
# The steps key defines the actions the plan will take in order.
|
637
|
+
steps:
|
638
|
+
- message: Hello from #{plan_name}
|
639
|
+
- name: command_step
|
640
|
+
command: whoami
|
641
|
+
targets: $targets
|
642
|
+
|
643
|
+
# The return key sets the return value of the plan.
|
644
|
+
return: $command_step
|
645
|
+
PLAN
|
646
|
+
|
647
|
+
begin
|
648
|
+
File.write(plan_path, plan_template)
|
649
|
+
rescue Errno::EACCES => e
|
650
|
+
raise Bolt::FileError.new(
|
651
|
+
"#{e.message}; unable to create plan",
|
652
|
+
plan_path
|
653
|
+
)
|
654
|
+
end
|
655
|
+
|
656
|
+
output = <<~OUTPUT
|
657
|
+
Created plan '#{plan_name}' at '#{plan_path}'
|
658
|
+
|
659
|
+
Show this plan with:
|
660
|
+
bolt plan show #{plan_name}
|
661
|
+
Run this plan with:
|
662
|
+
bolt plan run #{plan_name}
|
663
|
+
OUTPUT
|
664
|
+
|
665
|
+
outputter.print_message(output)
|
666
|
+
|
667
|
+
0
|
668
|
+
end
|
669
|
+
|
554
670
|
def run_plan(plan_name, plan_arguments, nodes, options)
|
555
671
|
unless nodes.empty?
|
556
672
|
if plan_arguments['nodes'] || plan_arguments['targets']
|
data/lib/bolt/module.rb
CHANGED
@@ -3,7 +3,8 @@
|
|
3
3
|
# Is this Bolt::Pobs::Module?
|
4
4
|
module Bolt
|
5
5
|
class Module
|
6
|
-
|
6
|
+
CONTENT_NAME_REGEX = /\A[a-z][a-z0-9_]*(::[a-z][a-z0-9_]*)*\z/.freeze
|
7
|
+
MODULE_NAME_REGEX = /\A[a-z][a-z0-9_]*\z/.freeze
|
7
8
|
|
8
9
|
def self.discover(modulepath)
|
9
10
|
modulepath.each_with_object({}) do |path, mods|
|
data/lib/bolt/project.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'pathname'
|
4
4
|
require 'bolt/config'
|
5
5
|
require 'bolt/pal'
|
6
|
+
require 'bolt/module'
|
6
7
|
|
7
8
|
module Bolt
|
8
9
|
class Project
|
@@ -17,7 +18,7 @@ module Bolt
|
|
17
18
|
|
18
19
|
attr_reader :path, :data, :config_file, :inventory_file, :modulepath, :hiera_config,
|
19
20
|
:puppetfile, :rerunfile, :type, :resource_types, :warnings, :project_file,
|
20
|
-
:deprecations, :downloads
|
21
|
+
:deprecations, :downloads, :plans_path
|
21
22
|
|
22
23
|
def self.default_project
|
23
24
|
create_project(File.expand_path(File.join('~', '.puppetlabs', 'bolt')), 'user')
|
@@ -82,6 +83,7 @@ module Bolt
|
|
82
83
|
@resource_types = @path + '.resource_types'
|
83
84
|
@type = type
|
84
85
|
@downloads = @path + 'downloads'
|
86
|
+
@plans_path = @path + 'plans'
|
85
87
|
|
86
88
|
tc = Bolt::Config::INVENTORY_OPTIONS.keys & raw_data.keys
|
87
89
|
if tc.any?
|
@@ -138,11 +140,9 @@ module Bolt
|
|
138
140
|
|
139
141
|
def validate
|
140
142
|
if name
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
Invalid project name '#{name}' in bolt-project.yaml; project name must match #{name_regex.inspect}
|
145
|
-
ERROR_STRING
|
143
|
+
if name !~ Bolt::Module::MODULE_NAME_REGEX
|
144
|
+
raise Bolt::ValidationError, "Invalid project name #{name.inspect.tr('"', "'")} in bolt-project.yaml; "\
|
145
|
+
"project name must match #{Bolt::Module::MODULE_NAME_REGEX.inspect}"
|
146
146
|
elsif Dir.children(Bolt::PAL::BOLTLIB_PATH).include?(name)
|
147
147
|
raise Bolt::ValidationError, "The project '#{name}' will not be loaded. The project name conflicts "\
|
148
148
|
"with a built-in Bolt module of the same name."
|
data/lib/bolt/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bolt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.22.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Puppet
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-08-
|
11
|
+
date: 2020-08-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|