bolt 2.29.0 → 2.33.2
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 +15 -14
- data/bolt-modules/boltlib/lib/puppet/functions/download_file.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/facts.rb +6 -0
- data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb +2 -2
- data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_task_with.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/write_file.rb +2 -2
- data/bolt-modules/out/lib/puppet/functions/out/message.rb +44 -1
- data/bolt-modules/prompt/lib/puppet/functions/prompt.rb +3 -0
- data/guides/logging.txt +18 -0
- data/guides/module.txt +19 -0
- data/guides/modulepath.txt +25 -0
- data/lib/bolt/bolt_option_parser.rb +48 -9
- data/lib/bolt/catalog.rb +1 -1
- data/lib/bolt/cli.rb +154 -116
- data/lib/bolt/config.rb +13 -1
- data/lib/bolt/config/modulepath.rb +30 -0
- data/lib/bolt/config/options.rb +32 -13
- data/lib/bolt/config/transport/options.rb +2 -2
- data/lib/bolt/error.rb +4 -0
- data/lib/bolt/executor.rb +13 -13
- data/lib/bolt/inventory.rb +10 -9
- data/lib/bolt/module_installer.rb +198 -0
- data/lib/bolt/{puppetfile → module_installer}/installer.rb +3 -2
- data/lib/bolt/module_installer/puppetfile.rb +117 -0
- data/lib/bolt/module_installer/puppetfile/forge_module.rb +54 -0
- data/lib/bolt/module_installer/puppetfile/git_module.rb +37 -0
- data/lib/bolt/module_installer/puppetfile/module.rb +26 -0
- data/lib/bolt/module_installer/resolver.rb +76 -0
- data/lib/bolt/module_installer/specs.rb +93 -0
- data/lib/bolt/module_installer/specs/forge_spec.rb +85 -0
- data/lib/bolt/module_installer/specs/git_spec.rb +179 -0
- data/lib/bolt/outputter.rb +2 -45
- data/lib/bolt/outputter/human.rb +78 -18
- data/lib/bolt/outputter/json.rb +22 -7
- data/lib/bolt/outputter/logger.rb +2 -2
- data/lib/bolt/pal.rb +55 -45
- data/lib/bolt/pal/yaml_plan.rb +4 -2
- data/lib/bolt/pal/yaml_plan/evaluator.rb +23 -1
- data/lib/bolt/pal/yaml_plan/loader.rb +14 -9
- data/lib/bolt/plugin.rb +1 -1
- data/lib/bolt/plugin/module.rb +1 -1
- data/lib/bolt/project.rb +32 -21
- data/lib/bolt/project_migrator.rb +80 -0
- data/lib/bolt/project_migrator/base.rb +39 -0
- data/lib/bolt/project_migrator/config.rb +67 -0
- data/lib/bolt/project_migrator/inventory.rb +67 -0
- data/lib/bolt/project_migrator/modules.rb +200 -0
- data/lib/bolt/result.rb +23 -11
- data/lib/bolt/shell/bash.rb +15 -9
- data/lib/bolt/shell/powershell.rb +11 -6
- data/lib/bolt/transport/base.rb +18 -18
- data/lib/bolt/transport/docker.rb +23 -6
- data/lib/bolt/transport/orch.rb +23 -14
- data/lib/bolt/transport/remote.rb +2 -2
- data/lib/bolt/transport/simple.rb +6 -6
- data/lib/bolt/transport/ssh/connection.rb +1 -1
- data/lib/bolt/util.rb +22 -0
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/acl.rb +2 -2
- data/lib/bolt_server/base_config.rb +3 -3
- data/lib/bolt_server/schemas/partials/task.json +17 -2
- data/lib/bolt_server/transport_app.rb +92 -12
- data/lib/bolt_spec/bolt_context.rb +4 -2
- data/lib/bolt_spec/plans.rb +1 -1
- 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 +6 -6
- data/lib/bolt_spec/run.rb +1 -1
- metadata +29 -10
- data/lib/bolt/project_migrate.rb +0 -138
- data/lib/bolt/puppetfile.rb +0 -160
- data/lib/bolt/puppetfile/module.rb +0 -89
- data/lib/bolt_server/pe/pal.rb +0 -67
- data/modules/secure_env_vars/plans/init.pp +0 -20
data/lib/bolt/config.rb
CHANGED
@@ -391,6 +391,12 @@ module Bolt
|
|
391
391
|
@logs << { warn: msg }
|
392
392
|
end
|
393
393
|
|
394
|
+
if @project.modules && @data['modulepath']&.include?(@project.managed_moduledir.to_s)
|
395
|
+
raise Bolt::ValidationError,
|
396
|
+
"Found invalid path in modulepath: #{@project.managed_moduledir}. This path "\
|
397
|
+
"is automatically appended to the modulepath and cannot be configured."
|
398
|
+
end
|
399
|
+
|
394
400
|
keys = OPTIONS.keys - %w[plugins plugin_hooks puppetdb]
|
395
401
|
keys.each do |key|
|
396
402
|
next unless Bolt::Util.references?(@data[key])
|
@@ -445,7 +451,13 @@ module Bolt
|
|
445
451
|
end
|
446
452
|
|
447
453
|
def modulepath
|
448
|
-
@data['modulepath'] || @project.modulepath
|
454
|
+
path = @data['modulepath'] || @project.modulepath
|
455
|
+
|
456
|
+
if @project.modules
|
457
|
+
path + [@project.managed_moduledir.to_s]
|
458
|
+
else
|
459
|
+
path
|
460
|
+
end
|
449
461
|
end
|
450
462
|
|
451
463
|
def modulepath=(value)
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bolt/config'
|
4
|
+
|
5
|
+
module Bolt
|
6
|
+
class Config
|
7
|
+
class Modulepath
|
8
|
+
BOLTLIB_PATH = File.expand_path('../../../bolt-modules', __dir__)
|
9
|
+
MODULES_PATH = File.expand_path('../../../modules', __dir__)
|
10
|
+
|
11
|
+
# The user_modulepath only includes the original modulepath and is used during pluginsync.
|
12
|
+
# We don't want to pluginsync any of the content from BOLT_MODULES since that content
|
13
|
+
# includes core modules that can conflict with modules installed with an agent.
|
14
|
+
attr_reader :user_modulepath
|
15
|
+
|
16
|
+
def initialize(user_modulepath, boltlib_path: BOLTLIB_PATH, builtin_content_path: MODULES_PATH)
|
17
|
+
@user_modulepath = Array(user_modulepath).flatten
|
18
|
+
@boltlib_path = Array(boltlib_path).flatten
|
19
|
+
@builtin_content_path = Array(builtin_content_path).flatten
|
20
|
+
end
|
21
|
+
|
22
|
+
# The full_modulepath includes both the BOLTLIB
|
23
|
+
# path and the MODULES_PATH to ensure bolt functions and
|
24
|
+
# built-in content are available in the compliler
|
25
|
+
def full_modulepath
|
26
|
+
@boltlib_path + @user_modulepath + @builtin_content_path
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/bolt/config/options.rb
CHANGED
@@ -233,26 +233,45 @@ module Bolt
|
|
233
233
|
"install` command.",
|
234
234
|
type: Array,
|
235
235
|
items: {
|
236
|
-
type: Hash,
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
236
|
+
type: [Hash, String],
|
237
|
+
oneOf: [
|
238
|
+
{
|
239
|
+
required: ["name"],
|
240
|
+
properties: {
|
241
|
+
"name" => {
|
242
|
+
description: "The name of the module.",
|
243
|
+
type: String
|
244
|
+
},
|
245
|
+
"version_requirement" => {
|
246
|
+
description: "The version requirement for the module. Accepts a specific version (1.2.3), version "\
|
247
|
+
"shorthand (1.2.x), or a version range (>= 1.2.0).",
|
248
|
+
type: String
|
249
|
+
}
|
250
|
+
}
|
242
251
|
},
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
252
|
+
{
|
253
|
+
required: %w[git ref],
|
254
|
+
properties: {
|
255
|
+
"git" => {
|
256
|
+
description: "The URL to the public git repository.",
|
257
|
+
type: String
|
258
|
+
},
|
259
|
+
"ref" => {
|
260
|
+
description: "The git reference to check out. Can be either a branch, tag, or commit SHA.",
|
261
|
+
type: String
|
262
|
+
}
|
263
|
+
}
|
247
264
|
}
|
248
|
-
|
265
|
+
]
|
249
266
|
},
|
250
267
|
_plugin: false,
|
251
268
|
_example: [
|
269
|
+
"puppetlabs-facts",
|
252
270
|
{ "name" => "puppetlabs-mysql" },
|
253
271
|
{ "name" => "puppetlabs-apache", "version_requirement" => "5.5.0" },
|
254
272
|
{ "name" => "puppetlabs-puppetdb", "version_requirement" => "7.x" },
|
255
|
-
{ "name" => "puppetlabs-firewall", "version_requirement" => ">= 1.0.0 < 3.0.0" }
|
273
|
+
{ "name" => "puppetlabs-firewall", "version_requirement" => ">= 1.0.0 < 3.0.0" },
|
274
|
+
{ "git" => "https://github.com/puppetlabs/puppetlabs-apt", "ref" => "7.6.0" }
|
256
275
|
]
|
257
276
|
},
|
258
277
|
"name" => {
|
@@ -328,7 +347,7 @@ module Bolt
|
|
328
347
|
"server_urls" => {
|
329
348
|
description: "An array containing the PuppetDB host to connect to. Include the protocol `https` "\
|
330
349
|
"and the port, which is usually `8081`. For example, "\
|
331
|
-
"`https://my-
|
350
|
+
"`https://my-puppetdb-server.com:8081`.",
|
332
351
|
type: Array,
|
333
352
|
_example: ["https://puppet.example.com:8081"]
|
334
353
|
},
|
@@ -357,7 +357,7 @@ module Bolt
|
|
357
357
|
description: "The URL of the host used for API requests.",
|
358
358
|
format: "uri",
|
359
359
|
_plugin: true,
|
360
|
-
_example: "https://api.example.com"
|
360
|
+
_example: "https://api.example.com:<port>"
|
361
361
|
},
|
362
362
|
"shell-command" => {
|
363
363
|
type: String,
|
@@ -374,7 +374,7 @@ module Bolt
|
|
374
374
|
},
|
375
375
|
"ssh-command" => {
|
376
376
|
type: [Array, String],
|
377
|
-
description: "The command and
|
377
|
+
description: "The command and options to use when SSHing. This option is used when you need support for "\
|
378
378
|
"features or algorithms that are not supported by the net-ssh Ruby library. **This option "\
|
379
379
|
"is experimental.** You can read more about this option in [Native SSH "\
|
380
380
|
"transport](experimental_features.md#native-ssh-transport).",
|
data/lib/bolt/error.rb
CHANGED
data/lib/bolt/executor.rb
CHANGED
@@ -227,7 +227,7 @@ module Bolt
|
|
227
227
|
data[:resource_mean] = sum / resource_counts.length
|
228
228
|
end
|
229
229
|
|
230
|
-
@analytics&.event('Apply', 'ast', data)
|
230
|
+
@analytics&.event('Apply', 'ast', **data)
|
231
231
|
end
|
232
232
|
|
233
233
|
def report_yaml_plan(plan)
|
@@ -253,33 +253,33 @@ module Bolt
|
|
253
253
|
result
|
254
254
|
end
|
255
255
|
|
256
|
-
def run_command(targets, command, options = {})
|
256
|
+
def run_command(targets, command, options = {}, position = [])
|
257
257
|
description = options.fetch(:description, "command '#{command}'")
|
258
258
|
log_action(description, targets) do
|
259
259
|
options[:run_as] = run_as if run_as && !options.key?(:run_as)
|
260
260
|
|
261
261
|
batch_execute(targets) do |transport, batch|
|
262
262
|
with_node_logging("Running command '#{command}'", batch) do
|
263
|
-
transport.batch_command(batch, command, options, &method(:publish_event))
|
263
|
+
transport.batch_command(batch, command, options, position, &method(:publish_event))
|
264
264
|
end
|
265
265
|
end
|
266
266
|
end
|
267
267
|
end
|
268
268
|
|
269
|
-
def run_script(targets, script, arguments, options = {})
|
269
|
+
def run_script(targets, script, arguments, options = {}, position = [])
|
270
270
|
description = options.fetch(:description, "script #{script}")
|
271
271
|
log_action(description, targets) do
|
272
272
|
options[:run_as] = run_as if run_as && !options.key?(:run_as)
|
273
273
|
|
274
274
|
batch_execute(targets) do |transport, batch|
|
275
275
|
with_node_logging("Running script #{script} with '#{arguments.to_json}'", batch) do
|
276
|
-
transport.batch_script(batch, script, arguments, options, &method(:publish_event))
|
276
|
+
transport.batch_script(batch, script, arguments, options, position, &method(:publish_event))
|
277
277
|
end
|
278
278
|
end
|
279
279
|
end
|
280
280
|
end
|
281
281
|
|
282
|
-
def run_task(targets, task, arguments, options = {})
|
282
|
+
def run_task(targets, task, arguments, options = {}, position = [])
|
283
283
|
description = options.fetch(:description, "task #{task.name}")
|
284
284
|
log_action(description, targets) do
|
285
285
|
options[:run_as] = run_as if run_as && !options.key?(:run_as)
|
@@ -287,13 +287,13 @@ module Bolt
|
|
287
287
|
|
288
288
|
batch_execute(targets) do |transport, batch|
|
289
289
|
with_node_logging("Running task #{task.name} with '#{arguments.to_json}'", batch) do
|
290
|
-
transport.batch_task(batch, task, arguments, options, &method(:publish_event))
|
290
|
+
transport.batch_task(batch, task, arguments, options, position, &method(:publish_event))
|
291
291
|
end
|
292
292
|
end
|
293
293
|
end
|
294
294
|
end
|
295
295
|
|
296
|
-
def run_task_with(target_mapping, task, options = {})
|
296
|
+
def run_task_with(target_mapping, task, options = {}, position = [])
|
297
297
|
targets = target_mapping.keys
|
298
298
|
description = options.fetch(:description, "task #{task.name}")
|
299
299
|
|
@@ -303,26 +303,26 @@ module Bolt
|
|
303
303
|
|
304
304
|
batch_execute(targets) do |transport, batch|
|
305
305
|
with_node_logging("Running task #{task.name}'", batch) do
|
306
|
-
transport.batch_task_with(batch, task, target_mapping, options, &method(:publish_event))
|
306
|
+
transport.batch_task_with(batch, task, target_mapping, options, position, &method(:publish_event))
|
307
307
|
end
|
308
308
|
end
|
309
309
|
end
|
310
310
|
end
|
311
311
|
|
312
|
-
def upload_file(targets, source, destination, options = {})
|
312
|
+
def upload_file(targets, source, destination, options = {}, position = [])
|
313
313
|
description = options.fetch(:description, "file upload from #{source} to #{destination}")
|
314
314
|
log_action(description, targets) do
|
315
315
|
options[:run_as] = run_as if run_as && !options.key?(:run_as)
|
316
316
|
|
317
317
|
batch_execute(targets) do |transport, batch|
|
318
318
|
with_node_logging("Uploading file #{source} to #{destination}", batch) do
|
319
|
-
transport.batch_upload(batch, source, destination, options, &method(:publish_event))
|
319
|
+
transport.batch_upload(batch, source, destination, options, position, &method(:publish_event))
|
320
320
|
end
|
321
321
|
end
|
322
322
|
end
|
323
323
|
end
|
324
324
|
|
325
|
-
def download_file(targets, source, destination, options = {})
|
325
|
+
def download_file(targets, source, destination, options = {}, position = [])
|
326
326
|
description = options.fetch(:description, "file download from #{source} to #{destination}")
|
327
327
|
|
328
328
|
begin
|
@@ -337,7 +337,7 @@ module Bolt
|
|
337
337
|
|
338
338
|
batch_execute(targets) do |transport, batch|
|
339
339
|
with_node_logging("Downloading file #{source} to #{destination}", batch) do
|
340
|
-
transport.batch_download(batch, source, destination, options, &method(:publish_event))
|
340
|
+
transport.batch_download(batch, source, destination, options, position, &method(:publish_event))
|
341
341
|
end
|
342
342
|
end
|
343
343
|
end
|
data/lib/bolt/inventory.rb
CHANGED
@@ -56,16 +56,17 @@ module Bolt
|
|
56
56
|
rescue Psych::Exception
|
57
57
|
raise Bolt::ParseError, "Could not parse inventory from $#{ENVIRONMENT_VAR}"
|
58
58
|
end
|
59
|
+
elsif config.inventoryfile
|
60
|
+
data = Bolt::Util.read_yaml_hash(config.inventoryfile, 'inventory')
|
61
|
+
logger.debug("Loaded inventory from #{config.inventoryfile}")
|
59
62
|
else
|
60
|
-
data =
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
# This avoids rubocop complaining about identical conditionals
|
68
|
-
logger.debug("Loaded inventory from #{config.inventoryfile}") if config.inventoryfile
|
63
|
+
data = Bolt::Util.read_optional_yaml_hash(config.default_inventoryfile, 'inventory')
|
64
|
+
|
65
|
+
if config.default_inventoryfile.exist?
|
66
|
+
logger.debug("Loaded inventory from #{config.default_inventoryfile}")
|
67
|
+
else
|
68
|
+
logger.debug("Tried to load inventory from #{config.default_inventoryfile}, but the file does not exist")
|
69
|
+
end
|
69
70
|
end
|
70
71
|
|
71
72
|
# Resolve plugin references from transport config
|
@@ -0,0 +1,198 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bolt/error'
|
4
|
+
require 'bolt/logger'
|
5
|
+
require 'bolt/module_installer/installer'
|
6
|
+
require 'bolt/module_installer/puppetfile'
|
7
|
+
require 'bolt/module_installer/resolver'
|
8
|
+
require 'bolt/module_installer/specs'
|
9
|
+
|
10
|
+
module Bolt
|
11
|
+
class ModuleInstaller
|
12
|
+
def initialize(outputter, pal)
|
13
|
+
@outputter = outputter
|
14
|
+
@pal = pal
|
15
|
+
@logger = Bolt::Logger.logger(self)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Adds a single module to the project.
|
19
|
+
#
|
20
|
+
def add(name, specs, puppetfile_path, moduledir, config_path)
|
21
|
+
project_specs = Specs.new(specs)
|
22
|
+
|
23
|
+
# Exit early if project config already includes a spec with this name.
|
24
|
+
if project_specs.include?(name)
|
25
|
+
@outputter.print_message(
|
26
|
+
"Project configuration file #{config_path} already includes specification with name "\
|
27
|
+
"#{name}. Nothing to do."
|
28
|
+
)
|
29
|
+
return true
|
30
|
+
end
|
31
|
+
|
32
|
+
@outputter.print_message("Adding module #{name} to project\n\n")
|
33
|
+
|
34
|
+
# Generate the specs to resolve from. If a Puppetfile exists, parse it and
|
35
|
+
# convert the modules to specs. Otherwise, use the project specs.
|
36
|
+
resolve_specs = if puppetfile_path.exist?
|
37
|
+
existing_puppetfile = Puppetfile.parse(puppetfile_path)
|
38
|
+
existing_puppetfile.assert_satisfies(project_specs)
|
39
|
+
Specs.from_puppetfile(existing_puppetfile)
|
40
|
+
else
|
41
|
+
project_specs
|
42
|
+
end
|
43
|
+
|
44
|
+
# Resolve module dependencies. Attempt to first resolve with resolve
|
45
|
+
# specss. If that fails, fall back to resolving from project specs.
|
46
|
+
# This prevents Bolt from modifying installed modules unless there is
|
47
|
+
# a version conflict.
|
48
|
+
@outputter.print_action_step("Resolving module dependencies, this may take a moment")
|
49
|
+
|
50
|
+
begin
|
51
|
+
resolve_specs.add_specs('name' => name)
|
52
|
+
puppetfile = Resolver.new.resolve(resolve_specs)
|
53
|
+
rescue Bolt::Error
|
54
|
+
project_specs.add_specs('name' => name)
|
55
|
+
puppetfile = Resolver.new.resolve(project_specs)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Display the diff between the existing Puppetfile and the new Puppetfile.
|
59
|
+
print_puppetfile_diff(existing_puppetfile, puppetfile)
|
60
|
+
|
61
|
+
# Add the module to the project configuration.
|
62
|
+
@outputter.print_action_step("Updating project configuration file at #{config_path}")
|
63
|
+
|
64
|
+
data = Bolt::Util.read_yaml_hash(config_path, 'project')
|
65
|
+
data['modules'] ||= []
|
66
|
+
data['modules'] << name.tr('-', '/')
|
67
|
+
|
68
|
+
begin
|
69
|
+
File.write(config_path, data.to_yaml)
|
70
|
+
rescue SystemCallError => e
|
71
|
+
raise Bolt::FileError.new(
|
72
|
+
"Unable to update project configuration file: #{e.message}",
|
73
|
+
config
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Write the Puppetfile.
|
78
|
+
@outputter.print_action_step("Writing Puppetfile at #{puppetfile_path}")
|
79
|
+
puppetfile.write(puppetfile_path, moduledir)
|
80
|
+
|
81
|
+
# Install the modules.
|
82
|
+
install_puppetfile(puppetfile_path, moduledir)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Outputs a diff of an old Puppetfile and a new Puppetfile.
|
86
|
+
#
|
87
|
+
def print_puppetfile_diff(old, new)
|
88
|
+
# Build hashes mapping the module name to the module object. This makes it
|
89
|
+
# a little easier to determine which modules have been added, removed, or
|
90
|
+
# modified.
|
91
|
+
old = (old&.modules || []).each_with_object({}) do |mod, acc|
|
92
|
+
next unless mod.type == :forge
|
93
|
+
acc[mod.full_name] = mod
|
94
|
+
end
|
95
|
+
|
96
|
+
new = new.modules.each_with_object({}) do |mod, acc|
|
97
|
+
next unless mod.type == :forge
|
98
|
+
acc[mod.full_name] = mod
|
99
|
+
end
|
100
|
+
|
101
|
+
# New modules are those present in new but not in old.
|
102
|
+
added = new.reject { |full_name, _mod| old.include?(full_name) }.values
|
103
|
+
|
104
|
+
if added.any?
|
105
|
+
diff = "Adding the following modules:\n"
|
106
|
+
added.each { |mod| diff += "#{mod.full_name} #{mod.version}\n" }
|
107
|
+
@outputter.print_action_step(diff)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Upgraded modules are those that have a newer version in new than old.
|
111
|
+
upgraded = new.select do |full_name, mod|
|
112
|
+
if old.include?(full_name)
|
113
|
+
mod.version > old[full_name].version
|
114
|
+
end
|
115
|
+
end.keys
|
116
|
+
|
117
|
+
if upgraded.any?
|
118
|
+
diff = "Upgrading the following modules:\n"
|
119
|
+
upgraded.each { |full_name| diff += "#{full_name} #{old[full_name].version} to #{new[full_name].version}\n" }
|
120
|
+
@outputter.print_action_step(diff)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Downgraded modules are those that have an older version in new than old.
|
124
|
+
downgraded = new.select do |full_name, mod|
|
125
|
+
if old.include?(full_name)
|
126
|
+
mod.version < old[full_name].version
|
127
|
+
end
|
128
|
+
end.keys
|
129
|
+
|
130
|
+
if downgraded.any?
|
131
|
+
diff = "Downgrading the following modules: \n"
|
132
|
+
downgraded.each { |full_name| diff += "#{full_name} #{old[full_name].version} to #{new[full_name].version}\n" }
|
133
|
+
@outputter.print_action_step(diff)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Removed modules are those present in old but not in new.
|
137
|
+
removed = old.reject { |full_name, _mod| new.include?(full_name) }.values
|
138
|
+
|
139
|
+
if removed.any?
|
140
|
+
diff = "Removing the following modules:\n"
|
141
|
+
removed.each { |mod| diff += "#{mod.full_name} #{mod.version}\n" }
|
142
|
+
@outputter.print_action_step(diff)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# Installs a project's module dependencies.
|
147
|
+
#
|
148
|
+
def install(specs, path, moduledir, force: false, resolve: true)
|
149
|
+
@outputter.print_message("Installing project modules\n\n")
|
150
|
+
|
151
|
+
if resolve != false
|
152
|
+
specs = Specs.new(specs)
|
153
|
+
|
154
|
+
# If forcibly installing or if there is no Puppetfile, resolve
|
155
|
+
# and write a Puppetfile.
|
156
|
+
if force || !path.exist?
|
157
|
+
@outputter.print_action_step("Resolving module dependencies, this may take a moment")
|
158
|
+
puppetfile = Resolver.new.resolve(specs)
|
159
|
+
|
160
|
+
# We get here either through 'bolt module install' which uses the
|
161
|
+
# managed modulepath (which isn't configurable) or through bolt
|
162
|
+
# project init --modules, which uses the default modulepath. This
|
163
|
+
# should be safe to assume that if `.modules/` is the moduledir the
|
164
|
+
# user is using the new workflow
|
165
|
+
@outputter.print_action_step("Writing Puppetfile at #{path}")
|
166
|
+
if moduledir.basename.to_s == '.modules'
|
167
|
+
puppetfile.write(path, moduledir)
|
168
|
+
else
|
169
|
+
puppetfile.write(path)
|
170
|
+
end
|
171
|
+
# If not forcibly installing and there is a Puppetfile, assert
|
172
|
+
# that it satisfies the specs.
|
173
|
+
else
|
174
|
+
puppetfile = Puppetfile.parse(path)
|
175
|
+
puppetfile.assert_satisfies(specs)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# Install the modules.
|
180
|
+
install_puppetfile(path, moduledir)
|
181
|
+
end
|
182
|
+
|
183
|
+
# Installs the Puppetfile and generates types.
|
184
|
+
#
|
185
|
+
def install_puppetfile(path, moduledir, config = {})
|
186
|
+
@outputter.print_action_step("Syncing modules from #{path} to #{moduledir}")
|
187
|
+
ok = Installer.new(config).install(path, moduledir)
|
188
|
+
|
189
|
+
# Automatically generate types after installing modules
|
190
|
+
@outputter.print_action_step("Generating type references")
|
191
|
+
@pal.generate_types
|
192
|
+
|
193
|
+
@outputter.print_puppetfile_result(ok, path, moduledir)
|
194
|
+
|
195
|
+
ok
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|