bolt 2.24.0 → 2.28.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 +1 -1
- data/bolt-modules/boltlib/lib/puppet/datatypes/result.rb +2 -1
- data/bolt-modules/boltlib/lib/puppet/functions/download_file.rb +1 -1
- data/bolt-modules/dir/lib/puppet/functions/dir/children.rb +1 -1
- data/lib/bolt/analytics.rb +7 -3
- data/lib/bolt/applicator.rb +21 -21
- data/lib/bolt/bolt_option_parser.rb +75 -7
- data/lib/bolt/catalog.rb +4 -2
- data/lib/bolt/cli.rb +126 -147
- data/lib/bolt/config.rb +56 -26
- data/lib/bolt/config/options.rb +24 -2
- data/lib/bolt/executor.rb +1 -1
- data/lib/bolt/inventory.rb +8 -1
- data/lib/bolt/inventory/group.rb +1 -1
- data/lib/bolt/inventory/inventory.rb +1 -1
- data/lib/bolt/inventory/target.rb +1 -1
- data/lib/bolt/logger.rb +9 -2
- data/lib/bolt/outputter/logger.rb +1 -1
- data/lib/bolt/pal.rb +21 -10
- data/lib/bolt/pal/yaml_plan/evaluator.rb +1 -1
- data/lib/bolt/plugin/puppetdb.rb +1 -1
- data/lib/bolt/project.rb +63 -17
- data/lib/bolt/puppetdb/client.rb +1 -1
- data/lib/bolt/puppetdb/config.rb +1 -1
- data/lib/bolt/puppetfile.rb +160 -0
- data/lib/bolt/puppetfile/installer.rb +43 -0
- data/lib/bolt/puppetfile/module.rb +66 -0
- data/lib/bolt/r10k_log_proxy.rb +1 -1
- data/lib/bolt/rerun.rb +2 -2
- data/lib/bolt/result.rb +23 -0
- data/lib/bolt/shell.rb +1 -1
- data/lib/bolt/task.rb +1 -1
- data/lib/bolt/transport/base.rb +5 -5
- data/lib/bolt/transport/docker/connection.rb +1 -1
- data/lib/bolt/transport/local/connection.rb +1 -1
- data/lib/bolt/transport/ssh.rb +1 -1
- data/lib/bolt/transport/ssh/connection.rb +1 -1
- data/lib/bolt/transport/ssh/exec_connection.rb +1 -1
- data/lib/bolt/transport/winrm.rb +1 -1
- data/lib/bolt/transport/winrm/connection.rb +1 -1
- data/lib/bolt/util.rb +11 -11
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/base_config.rb +1 -1
- data/lib/bolt_server/config.rb +1 -1
- data/lib/bolt_server/file_cache.rb +12 -12
- data/lib/bolt_server/transport_app.rb +125 -26
- data/lib/bolt_spec/bolt_context.rb +4 -4
- data/lib/bolt_spec/run.rb +3 -0
- metadata +9 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 03de2a7e4d6fa0b9d4120fff783ccb009665077c7b00e910f5e2de14c03a1767
|
4
|
+
data.tar.gz: 511e18c31228338f47519ee02a7b248f4d264b93516a58aa1b063a41bb835e80
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1956edc3051eae34d25957c7827ce1e1f12bfc7e322d9305a79d9a2cb32cf144309413626cfb9db6667193a8853810dabf8d6004924ad3899633a220f34cecb7
|
7
|
+
data.tar.gz: af2e40875cb54c1e2b4153605ffc6abb6b11a65e2f0abcc30f7eb87701cb3c5c023905dc1709ff0bf7261e856ceaae29fad9df13e4b9b51b9f74a4ef65fb0b74
|
data/Puppetfile
CHANGED
@@ -6,7 +6,7 @@ moduledir File.join(File.dirname(__FILE__), 'modules')
|
|
6
6
|
|
7
7
|
# Core modules used by 'apply'
|
8
8
|
mod 'puppetlabs-service', '1.3.0'
|
9
|
-
mod 'puppetlabs-puppet_agent', '
|
9
|
+
mod 'puppetlabs-puppet_agent', '4.1.1'
|
10
10
|
mod 'puppetlabs-facts', '1.0.0'
|
11
11
|
|
12
12
|
# Core types and providers for Puppet 6
|
@@ -9,11 +9,12 @@ Puppet::DataTypes.create_type('Result') do
|
|
9
9
|
functions => {
|
10
10
|
error => Callable[[], Optional[Error]],
|
11
11
|
message => Callable[[], Optional[String]],
|
12
|
+
sensitive => Callable[[], Optional[Sensitive[Data]]],
|
12
13
|
action => Callable[[], String],
|
13
14
|
status => Callable[[], String],
|
14
15
|
to_data => Callable[[], Hash],
|
15
16
|
ok => Callable[[], Boolean],
|
16
|
-
'[]' => Callable[[String[1]], Data]
|
17
|
+
'[]' => Callable[[String[1]], Variant[Data, Sensitive[Data]]]
|
17
18
|
}
|
18
19
|
PUPPET
|
19
20
|
|
@@ -96,7 +96,7 @@ Puppet::Functions.create_function(:download_file, Puppet::Functions::InternalFun
|
|
96
96
|
|
97
97
|
# Paths expand relative to the default downloads directory for the project
|
98
98
|
# e.g. ~/.puppetlabs/bolt/downloads/
|
99
|
-
destination = Puppet.lookup(:
|
99
|
+
destination = Puppet.lookup(:bolt_project).downloads + destination
|
100
100
|
|
101
101
|
# If the destination directory already exists, delete any existing contents
|
102
102
|
if Dir.exist?(destination)
|
@@ -25,7 +25,7 @@ Puppet::Functions.create_function(:'dir::children', Puppet::Functions::InternalF
|
|
25
25
|
full_mod_path = File.join(mod_path, subpath || '') if mod_path
|
26
26
|
|
27
27
|
# Expand relative to the project directory if path is relative
|
28
|
-
project = Puppet.lookup(:
|
28
|
+
project = Puppet.lookup(:bolt_project)
|
29
29
|
pathname = Pathname.new(dirname)
|
30
30
|
full_dir = pathname.absolute? ? dirname : File.expand_path(File.join(project.path, dirname))
|
31
31
|
|
data/lib/bolt/analytics.rb
CHANGED
@@ -27,7 +27,7 @@ module Bolt
|
|
27
27
|
}.freeze
|
28
28
|
|
29
29
|
def self.build_client
|
30
|
-
logger =
|
30
|
+
logger = Bolt::Logger.logger(self)
|
31
31
|
begin
|
32
32
|
config_file = config_path(logger)
|
33
33
|
config = load_config(config_file, logger)
|
@@ -93,6 +93,10 @@ module Bolt
|
|
93
93
|
def self.write_config(filename, config)
|
94
94
|
FileUtils.mkdir_p(File.dirname(filename))
|
95
95
|
File.write(filename, config.to_yaml)
|
96
|
+
rescue StandardError => e
|
97
|
+
Bolt::Logger.warn_once('unwriteable_file', "Could not write analytics configuration to #{filename}.")
|
98
|
+
# This will get caught by build_client and create a NoopClient
|
99
|
+
raise e
|
96
100
|
end
|
97
101
|
|
98
102
|
class Client
|
@@ -106,7 +110,7 @@ module Bolt
|
|
106
110
|
require 'httpclient'
|
107
111
|
require 'locale'
|
108
112
|
|
109
|
-
@logger =
|
113
|
+
@logger = Bolt::Logger.logger(self)
|
110
114
|
@http = HTTPClient.new
|
111
115
|
@user_id = user_id
|
112
116
|
@executor = Concurrent.global_io_executor
|
@@ -210,7 +214,7 @@ module Bolt
|
|
210
214
|
attr_accessor :bundled_content
|
211
215
|
|
212
216
|
def initialize
|
213
|
-
@logger =
|
217
|
+
@logger = Bolt::Logger.logger(self)
|
214
218
|
@bundled_content = []
|
215
219
|
end
|
216
220
|
|
data/lib/bolt/applicator.rb
CHANGED
@@ -28,7 +28,7 @@ module Bolt
|
|
28
28
|
@apply_settings = apply_settings || {}
|
29
29
|
|
30
30
|
@pool = Concurrent::ThreadPoolExecutor.new(name: 'apply', max_threads: max_compiles)
|
31
|
-
@logger =
|
31
|
+
@logger = Bolt::Logger.logger(self)
|
32
32
|
end
|
33
33
|
|
34
34
|
private def libexec
|
@@ -50,15 +50,15 @@ module Bolt
|
|
50
50
|
|
51
51
|
def catalog_apply_task
|
52
52
|
@catalog_apply_task ||= begin
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
53
|
+
path = File.join(libexec, 'apply_catalog.rb')
|
54
|
+
file = { 'name' => 'apply_catalog.rb', 'path' => path }
|
55
|
+
metadata = { 'supports_noop' => true, 'input_method' => 'stdin',
|
56
|
+
'implementations' => [
|
57
|
+
{ 'name' => 'apply_catalog.rb' },
|
58
|
+
{ 'name' => 'apply_catalog.rb', 'remote' => true }
|
59
|
+
] }
|
60
|
+
Bolt::Task.new('apply_helpers::apply_catalog', metadata, [file])
|
61
|
+
end
|
62
62
|
end
|
63
63
|
|
64
64
|
def query_resources_task
|
@@ -75,34 +75,35 @@ module Bolt
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
-
def compile(target,
|
78
|
+
def compile(target, scope)
|
79
79
|
# This simplified Puppet node object is what .local uses to determine the
|
80
80
|
# certname of the target
|
81
81
|
node = Puppet::Node.from_data_hash('name' => target.name,
|
82
82
|
'parameters' => { 'clientcert' => target.name })
|
83
83
|
trusted = Puppet::Context::TrustedInformation.local(node)
|
84
|
-
|
84
|
+
target_data = {
|
85
85
|
name: target.name,
|
86
86
|
facts: @inventory.facts(target).merge('bolt' => true),
|
87
87
|
variables: @inventory.vars(target),
|
88
88
|
trusted: trusted.to_h
|
89
89
|
}
|
90
|
+
catalog_request = scope.merge(target: target_data)
|
90
91
|
|
91
92
|
bolt_catalog_exe = File.join(libexec, 'bolt_catalog')
|
92
93
|
old_path = ENV['PATH']
|
93
94
|
ENV['PATH'] = "#{RbConfig::CONFIG['bindir']}#{File::PATH_SEPARATOR}#{old_path}"
|
94
|
-
out, err, stat = Open3.capture3('ruby', bolt_catalog_exe, 'compile', stdin_data:
|
95
|
+
out, err, stat = Open3.capture3('ruby', bolt_catalog_exe, 'compile', stdin_data: catalog_request.to_json)
|
95
96
|
ENV['PATH'] = old_path
|
96
97
|
|
97
98
|
# If bolt_catalog does not return valid JSON, we should print stderr to
|
98
99
|
# see what happened
|
99
100
|
print_logs = stat.success?
|
100
101
|
result = begin
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
102
|
+
JSON.parse(out)
|
103
|
+
rescue JSON::ParserError
|
104
|
+
print_logs = true
|
105
|
+
{ 'message' => "Something's gone terribly wrong! STDERR is logged." }
|
106
|
+
end
|
106
107
|
|
107
108
|
# Any messages logged by Puppet will be on stderr as JSON hashes, so we
|
108
109
|
# parse those and store them here. Any message on stderr that is not
|
@@ -183,17 +184,16 @@ module Bolt
|
|
183
184
|
type_by_reference: true,
|
184
185
|
local_reference: true)
|
185
186
|
|
186
|
-
bolt_project = @project if @project&.name
|
187
187
|
scope = {
|
188
188
|
code_ast: ast,
|
189
189
|
modulepath: @modulepath,
|
190
|
-
project:
|
190
|
+
project: @project.to_h,
|
191
191
|
pdb_config: @pdb_client.config.to_hash,
|
192
192
|
hiera_config: @hiera_config,
|
193
193
|
plan_vars: plan_vars,
|
194
194
|
# This data isn't available on the target config hash
|
195
195
|
config: @inventory.transport_data_get
|
196
|
-
}
|
196
|
+
}.freeze
|
197
197
|
description = options[:description] || 'apply catalog'
|
198
198
|
|
199
199
|
required_modules = options[:required_modules].nil? ? nil : Array(options[:required_modules])
|
@@ -64,6 +64,21 @@ module Bolt
|
|
64
64
|
when 'guide'
|
65
65
|
{ flags: OPTIONS[:global] + %w[format],
|
66
66
|
banner: GUIDE_HELP }
|
67
|
+
when 'module'
|
68
|
+
case action
|
69
|
+
when 'install'
|
70
|
+
{ flags: OPTIONS[:global] + %w[configfile force project],
|
71
|
+
banner: MODULE_INSTALL_HELP }
|
72
|
+
when 'show'
|
73
|
+
{ flags: OPTIONS[:global] + OPTIONS[:global_config_setters],
|
74
|
+
banner: MODULE_SHOW_HELP }
|
75
|
+
when 'generate-types'
|
76
|
+
{ flags: OPTIONS[:global] + OPTIONS[:global_config_setters],
|
77
|
+
banner: MODULE_GENERATETYPES_HELP }
|
78
|
+
else
|
79
|
+
{ flags: OPTIONS[:global],
|
80
|
+
banner: MODULE_HELP }
|
81
|
+
end
|
67
82
|
when 'plan'
|
68
83
|
case action
|
69
84
|
when 'convert'
|
@@ -341,6 +356,59 @@ module Bolt
|
|
341
356
|
Show the list of targets an action would run on.
|
342
357
|
HELP
|
343
358
|
|
359
|
+
MODULE_HELP = <<~HELP
|
360
|
+
NAME
|
361
|
+
module
|
362
|
+
|
363
|
+
USAGE
|
364
|
+
bolt module <action> [options]
|
365
|
+
|
366
|
+
DESCRIPTION
|
367
|
+
Install and list modules and generate type references
|
368
|
+
|
369
|
+
ACTIONS
|
370
|
+
generate-types Generate type references to register in plans
|
371
|
+
install Install the project's modules
|
372
|
+
show List modules available to the Bolt project
|
373
|
+
HELP
|
374
|
+
|
375
|
+
MODULE_INSTALL_HELP = <<~HELP
|
376
|
+
NAME
|
377
|
+
install
|
378
|
+
|
379
|
+
USAGE
|
380
|
+
bolt module install [options]
|
381
|
+
|
382
|
+
DESCRIPTION
|
383
|
+
Install the project's modules.
|
384
|
+
|
385
|
+
Module declarations are loaded from the project's configuration
|
386
|
+
file. Bolt will automatically resolve all module dependencies,
|
387
|
+
generate a Puppetfile, and install the modules.
|
388
|
+
HELP
|
389
|
+
|
390
|
+
MODULE_GENERATETYPES_HELP = <<~HELP
|
391
|
+
NAME
|
392
|
+
generate-types
|
393
|
+
|
394
|
+
USAGE
|
395
|
+
bolt module generate-types [options]
|
396
|
+
|
397
|
+
DESCRIPTION
|
398
|
+
Generate type references to register in plans.
|
399
|
+
HELP
|
400
|
+
|
401
|
+
MODULE_SHOW_HELP = <<~HELP
|
402
|
+
NAME
|
403
|
+
show
|
404
|
+
|
405
|
+
USAGE
|
406
|
+
bolt module show [options]
|
407
|
+
|
408
|
+
DESCRIPTION
|
409
|
+
List modules available to the Bolt project.
|
410
|
+
HELP
|
411
|
+
|
344
412
|
PLAN_HELP = <<~HELP
|
345
413
|
NAME
|
346
414
|
plan
|
@@ -366,11 +434,11 @@ module Bolt
|
|
366
434
|
bolt plan convert <path> [options]
|
367
435
|
|
368
436
|
DESCRIPTION
|
369
|
-
Convert a YAML plan to a
|
437
|
+
Convert a YAML plan to a Puppet language plan and print the converted plan to stdout.
|
370
438
|
|
371
439
|
Converting a YAML plan may result in a plan that is syntactically
|
372
440
|
correct but has different behavior. Always verify a converted plan's
|
373
|
-
functionality.
|
441
|
+
functionality. Note that the converted plan is not written to a file.
|
374
442
|
|
375
443
|
EXAMPLES
|
376
444
|
bolt plan convert path/to/plan/myplan.yaml
|
@@ -421,9 +489,9 @@ module Bolt
|
|
421
489
|
the plan, including a list of available parameters.
|
422
490
|
|
423
491
|
EXAMPLES
|
424
|
-
Display a list of available
|
492
|
+
Display a list of available plans
|
425
493
|
bolt plan show
|
426
|
-
Display documentation for the
|
494
|
+
Display documentation for the aggregate::count plan
|
427
495
|
bolt plan show aggregate::count
|
428
496
|
HELP
|
429
497
|
|
@@ -828,7 +896,7 @@ module Bolt
|
|
828
896
|
"This option is experimental.") do |exec|
|
829
897
|
@options[:'copy-command'] = exec
|
830
898
|
end
|
831
|
-
define('--connect-timeout TIMEOUT', Integer, 'Connection timeout (defaults vary)') do |timeout|
|
899
|
+
define('--connect-timeout TIMEOUT', Integer, 'Connection timeout in seconds (defaults vary)') do |timeout|
|
832
900
|
@options[:'connect-timeout'] = timeout
|
833
901
|
end
|
834
902
|
define('--[no-]tty', 'Request a pseudo TTY on targets that support it') do |tty|
|
@@ -864,9 +932,9 @@ module Bolt
|
|
864
932
|
define('--modules MODULES',
|
865
933
|
'A comma-separated list of modules to install from the Puppet Forge',
|
866
934
|
'when initializing a project. Resolves and installs all dependencies.') do |modules|
|
867
|
-
@options[:modules] = modules.split(',')
|
935
|
+
@options[:modules] = modules.split(',').map { |mod| { 'name' => mod } }
|
868
936
|
end
|
869
|
-
define('--force', '
|
937
|
+
define('--force', 'Force a destructive action') do |_force|
|
870
938
|
@options[:force] = true
|
871
939
|
end
|
872
940
|
|
data/lib/bolt/catalog.rb
CHANGED
@@ -57,8 +57,10 @@ module Bolt
|
|
57
57
|
|
58
58
|
def compile_catalog(request)
|
59
59
|
pdb_client = Bolt::PuppetDB::Client.new(Bolt::PuppetDB::Config.new(request['pdb_config']))
|
60
|
-
project = request['project']
|
61
|
-
bolt_project = Struct.new(:name, :path).new(project['name'],
|
60
|
+
project = request['project']
|
61
|
+
bolt_project = Struct.new(:name, :path, :load_as_module?).new(project['name'],
|
62
|
+
project['path'],
|
63
|
+
project['load_as_module?'])
|
62
64
|
inv = Bolt::ApplyInventory.new(request['config'])
|
63
65
|
puppet_overrides = {
|
64
66
|
bolt_pdb_client: pdb_client,
|
data/lib/bolt/cli.rb
CHANGED
@@ -40,13 +40,14 @@ module Bolt
|
|
40
40
|
'group' => %w[show],
|
41
41
|
'project' => %w[init migrate],
|
42
42
|
'apply' => %w[],
|
43
|
-
'guide' => %w[]
|
43
|
+
'guide' => %w[],
|
44
|
+
'module' => %w[install show generate-types] }.freeze
|
44
45
|
|
45
46
|
attr_reader :config, :options
|
46
47
|
|
47
48
|
def initialize(argv)
|
48
49
|
Bolt::Logger.initialize_logging
|
49
|
-
@logger =
|
50
|
+
@logger = Bolt::Logger.logger(self)
|
50
51
|
@argv = argv
|
51
52
|
@options = {}
|
52
53
|
end
|
@@ -79,7 +80,7 @@ module Bolt
|
|
79
80
|
|
80
81
|
# Wrapper method that is called by the Bolt executable. Parses the command and
|
81
82
|
# then loads the project and config. Once config is loaded, it completes the
|
82
|
-
# setup process by configuring Bolt and
|
83
|
+
# setup process by configuring Bolt and logging messages.
|
83
84
|
#
|
84
85
|
# This separation is needed since the Bolt::Outputter class that normally handles
|
85
86
|
# printing errors relies on config being loaded. All setup that happens before
|
@@ -167,20 +168,17 @@ module Bolt
|
|
167
168
|
raise e
|
168
169
|
end
|
169
170
|
|
170
|
-
# Completes the setup process by configuring Bolt and
|
171
|
+
# Completes the setup process by configuring Bolt and log messages
|
171
172
|
def finalize_setup
|
172
173
|
Bolt::Logger.configure(config.log, config.color)
|
173
174
|
Bolt::Logger.analytics = analytics
|
174
175
|
|
175
|
-
# Logger must be configured before checking path case and project file, otherwise
|
176
|
+
# Logger must be configured before checking path case and project file, otherwise logs will not display
|
176
177
|
config.check_path_case('modulepath', config.modulepath)
|
177
178
|
config.project.check_deprecated_file
|
178
179
|
|
179
|
-
# Log
|
180
|
-
|
181
|
-
|
182
|
-
# Display warnings created during parser and config initialization
|
183
|
-
config.warnings.each { |warning| @logger.warn(warning[:msg]) }
|
180
|
+
# Log messages created during parser and config initialization
|
181
|
+
config.logs.each { |log| @logger.send(log.keys[0], log.values[0]) }
|
184
182
|
@parser_deprecations.each { |dep| Bolt::Logger.deprecation_warning(dep[:type], dep[:msg]) }
|
185
183
|
config.deprecations.each { |dep| Bolt::Logger.deprecation_warning(dep[:type], dep[:msg]) }
|
186
184
|
|
@@ -213,10 +211,14 @@ module Bolt
|
|
213
211
|
end
|
214
212
|
|
215
213
|
def validate(options)
|
216
|
-
unless
|
214
|
+
# Disables the 'module' subcommand unless the module feature flag is set.
|
215
|
+
commands = COMMANDS.dup
|
216
|
+
commands.delete('module') unless ENV['BOLT_MODULE_FEATURE']
|
217
|
+
|
218
|
+
unless commands.include?(options[:subcommand])
|
217
219
|
raise Bolt::CLIError,
|
218
220
|
"Expected subcommand '#{options[:subcommand]}' to be one of " \
|
219
|
-
"#{
|
221
|
+
"#{commands.keys.join(', ')}"
|
220
222
|
end
|
221
223
|
|
222
224
|
actions = COMMANDS[options[:subcommand]]
|
@@ -356,7 +358,7 @@ module Bolt
|
|
356
358
|
# Initialize inventory and targets. Errors here are better to catch early.
|
357
359
|
# options[:target_args] will contain a string/array version of the targetting options this is passed to plans
|
358
360
|
# options[:targets] will contain a resolved set of Target objects
|
359
|
-
unless %w[project puppetfile secret
|
361
|
+
unless %w[guide module project puppetfile secret].include?(options[:subcommand]) ||
|
360
362
|
%w[convert new show].include?(options[:action])
|
361
363
|
update_targets(options)
|
362
364
|
end
|
@@ -407,6 +409,8 @@ module Bolt
|
|
407
409
|
end
|
408
410
|
when 'group'
|
409
411
|
list_groups
|
412
|
+
when 'module'
|
413
|
+
list_modules
|
410
414
|
end
|
411
415
|
return 0
|
412
416
|
when 'show-modules'
|
@@ -446,12 +450,19 @@ module Bolt
|
|
446
450
|
when 'run'
|
447
451
|
code = run_plan(options[:object], options[:task_options], options[:target_args], options)
|
448
452
|
end
|
453
|
+
when 'module'
|
454
|
+
case options[:action]
|
455
|
+
when 'install'
|
456
|
+
code = install_project_modules
|
457
|
+
when 'generate-types'
|
458
|
+
code = generate_types
|
459
|
+
end
|
449
460
|
when 'puppetfile'
|
450
461
|
case options[:action]
|
451
462
|
when 'generate-types'
|
452
463
|
code = generate_types
|
453
464
|
when 'install'
|
454
|
-
code = install_puppetfile(config.puppetfile_config, config.puppetfile, config.modulepath)
|
465
|
+
code = install_puppetfile(config.puppetfile_config, config.puppetfile, config.modulepath.first)
|
455
466
|
end
|
456
467
|
when 'secret'
|
457
468
|
code = Bolt::Secret.execute(plugins, outputter, options)
|
@@ -801,36 +812,38 @@ module Bolt
|
|
801
812
|
old_config = project + 'bolt.yaml'
|
802
813
|
config = project + 'bolt-project.yaml'
|
803
814
|
puppetfile = project + 'Puppetfile'
|
804
|
-
|
815
|
+
moduledir = project + 'modules'
|
805
816
|
|
806
|
-
#
|
807
|
-
#
|
808
|
-
#
|
809
|
-
#
|
810
|
-
#
|
817
|
+
# Warn the user if the project directory already exists. We don't error
|
818
|
+
# here since users might not have installed any modules yet. If both
|
819
|
+
# bolt.yaml and bolt-project.yaml exist, this will just warn about
|
820
|
+
# bolt-project.yaml and subsequent Bolt actions will warn about both files
|
821
|
+
# existing.
|
822
|
+
if config.exist?
|
823
|
+
@logger.warn "Found existing project directory at #{project}. Skipping file creation."
|
824
|
+
elsif old_config.exist?
|
825
|
+
@logger.warn "Found existing #{old_config.basename} at #{project}. "\
|
826
|
+
"#{old_config.basename} is deprecated, please rename to #{config.basename}."
|
827
|
+
end
|
828
|
+
|
829
|
+
# If modules were specified, first check if there is already a Puppetfile
|
830
|
+
# at the project directory, erroring if there is. If there is no
|
831
|
+
# Puppetfile, install the specified modules. The module installer will
|
832
|
+
# resolve dependencies, generate a Puppetfile, and install the modules.
|
811
833
|
if options[:modules]
|
812
834
|
if puppetfile.exist?
|
813
835
|
raise Bolt::CLIError,
|
814
|
-
"Found existing Puppetfile at #{puppetfile}, unable to initialize
|
815
|
-
"
|
816
|
-
else
|
817
|
-
puppetfile_specs = resolve_puppetfile_specs
|
836
|
+
"Found existing Puppetfile at #{puppetfile}, unable to initialize "\
|
837
|
+
"project with modules."
|
818
838
|
end
|
839
|
+
|
840
|
+
install_modules(puppetfile, {}, moduledir, options[:modules])
|
819
841
|
end
|
820
842
|
|
821
|
-
#
|
822
|
-
#
|
823
|
-
#
|
824
|
-
|
825
|
-
# both files existing
|
826
|
-
if config.exist?
|
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}."
|
832
|
-
# Bless the project directory as a...wait for it...project
|
833
|
-
else
|
843
|
+
# If either bolt.yaml or bolt-project.yaml exist, the user has already
|
844
|
+
# been warned and we can just finish project creation. Otherwise, create a
|
845
|
+
# bolt-project.yaml with the project name in it.
|
846
|
+
unless config.exist? || old_config.exist?
|
834
847
|
begin
|
835
848
|
content = { 'name' => name }
|
836
849
|
File.write(config.to_path, content.to_yaml)
|
@@ -840,109 +853,82 @@ module Bolt
|
|
840
853
|
end
|
841
854
|
end
|
842
855
|
|
843
|
-
# Write the generated Puppetfile to the fancy new project
|
844
|
-
if puppetfile_specs
|
845
|
-
File.write(puppetfile, puppetfile_specs.join("\n"))
|
846
|
-
outputter.print_message "Successfully created Puppetfile at #{puppetfile}"
|
847
|
-
# Install the modules from our shiny new Puppetfile
|
848
|
-
if install_puppetfile({}, puppetfile, modulepath)
|
849
|
-
outputter.print_message "Successfully installed #{options[:modules].join(', ')}"
|
850
|
-
else
|
851
|
-
raise Bolt::CLIError, "Could not install #{options[:modules].join(', ')}"
|
852
|
-
end
|
853
|
-
end
|
854
|
-
|
855
856
|
0
|
856
857
|
end
|
857
858
|
|
858
|
-
#
|
859
|
-
#
|
860
|
-
def
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
options[:modules].each do |mod_name|
|
866
|
-
model.add_module(
|
867
|
-
PuppetfileResolver::Puppetfile::ForgeModule.new(mod_name).tap { |mod| mod.version = :latest }
|
868
|
-
)
|
869
|
-
end
|
870
|
-
|
871
|
-
# Make sure the Puppetfile model is valid
|
872
|
-
unless model.valid?
|
873
|
-
raise Bolt::ValidationError,
|
874
|
-
"Unable to resolve dependencies for #{options[:modules].join(', ')}"
|
859
|
+
# Installs modules declared in the project configuration file.
|
860
|
+
#
|
861
|
+
def install_project_modules
|
862
|
+
if config.project.modules.nil?
|
863
|
+
outputter.print_message "Project configuration file '#{config.project.project_file}' "\
|
864
|
+
"does not specify any module dependencies. Nothing to do."
|
865
|
+
return 0
|
875
866
|
end
|
876
867
|
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
cache: nil,
|
883
|
-
ui: nil,
|
884
|
-
module_paths: [],
|
885
|
-
allow_missing_modules: true
|
868
|
+
install_modules(
|
869
|
+
config.puppetfile,
|
870
|
+
config.puppetfile_config,
|
871
|
+
config.project.path + '.modules',
|
872
|
+
config.project.modules
|
886
873
|
)
|
874
|
+
end
|
887
875
|
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
876
|
+
# Installs modules declared in the project configuration file.
|
877
|
+
#
|
878
|
+
def install_modules(puppetfile_path, config, moduledir, modules)
|
879
|
+
require 'bolt/puppetfile'
|
880
|
+
require 'bolt/puppetfile/installer'
|
881
|
+
|
882
|
+
puppetfile = Bolt::Puppetfile.new(modules)
|
883
|
+
|
884
|
+
# If the Puppetfile exists, check if it includes specs for each declared
|
885
|
+
# module, erroring if there are any missing. Otherwise, resolve the
|
886
|
+
# module dependencies and write a new Puppetfile. Users can forcibly
|
887
|
+
# overwrite an existing Puppetfile with the '--force' option.
|
888
|
+
if puppetfile_path.exist? && !options[:force]
|
889
|
+
outputter.print_message "Parsing existing Puppetfile at #{puppetfile_path}"
|
890
|
+
existing = Bolt::Puppetfile.parse(puppetfile_path)
|
891
|
+
|
892
|
+
unless existing.modules.superset? puppetfile.modules
|
893
|
+
missing_modules = puppetfile.modules - existing.modules
|
894
|
+
|
895
|
+
raise Bolt::Error.new(
|
896
|
+
"Puppetfile #{puppetfile_path} is missing specifications for modules: "\
|
897
|
+
"#{missing_modules.map(&:title).join(', ')}. This may not be a Puppetfile "\
|
898
|
+
"managed by Bolt. To forcibly overwrite the Puppetfile, run with the "\
|
899
|
+
"'--force' option.",
|
900
|
+
'bolt/missing-module-specs'
|
901
|
+
)
|
896
902
|
end
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
"Unknown module name#{plural} #{names.join(', ')}"
|
903
|
+
else
|
904
|
+
outputter.print_message "Resolving module dependencies, this may take a moment"
|
905
|
+
puppetfile.resolve
|
906
|
+
outputter.print_message "Writing Puppetfile at #{puppetfile_path}"
|
907
|
+
puppetfile.write(puppetfile_path, force: true)
|
903
908
|
end
|
904
909
|
|
905
|
-
|
906
|
-
|
907
|
-
spec.instance_of? PuppetfileResolver::Models::ModuleSpecification
|
908
|
-
end
|
910
|
+
outputter.print_message "Syncing modules from #{puppetfile_path} to #{moduledir}"
|
911
|
+
ok = Bolt::Puppetfile::Installer.new(config).install(puppetfile_path, moduledir)
|
909
912
|
|
910
|
-
#
|
911
|
-
|
912
|
-
"mod '#{spec.owner}-#{spec.name}', '#{spec.version}'"
|
913
|
-
end
|
914
|
-
end
|
915
|
-
|
916
|
-
def install_puppetfile(config, puppetfile, modulepath)
|
917
|
-
require 'r10k/cli'
|
918
|
-
require 'bolt/r10k_log_proxy'
|
913
|
+
# Automatically generate types after installing modules.
|
914
|
+
pal.generate_types
|
919
915
|
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
root: puppetfile.dirname.to_s,
|
924
|
-
puppetfile: puppetfile.to_s,
|
925
|
-
moduledir: moduledir
|
926
|
-
}
|
916
|
+
outputter.print_puppetfile_result(ok, puppetfile_path, moduledir)
|
917
|
+
ok ? 0 : 1
|
918
|
+
end
|
927
919
|
|
928
|
-
|
929
|
-
|
930
|
-
|
920
|
+
# Loads a Puppetfile and installs its modules.
|
921
|
+
#
|
922
|
+
def install_puppetfile(config, puppetfile, moduledir)
|
923
|
+
require 'bolt/puppetfile/installer'
|
931
924
|
|
932
|
-
|
933
|
-
R10K::Logging.instance_variable_set(:@outputter, Bolt::R10KLogProxy.new)
|
925
|
+
ok = Bolt::Puppetfile::Installer.new(config).install(puppetfile, moduledir)
|
934
926
|
|
935
|
-
|
936
|
-
|
937
|
-
# Automatically generate types after installing modules
|
938
|
-
pal.generate_types
|
927
|
+
# Automatically generate types after installing modules.
|
928
|
+
pal.generate_types
|
939
929
|
|
940
|
-
|
941
|
-
|
942
|
-
raise Bolt::FileError.new("Could not find a Puppetfile at #{puppetfile}", puppetfile)
|
943
|
-
end
|
944
|
-
rescue R10K::Error => e
|
945
|
-
raise PuppetfileError, e
|
930
|
+
outputter.print_puppetfile_result(ok, puppetfile, moduledir)
|
931
|
+
ok ? 0 : 1
|
946
932
|
end
|
947
933
|
|
948
934
|
def pal
|
@@ -958,17 +944,17 @@ module Bolt
|
|
958
944
|
# Collects the list of Bolt guides and maps them to their topics.
|
959
945
|
def guides
|
960
946
|
@guides ||= begin
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
947
|
+
root_path = File.expand_path(File.join(__dir__, '..', '..', 'guides'))
|
948
|
+
files = Dir.children(root_path).sort
|
949
|
+
|
950
|
+
files.each_with_object({}) do |file, guides|
|
951
|
+
next if file !~ /\.txt\z/
|
952
|
+
topic = File.basename(file, '.txt')
|
953
|
+
guides[topic] = File.join(root_path, file)
|
954
|
+
end
|
955
|
+
rescue SystemCallError => e
|
956
|
+
raise Bolt::FileError.new("#{e.message}: unable to load guides directory", root_path)
|
957
|
+
end
|
972
958
|
end
|
973
959
|
|
974
960
|
# Display the list of available Bolt guides.
|
@@ -1019,10 +1005,10 @@ module Bolt
|
|
1019
1005
|
|
1020
1006
|
def analytics
|
1021
1007
|
@analytics ||= begin
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1008
|
+
client = Bolt::Analytics.build_client
|
1009
|
+
client.bundled_content = bundled_content
|
1010
|
+
client
|
1011
|
+
end
|
1026
1012
|
end
|
1027
1013
|
|
1028
1014
|
def bundled_content
|
@@ -1057,17 +1043,10 @@ module Bolt
|
|
1057
1043
|
content
|
1058
1044
|
end
|
1059
1045
|
|
1060
|
-
def config_loaded
|
1061
|
-
msg = <<~MSG.chomp
|
1062
|
-
Loaded configuration from: '#{config.config_files.join("', '")}'
|
1063
|
-
MSG
|
1064
|
-
@logger.info(msg)
|
1065
|
-
end
|
1066
|
-
|
1067
1046
|
# Gem installs include the aggregate, canary, and puppetdb_fact modules, while
|
1068
1047
|
# package installs include modules listed in the Bolt repo Puppetfile
|
1069
1048
|
def incomplete_install?
|
1070
|
-
(Dir.children(Bolt::PAL::MODULES_PATH) - %w[aggregate canary puppetdb_fact]).empty?
|
1049
|
+
(Dir.children(Bolt::PAL::MODULES_PATH) - %w[aggregate canary puppetdb_fact secure_env_vars]).empty?
|
1071
1050
|
end
|
1072
1051
|
|
1073
1052
|
# Mimicks the output from Outputter::Human#fatal_error. This should be used to print
|