bolt 2.35.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/bolt-modules/boltlib/lib/puppet/datatypes/applyresult.rb +1 -0
- data/lib/bolt/analytics.rb +27 -8
- data/lib/bolt/apply_result.rb +3 -3
- data/lib/bolt/bolt_option_parser.rb +38 -15
- data/lib/bolt/cli.rb +13 -87
- data/lib/bolt/config.rb +131 -52
- data/lib/bolt/config/options.rb +42 -4
- data/lib/bolt/config/transport/base.rb +10 -19
- data/lib/bolt/config/transport/local.rb +0 -7
- data/lib/bolt/config/transport/ssh.rb +8 -14
- data/lib/bolt/config/validator.rb +231 -0
- data/lib/bolt/executor.rb +5 -17
- data/lib/bolt/outputter/rainbow.rb +1 -1
- data/lib/bolt/plugin.rb +0 -7
- 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} +41 -4
- data/lib/bolt/{project_migrator/inventory.rb → project_manager/inventory_migrator.rb} +3 -3
- 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/config.rb +1 -2
- data/lib/bolt/shell/bash.rb +1 -1
- data/lib/bolt/task/run.rb +1 -1
- data/lib/bolt/transport/ssh/exec_connection.rb +6 -2
- data/lib/bolt/util.rb +14 -7
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/base_config.rb +3 -1
- data/lib/bolt_server/config.rb +3 -1
- data/lib/bolt_server/schemas/partials/task.json +2 -2
- data/lib/bolt_server/transport_app.rb +5 -5
- data/libexec/apply_catalog.rb +1 -1
- data/libexec/custom_facts.rb +1 -1
- data/libexec/query_resources.rb +1 -1
- metadata +8 -13
- data/lib/bolt/project_migrator.rb +0 -80
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1881e4097a89e606b9326f93e2e6fd9d934a7db1eb8609e6f9a09ffa322ac7c4
|
4
|
+
data.tar.gz: '02509b1919e57f137bf4e868332be3b73238d22d83251680dc29c7c93ef90a19'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1fc1215430ac99b765c24c87ee210afb03a247a6c0baac9af3b00e34d56cfb58bacb2140dcfafbe197fd655602713463e2697c2df5083c259b66c8d8cd7bc112
|
7
|
+
data.tar.gz: 445a5f77a5beaf8a1a3c4cb2193e973ada23cb4a7a5f3a8caba2ccc47be4fc8a8fdef3ba797e082c0df3b9553c2f2e67c06084f2c2b2684347d2b9a86e45bde0
|
data/lib/bolt/analytics.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'bolt/util'
|
4
4
|
require 'bolt/version'
|
5
|
+
require 'find'
|
5
6
|
require 'json'
|
6
7
|
require 'logging'
|
7
8
|
require 'securerandom'
|
@@ -23,14 +24,16 @@ module Bolt
|
|
23
24
|
plan_steps: :cd8,
|
24
25
|
return_type: :cd9,
|
25
26
|
inventory_version: :cd10,
|
26
|
-
boltdir_type: :cd11
|
27
|
+
boltdir_type: :cd11,
|
28
|
+
puppet_plan_count: :cd12,
|
29
|
+
yaml_plan_count: :cd13
|
27
30
|
}.freeze
|
28
31
|
|
29
32
|
def self.build_client
|
30
33
|
logger = Bolt::Logger.logger(self)
|
31
34
|
begin
|
32
|
-
config_file = config_path
|
33
|
-
config = load_config(config_file
|
35
|
+
config_file = config_path
|
36
|
+
config = load_config(config_file)
|
34
37
|
rescue ArgumentError
|
35
38
|
config = { 'disabled' => true }
|
36
39
|
end
|
@@ -51,7 +54,7 @@ module Bolt
|
|
51
54
|
NoopClient.new
|
52
55
|
end
|
53
56
|
|
54
|
-
def self.config_path
|
57
|
+
def self.config_path
|
55
58
|
path = File.expand_path(File.join('~', '.puppetlabs', 'etc', 'bolt', 'analytics.yaml'))
|
56
59
|
old_path = File.expand_path(File.join('~', '.puppetlabs', 'bolt', 'analytics.yaml'))
|
57
60
|
|
@@ -59,7 +62,7 @@ module Bolt
|
|
59
62
|
if File.exist?(old_path)
|
60
63
|
message = "Detected analytics configuration files at '#{old_path}' and '#{path}'. Loading "\
|
61
64
|
"analytics configuration from '#{path}'."
|
62
|
-
|
65
|
+
Bolt::Logger.warn_once('duplicate_analytics', message)
|
63
66
|
end
|
64
67
|
|
65
68
|
path
|
@@ -70,12 +73,12 @@ module Bolt
|
|
70
73
|
end
|
71
74
|
end
|
72
75
|
|
73
|
-
def self.load_config(filename
|
76
|
+
def self.load_config(filename)
|
74
77
|
if File.exist?(filename)
|
75
78
|
Bolt::Util.read_optional_yaml_hash(filename, 'analytics')
|
76
79
|
else
|
77
80
|
unless ENV['BOLT_DISABLE_ANALYTICS']
|
78
|
-
|
81
|
+
Bolt::Logger.warn_once('analytics_opt_out', <<~ANALYTICS)
|
79
82
|
Bolt collects data about how you use it. You can opt out of providing this data.
|
80
83
|
|
81
84
|
To disable analytics data collection, add this line to ~/.puppetlabs/etc/bolt/analytics.yaml :
|
@@ -134,11 +137,23 @@ module Bolt
|
|
134
137
|
end
|
135
138
|
|
136
139
|
def report_bundled_content(mode, name)
|
137
|
-
if bundled_content[mode.split
|
140
|
+
if bundled_content[mode.split.first]&.include?(name)
|
138
141
|
event('Bundled Content', mode, label: name)
|
139
142
|
end
|
140
143
|
end
|
141
144
|
|
145
|
+
def plan_counts(plans_path)
|
146
|
+
pp_count, yaml_count = if File.exist?(plans_path)
|
147
|
+
%w[pp yaml].map do |extension|
|
148
|
+
Find.find(plans_path.to_s).grep(/.*\.#{extension}/).length
|
149
|
+
end
|
150
|
+
else
|
151
|
+
[0, 0]
|
152
|
+
end
|
153
|
+
|
154
|
+
{ puppet_plan_count: pp_count, yaml_plan_count: yaml_count }
|
155
|
+
end
|
156
|
+
|
142
157
|
def event(category, action, label: nil, value: nil, **kwargs)
|
143
158
|
custom_dimensions = Bolt::Util.walk_keys(kwargs) do |k|
|
144
159
|
CUSTOM_DIMENSIONS[k] || raise("Unknown analytics key '#{k}'")
|
@@ -224,6 +239,10 @@ module Bolt
|
|
224
239
|
|
225
240
|
def report_bundled_content(mode, name); end
|
226
241
|
|
242
|
+
def plan_counts(_)
|
243
|
+
{}
|
244
|
+
end
|
245
|
+
|
227
246
|
def event(category, action, **_kwargs)
|
228
247
|
@logger.trace "Skipping submission of '#{category} #{action}' event because analytics is disabled"
|
229
248
|
end
|
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
|
data/lib/bolt/cli.rb
CHANGED
@@ -21,7 +21,7 @@ require 'bolt/outputter'
|
|
21
21
|
require 'bolt/pal'
|
22
22
|
require 'bolt/plan_creator'
|
23
23
|
require 'bolt/plugin'
|
24
|
-
require 'bolt/
|
24
|
+
require 'bolt/project_manager'
|
25
25
|
require 'bolt/puppetdb'
|
26
26
|
require 'bolt/rerun'
|
27
27
|
require 'bolt/secret'
|
@@ -30,6 +30,7 @@ require 'bolt/version'
|
|
30
30
|
|
31
31
|
module Bolt
|
32
32
|
class CLIExit < StandardError; end
|
33
|
+
|
33
34
|
class CLI
|
34
35
|
COMMANDS = {
|
35
36
|
'command' => %w[run],
|
@@ -164,8 +165,9 @@ module Bolt
|
|
164
165
|
elsif options[:configfile]
|
165
166
|
Bolt::Config.from_file(options[:configfile], options)
|
166
167
|
else
|
167
|
-
|
168
|
-
|
168
|
+
cli_flag = options[:project] || options[:boltdir]
|
169
|
+
project = if cli_flag
|
170
|
+
dir = Pathname.new(cli_flag)
|
169
171
|
if (dir + Bolt::Project::BOLTDIR_NAME).directory?
|
170
172
|
Bolt::Project.create_project(dir + Bolt::Project::BOLTDIR_NAME)
|
171
173
|
else
|
@@ -293,7 +295,7 @@ module Bolt
|
|
293
295
|
"Unknown argument(s) #{options[:leftovers].join(', ')}"
|
294
296
|
end
|
295
297
|
|
296
|
-
if options
|
298
|
+
if options.slice(:boltdir, :configfile, :project).length > 1
|
297
299
|
raise Bolt::CLIError, "Only one of '--boltdir', '--project', or '--configfile' may be specified"
|
298
300
|
end
|
299
301
|
|
@@ -340,15 +342,10 @@ module Bolt
|
|
340
342
|
def warn_inventory_overrides_cli(opts)
|
341
343
|
inventory_source = if ENV[Bolt::Inventory::ENVIRONMENT_VAR]
|
342
344
|
Bolt::Inventory::ENVIRONMENT_VAR
|
343
|
-
elsif config.inventoryfile
|
345
|
+
elsif config.inventoryfile
|
344
346
|
config.inventoryfile
|
345
|
-
|
346
|
-
|
347
|
-
Bolt::Util.file_stat(config.default_inventoryfile)
|
348
|
-
config.default_inventoryfile
|
349
|
-
rescue Errno::ENOENT
|
350
|
-
nil
|
351
|
-
end
|
347
|
+
elsif File.exist?(config.default_inventoryfile)
|
348
|
+
config.default_inventoryfile
|
352
349
|
end
|
353
350
|
|
354
351
|
inventory_cli_opts = %i[authentication escalation transports].each_with_object([]) do |key, acc|
|
@@ -392,7 +389,7 @@ module Bolt
|
|
392
389
|
output_format: config.format,
|
393
390
|
# For continuity
|
394
391
|
boltdir_type: config.project.type
|
395
|
-
}
|
392
|
+
}.merge!(analytics.plan_counts(config.project.plans_path))
|
396
393
|
|
397
394
|
# Only include target and inventory info for commands that take a targets
|
398
395
|
# list. This avoids loading inventory for commands that don't need it.
|
@@ -456,15 +453,14 @@ module Bolt
|
|
456
453
|
when 'project'
|
457
454
|
case options[:action]
|
458
455
|
when 'init'
|
459
|
-
code =
|
456
|
+
code = Bolt::ProjectManager.new(config, outputter, pal)
|
457
|
+
.create(Dir.pwd, options[:object], options[:modules])
|
460
458
|
when 'migrate'
|
461
|
-
code = Bolt::
|
459
|
+
code = Bolt::ProjectManager.new(config, outputter, pal).migrate
|
462
460
|
end
|
463
461
|
when 'plan'
|
464
462
|
case options[:action]
|
465
463
|
when 'new'
|
466
|
-
command = Bolt::Util.powershell? ? 'New-BoltPlan' : 'bolt plan new'
|
467
|
-
@logger.warn("Command '#{command}' is experimental and subject to changes.")
|
468
464
|
plan_name = options[:object]
|
469
465
|
|
470
466
|
# If this passes validation, it will return the path to the plan to create
|
@@ -729,76 +725,6 @@ module Bolt
|
|
729
725
|
0
|
730
726
|
end
|
731
727
|
|
732
|
-
# Initializes a specified directory as a Bolt project and installs any modules
|
733
|
-
# specified by the user, along with their dependencies
|
734
|
-
def initialize_project
|
735
|
-
# Dir.pwd will return backslashes on Windows, but Pathname always uses
|
736
|
-
# forward slashes to concatenate paths. This results in paths like
|
737
|
-
# C:\User\Administrator/modules, which fail module install. This ensure
|
738
|
-
# forward slashes in the cwd path.
|
739
|
-
dir = File.expand_path(Dir.pwd)
|
740
|
-
name = options[:object] || File.basename(dir)
|
741
|
-
if name !~ Bolt::Module::MODULE_NAME_REGEX
|
742
|
-
if options[:object]
|
743
|
-
raise Bolt::ValidationError, "The provided project name '#{name}' is invalid; "\
|
744
|
-
"project name must begin with a lowercase letter and can include lowercase "\
|
745
|
-
"letters, numbers, and underscores."
|
746
|
-
else
|
747
|
-
command = Bolt::Util.powershell? ? 'New-BoltProject -Name <NAME>' : 'bolt project init <NAME>'
|
748
|
-
raise Bolt::ValidationError, "The current directory name '#{name}' is an invalid "\
|
749
|
-
"project name. Please specify a name using '#{command}'."
|
750
|
-
end
|
751
|
-
end
|
752
|
-
|
753
|
-
project = Pathname.new(dir)
|
754
|
-
old_config = project + 'bolt.yaml'
|
755
|
-
config = project + 'bolt-project.yaml'
|
756
|
-
puppetfile = project + 'Puppetfile'
|
757
|
-
moduledir = project + 'modules'
|
758
|
-
|
759
|
-
# Warn the user if the project directory already exists. We don't error
|
760
|
-
# here since users might not have installed any modules yet. If both
|
761
|
-
# bolt.yaml and bolt-project.yaml exist, this will just warn about
|
762
|
-
# bolt-project.yaml and subsequent Bolt actions will warn about both files
|
763
|
-
# existing.
|
764
|
-
if config.exist?
|
765
|
-
@logger.warn "Found existing project directory at #{project}. Skipping file creation."
|
766
|
-
elsif old_config.exist?
|
767
|
-
@logger.warn "Found existing #{old_config.basename} at #{project}. "\
|
768
|
-
"#{old_config.basename} is deprecated, please rename to #{config.basename}."
|
769
|
-
end
|
770
|
-
|
771
|
-
# If modules were specified, first check if there is already a Puppetfile
|
772
|
-
# at the project directory, erroring if there is. If there is no
|
773
|
-
# Puppetfile, install the specified modules. The module installer will
|
774
|
-
# resolve dependencies, generate a Puppetfile, and install the modules.
|
775
|
-
if options[:modules]
|
776
|
-
if puppetfile.exist?
|
777
|
-
raise Bolt::CLIError,
|
778
|
-
"Found existing Puppetfile at #{puppetfile}, unable to initialize "\
|
779
|
-
"project with modules."
|
780
|
-
end
|
781
|
-
|
782
|
-
installer = Bolt::ModuleInstaller.new(outputter, pal)
|
783
|
-
installer.install(options[:modules], puppetfile, moduledir)
|
784
|
-
end
|
785
|
-
|
786
|
-
# If either bolt.yaml or bolt-project.yaml exist, the user has already
|
787
|
-
# been warned and we can just finish project creation. Otherwise, create a
|
788
|
-
# bolt-project.yaml with the project name in it.
|
789
|
-
unless config.exist? || old_config.exist?
|
790
|
-
begin
|
791
|
-
content = { 'name' => name }
|
792
|
-
File.write(config.to_path, content.to_yaml)
|
793
|
-
outputter.print_message "Successfully created Bolt project at #{project}"
|
794
|
-
rescue StandardError => e
|
795
|
-
raise Bolt::FileError.new("Could not create bolt-project.yaml at #{project}: #{e.message}", nil)
|
796
|
-
end
|
797
|
-
end
|
798
|
-
|
799
|
-
0
|
800
|
-
end
|
801
|
-
|
802
728
|
# Installs modules declared in the project configuration file.
|
803
729
|
#
|
804
730
|
def install_project_modules(project, force, resolve)
|
data/lib/bolt/config.rb
CHANGED
@@ -7,6 +7,7 @@ require 'bolt/project'
|
|
7
7
|
require 'bolt/logger'
|
8
8
|
require 'bolt/util'
|
9
9
|
require 'bolt/config/options'
|
10
|
+
require 'bolt/config/validator'
|
10
11
|
|
11
12
|
module Bolt
|
12
13
|
class UnknownTransportError < Bolt::Error
|
@@ -32,53 +33,97 @@ module Bolt
|
|
32
33
|
end
|
33
34
|
|
34
35
|
def self.from_project(project, overrides = {})
|
35
|
-
logs
|
36
|
+
logs = []
|
37
|
+
deprecations = []
|
38
|
+
|
36
39
|
conf = if project.project_file == project.config_file
|
37
40
|
project.data
|
38
41
|
else
|
39
42
|
c = Bolt::Util.read_optional_yaml_hash(project.config_file, 'config')
|
43
|
+
|
44
|
+
# Validate the config against the schema. This will raise a single error
|
45
|
+
# with all validation errors.
|
46
|
+
Validator.new.tap do |validator|
|
47
|
+
validator.validate(c, bolt_schema, project.config_file.to_s)
|
48
|
+
|
49
|
+
validator.warnings.each { |warning| logs << { warn: warning } }
|
50
|
+
|
51
|
+
validator.deprecations.each do |dep|
|
52
|
+
deprecations << { type: "#{BOLT_CONFIG_NAME} #{dep[:option]}", msg: dep[:message] }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
40
56
|
logs << { debug: "Loaded configuration from #{project.config_file}" } if File.exist?(project.config_file)
|
41
57
|
c
|
42
58
|
end
|
43
59
|
|
44
60
|
data = load_defaults(project).push(
|
45
|
-
filepath:
|
46
|
-
data:
|
47
|
-
logs:
|
48
|
-
deprecations:
|
61
|
+
filepath: project.config_file,
|
62
|
+
data: conf,
|
63
|
+
logs: logs,
|
64
|
+
deprecations: deprecations
|
49
65
|
)
|
50
66
|
|
51
67
|
new(project, data, overrides)
|
52
68
|
end
|
53
69
|
|
54
70
|
def self.from_file(configfile, overrides = {})
|
55
|
-
project
|
56
|
-
logs
|
71
|
+
project = Bolt::Project.create_project(Pathname.new(configfile).expand_path.dirname)
|
72
|
+
logs = []
|
73
|
+
deprecations = []
|
57
74
|
|
58
75
|
conf = if project.project_file == project.config_file
|
59
76
|
project.data
|
60
77
|
else
|
61
78
|
c = Bolt::Util.read_yaml_hash(configfile, 'config')
|
79
|
+
|
80
|
+
# Validate the config against the schema. This will raise a single error
|
81
|
+
# with all validation errors.
|
82
|
+
Validator.new.tap do |validator|
|
83
|
+
validator.validate(c, bolt_schema, project.config_file.to_s)
|
84
|
+
|
85
|
+
validator.warnings.each { |warning| logs << { warn: warning } }
|
86
|
+
|
87
|
+
validator.deprecations.each do |dep|
|
88
|
+
deprecations << { type: "#{BOLT_CONFIG_NAME} #{dep[:option]}", msg: dep[:message] }
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
62
92
|
logs << { debug: "Loaded configuration from #{configfile}" }
|
63
93
|
c
|
64
94
|
end
|
65
95
|
|
66
96
|
data = load_defaults(project).push(
|
67
|
-
filepath:
|
68
|
-
data:
|
69
|
-
logs:
|
70
|
-
deprecations:
|
97
|
+
filepath: configfile,
|
98
|
+
data: conf,
|
99
|
+
logs: logs,
|
100
|
+
deprecations: deprecations
|
71
101
|
)
|
72
102
|
|
73
103
|
new(project, data, overrides)
|
74
104
|
end
|
75
105
|
|
76
|
-
def self.
|
77
|
-
|
78
|
-
|
106
|
+
def self.defaults_schema
|
107
|
+
base = OPTIONS.slice(*BOLT_DEFAULTS_OPTIONS)
|
108
|
+
inventory = INVENTORY_OPTIONS.each_with_object({}) do |(option, definition), acc|
|
109
|
+
acc[option] = TRANSPORT_CONFIG.key?(option) ? definition.merge(TRANSPORT_CONFIG[option].schema) : definition
|
110
|
+
end
|
111
|
+
|
112
|
+
base['inventory-config'][:properties] = inventory
|
113
|
+
base
|
114
|
+
end
|
79
115
|
|
116
|
+
def self.bolt_schema
|
117
|
+
inventory = INVENTORY_OPTIONS.each_with_object({}) do |(option, definition), acc|
|
118
|
+
acc[option] = TRANSPORT_CONFIG.key?(option) ? definition.merge(TRANSPORT_CONFIG[option].schema) : definition
|
119
|
+
end
|
120
|
+
|
121
|
+
OPTIONS.slice(*BOLT_OPTIONS).merge(inventory)
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.system_path
|
80
125
|
if Bolt::Util.windows?
|
81
|
-
Pathname.new(File.join(
|
126
|
+
Pathname.new(File.join(ENV['ALLUSERSPROFILE'], 'PuppetLabs', 'bolt', 'etc'))
|
82
127
|
else
|
83
128
|
Pathname.new(File.join('/etc', 'puppetlabs', 'bolt'))
|
84
129
|
end
|
@@ -94,9 +139,10 @@ module Bolt
|
|
94
139
|
# projects. This file does not allow project-specific configuration such as 'hiera-config' and
|
95
140
|
# 'inventoryfile', and nests all default inventory configuration under an 'inventory-config' key.
|
96
141
|
def self.load_bolt_defaults_yaml(dir)
|
97
|
-
filepath
|
98
|
-
data
|
99
|
-
logs
|
142
|
+
filepath = dir + BOLT_DEFAULTS_NAME
|
143
|
+
data = Bolt::Util.read_yaml_hash(filepath, 'config')
|
144
|
+
logs = [{ debug: "Loaded configuration from #{filepath}" }]
|
145
|
+
deprecations = []
|
100
146
|
|
101
147
|
# Warn if 'bolt.yaml' detected in same directory.
|
102
148
|
if File.exist?(bolt_yaml = dir + BOLT_CONFIG_NAME)
|
@@ -106,6 +152,18 @@ module Bolt
|
|
106
152
|
)
|
107
153
|
end
|
108
154
|
|
155
|
+
# Validate the config against the schema. This will raise a single error
|
156
|
+
# with all validation errors.
|
157
|
+
Validator.new.tap do |validator|
|
158
|
+
validator.validate(data, defaults_schema, filepath)
|
159
|
+
|
160
|
+
validator.warnings.each { |warning| logs << { warn: warning } }
|
161
|
+
|
162
|
+
validator.deprecations.each do |dep|
|
163
|
+
deprecations << { type: "#{BOLT_DEFAULTS_NAME} #{dep[:option]}", msg: dep[:message] }
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
109
167
|
# Remove project-specific config such as hiera-config, etc.
|
110
168
|
project_config = data.slice(*(BOLT_PROJECT_OPTIONS - BOLT_DEFAULTS_OPTIONS))
|
111
169
|
|
@@ -148,19 +206,31 @@ module Bolt
|
|
148
206
|
data = data.merge(data.delete('inventory-config'))
|
149
207
|
end
|
150
208
|
|
151
|
-
{ filepath: filepath, data: data, logs: logs, deprecations:
|
209
|
+
{ filepath: filepath, data: data, logs: logs, deprecations: deprecations }
|
152
210
|
end
|
153
211
|
|
154
212
|
# Loads a 'bolt.yaml' file, the legacy configuration file. There's no special munging needed
|
155
213
|
# here since Bolt::Config will just ignore any invalid keys.
|
156
214
|
def self.load_bolt_yaml(dir)
|
157
|
-
filepath
|
158
|
-
data
|
159
|
-
logs
|
215
|
+
filepath = dir + BOLT_CONFIG_NAME
|
216
|
+
data = Bolt::Util.read_yaml_hash(filepath, 'config')
|
217
|
+
logs = [{ debug: "Loaded configuration from #{filepath}" }]
|
160
218
|
deprecations = [{ type: 'Using bolt.yaml for system configuration',
|
161
219
|
msg: "Configuration file #{filepath} is deprecated and will be removed in a future version "\
|
162
220
|
"of Bolt. Use '#{dir + BOLT_DEFAULTS_NAME}' instead." }]
|
163
221
|
|
222
|
+
# Validate the config against the schema. This will raise a single error
|
223
|
+
# with all validation errors.
|
224
|
+
Validator.new.tap do |validator|
|
225
|
+
validator.validate(data, bolt_schema, filepath)
|
226
|
+
|
227
|
+
validator.warnings.each { |warning| logs << { warn: warning } }
|
228
|
+
|
229
|
+
validator.deprecations.each do |dep|
|
230
|
+
deprecations << { type: "#{BOLT_CONFIG_NAME} #{dep[:option]}", msg: dep[:message] }
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
164
234
|
{ filepath: filepath, data: data, logs: logs, deprecations: deprecations }
|
165
235
|
end
|
166
236
|
|
@@ -206,12 +276,14 @@ module Bolt
|
|
206
276
|
@config_files = []
|
207
277
|
|
208
278
|
default_data = {
|
279
|
+
'apply-settings' => {},
|
209
280
|
'apply_settings' => {},
|
210
281
|
'color' => true,
|
211
282
|
'compile-concurrency' => Etc.nprocessors,
|
212
283
|
'concurrency' => default_concurrency,
|
213
284
|
'format' => 'human',
|
214
285
|
'log' => { 'console' => {} },
|
286
|
+
'plugin-hooks' => {},
|
215
287
|
'plugin_hooks' => {},
|
216
288
|
'plugins' => {},
|
217
289
|
'puppetdb' => {},
|
@@ -271,7 +343,7 @@ module Bolt
|
|
271
343
|
|
272
344
|
# Set console log to debug if in debug mode
|
273
345
|
if options[:debug]
|
274
|
-
overrides['log'] = { 'console' => { 'level' =>
|
346
|
+
overrides['log'] = { 'console' => { 'level' => 'debug' } }
|
275
347
|
end
|
276
348
|
|
277
349
|
if options[:puppetfile_path]
|
@@ -280,6 +352,9 @@ module Bolt
|
|
280
352
|
|
281
353
|
overrides['trace'] = opts['trace'] if opts.key?('trace')
|
282
354
|
|
355
|
+
# Validate the overrides
|
356
|
+
Validator.new.validate(overrides, OPTIONS, 'command line')
|
357
|
+
|
283
358
|
overrides
|
284
359
|
end
|
285
360
|
|
@@ -296,7 +371,7 @@ module Bolt
|
|
296
371
|
when *TRANSPORT_CONFIG.keys
|
297
372
|
Bolt::Util.deep_merge(val1, val2)
|
298
373
|
# Hash values are shallow merged
|
299
|
-
when 'puppetdb', 'plugin_hooks', 'apply_settings', 'log'
|
374
|
+
when 'puppetdb', 'plugin-hooks', 'plugin_hooks', 'apply-settings', 'apply_settings', 'log'
|
300
375
|
val1.merge(val2)
|
301
376
|
# All other values are overwritten
|
302
377
|
else
|
@@ -333,8 +408,9 @@ module Bolt
|
|
333
408
|
end
|
334
409
|
|
335
410
|
# Filter hashes to only include valid options
|
336
|
-
|
337
|
-
|
411
|
+
%w[apply-settings apply_settings puppetfile].each do |opt|
|
412
|
+
@data[opt] = @data[opt].slice(*OPTIONS.dig(opt, :properties).keys)
|
413
|
+
end
|
338
414
|
end
|
339
415
|
|
340
416
|
private def normalize_log(target)
|
@@ -397,37 +473,18 @@ module Bolt
|
|
397
473
|
"is automatically appended to the modulepath and cannot be configured."
|
398
474
|
end
|
399
475
|
|
400
|
-
keys = OPTIONS.keys - %w[plugins plugin_hooks puppetdb]
|
401
|
-
keys.each do |key|
|
402
|
-
next unless Bolt::Util.references?(@data[key])
|
403
|
-
valid_keys = TRANSPORT_CONFIG.keys + %w[plugins plugin_hooks puppetdb]
|
404
|
-
raise Bolt::ValidationError,
|
405
|
-
"Found unsupported key _plugin in config setting #{key}. Plugins are only available in "\
|
406
|
-
"#{valid_keys.join(', ')}."
|
407
|
-
end
|
408
|
-
|
409
|
-
unless concurrency.is_a?(Integer) && concurrency > 0
|
410
|
-
raise Bolt::ValidationError,
|
411
|
-
"Concurrency must be a positive Integer, received #{concurrency.class} #{concurrency}"
|
412
|
-
end
|
413
|
-
|
414
|
-
unless compile_concurrency.is_a?(Integer) && compile_concurrency > 0
|
415
|
-
raise Bolt::ValidationError,
|
416
|
-
"Compile concurrency must be a positive Integer, received #{compile_concurrency.class} "\
|
417
|
-
"#{compile_concurrency}"
|
418
|
-
end
|
419
|
-
|
420
476
|
compile_limit = 2 * Etc.nprocessors
|
421
477
|
unless compile_concurrency < compile_limit
|
422
478
|
raise Bolt::ValidationError, "Compilation is CPU-intensive, set concurrency less than #{compile_limit}"
|
423
479
|
end
|
424
480
|
|
425
|
-
|
426
|
-
|
481
|
+
%w[hiera-config trusted-external-command inventoryfile].each do |opt|
|
482
|
+
Bolt::Util.validate_file(opt, @data[opt]) if @data[opt]
|
427
483
|
end
|
428
484
|
|
429
|
-
|
430
|
-
|
485
|
+
if File.exist?(default_inventoryfile)
|
486
|
+
Bolt::Util.validate_file('inventory file', default_inventoryfile)
|
487
|
+
end
|
431
488
|
|
432
489
|
unless TRANSPORT_CONFIG.include?(transport)
|
433
490
|
raise UnknownTransportError, transport
|
@@ -513,7 +570,18 @@ module Bolt
|
|
513
570
|
end
|
514
571
|
|
515
572
|
def plugin_hooks
|
516
|
-
@data['plugin_hooks']
|
573
|
+
if @data['plugin-hooks'].any? && @data['plugin_hooks'].any?
|
574
|
+
Bolt::Logger.warn_once(
|
575
|
+
"plugin-hooks and plugin_hooks set",
|
576
|
+
"Detected configuration for 'plugin-hooks' and 'plugin_hooks'. Bolt will ignore 'plugin_hooks'."
|
577
|
+
)
|
578
|
+
|
579
|
+
@data['plugin-hooks']
|
580
|
+
elsif @data['plugin-hooks'].any?
|
581
|
+
@data['plugin-hooks']
|
582
|
+
else
|
583
|
+
@data['plugin_hooks']
|
584
|
+
end
|
517
585
|
end
|
518
586
|
|
519
587
|
def trusted_external
|
@@ -521,7 +589,18 @@ module Bolt
|
|
521
589
|
end
|
522
590
|
|
523
591
|
def apply_settings
|
524
|
-
@data['apply_settings']
|
592
|
+
if @data['apply-settings'].any? && @data['apply_settings'].any?
|
593
|
+
Bolt::Logger.warn_once(
|
594
|
+
"apply-settings and apply_settings set",
|
595
|
+
"Detected configuration for 'apply-settings' and 'apply_settings'. Bolt will ignore 'apply_settings'."
|
596
|
+
)
|
597
|
+
|
598
|
+
@data['apply-settings']
|
599
|
+
elsif @data['apply-settings'].any?
|
600
|
+
@data['apply-settings']
|
601
|
+
else
|
602
|
+
@data['apply_settings']
|
603
|
+
end
|
525
604
|
end
|
526
605
|
|
527
606
|
def transport
|