bolt 2.26.0 → 2.31.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 +13 -12
- data/bolt-modules/boltlib/lib/puppet/functions/write_file.rb +2 -2
- data/lib/bolt/analytics.rb +4 -0
- data/lib/bolt/applicator.rb +19 -18
- data/lib/bolt/bolt_option_parser.rb +112 -22
- data/lib/bolt/catalog.rb +1 -1
- data/lib/bolt/cli.rb +210 -174
- data/lib/bolt/config.rb +22 -2
- data/lib/bolt/config/modulepath.rb +30 -0
- data/lib/bolt/config/options.rb +30 -0
- data/lib/bolt/config/transport/options.rb +1 -1
- data/lib/bolt/executor.rb +1 -1
- data/lib/bolt/inventory.rb +11 -10
- data/lib/bolt/logger.rb +26 -19
- data/lib/bolt/module_installer.rb +242 -0
- data/lib/bolt/outputter.rb +4 -0
- data/lib/bolt/outputter/human.rb +77 -17
- data/lib/bolt/outputter/json.rb +21 -6
- data/lib/bolt/outputter/logger.rb +2 -2
- data/lib/bolt/pal.rb +46 -25
- data/lib/bolt/plugin.rb +1 -1
- data/lib/bolt/plugin/module.rb +1 -1
- data/lib/bolt/project.rb +62 -12
- 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 +198 -0
- data/lib/bolt/puppetfile.rb +149 -0
- data/lib/bolt/puppetfile/installer.rb +43 -0
- data/lib/bolt/puppetfile/module.rb +93 -0
- data/lib/bolt/rerun.rb +1 -1
- data/lib/bolt/result.rb +15 -0
- data/lib/bolt/shell/bash.rb +4 -3
- data/lib/bolt/transport/base.rb +4 -4
- data/lib/bolt/transport/ssh/connection.rb +1 -1
- data/lib/bolt/util.rb +51 -10
- 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/config.rb +1 -1
- data/lib/bolt_server/file_cache.rb +11 -11
- data/lib/bolt_server/transport_app.rb +206 -27
- data/lib/bolt_spec/bolt_context.rb +8 -6
- data/lib/bolt_spec/plans.rb +1 -1
- data/lib/bolt_spec/plans/mock_executor.rb +1 -1
- data/lib/bolt_spec/run.rb +1 -1
- metadata +14 -6
- data/lib/bolt/project_migrate.rb +0 -138
- data/lib/bolt_server/pe/pal.rb +0 -67
data/lib/bolt/config.rb
CHANGED
@@ -64,7 +64,7 @@ module Bolt
|
|
64
64
|
end
|
65
65
|
|
66
66
|
data = load_defaults(project).push(
|
67
|
-
filepath:
|
67
|
+
filepath: configfile,
|
68
68
|
data: conf,
|
69
69
|
logs: logs,
|
70
70
|
deprecations: []
|
@@ -344,6 +344,14 @@ module Bolt
|
|
344
344
|
end
|
345
345
|
|
346
346
|
private def update_logs(logs)
|
347
|
+
begin
|
348
|
+
if logs['bolt-debug.log'] && logs['bolt-debug.log'] != 'disable'
|
349
|
+
FileUtils.touch(File.expand_path('bolt-debug.log', @project.path))
|
350
|
+
end
|
351
|
+
rescue StandardError
|
352
|
+
logs.delete('bolt-debug.log')
|
353
|
+
end
|
354
|
+
|
347
355
|
logs.each_with_object({}) do |(key, val), acc|
|
348
356
|
# Remove any disabled logs
|
349
357
|
next if val == 'disable'
|
@@ -383,6 +391,12 @@ module Bolt
|
|
383
391
|
@logs << { warn: msg }
|
384
392
|
end
|
385
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
|
+
|
386
400
|
keys = OPTIONS.keys - %w[plugins plugin_hooks puppetdb]
|
387
401
|
keys.each do |key|
|
388
402
|
next unless Bolt::Util.references?(@data[key])
|
@@ -437,7 +451,13 @@ module Bolt
|
|
437
451
|
end
|
438
452
|
|
439
453
|
def modulepath
|
440
|
-
@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
|
441
461
|
end
|
442
462
|
|
443
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
@@ -227,6 +227,35 @@ module Bolt
|
|
227
227
|
_example: ["~/.puppetlabs/bolt/modules", "~/.puppetlabs/bolt/site-modules"],
|
228
228
|
_default: ["project/modules", "project/site-modules", "project/site"]
|
229
229
|
},
|
230
|
+
"modules" => {
|
231
|
+
description: "A list of module dependencies for the project. Each dependency is a map of data specifying "\
|
232
|
+
"the module to install. To install the project's module dependencies, run the `bolt module "\
|
233
|
+
"install` command.",
|
234
|
+
type: Array,
|
235
|
+
items: {
|
236
|
+
type: [Hash, String],
|
237
|
+
required: ["name"],
|
238
|
+
properties: {
|
239
|
+
"name" => {
|
240
|
+
description: "The name of the module.",
|
241
|
+
type: String
|
242
|
+
},
|
243
|
+
"version_requirement" => {
|
244
|
+
description: "The version requirement for the module. Accepts a specific version (1.2.3), version "\
|
245
|
+
"shorthand (1.2.x), or a version range (>= 1.2.0).",
|
246
|
+
type: String
|
247
|
+
}
|
248
|
+
}
|
249
|
+
},
|
250
|
+
_plugin: false,
|
251
|
+
_example: [
|
252
|
+
{ "name" => "puppetlabs-mysql" },
|
253
|
+
"puppetlabs-facts",
|
254
|
+
{ "name" => "puppetlabs-apache", "version_requirement" => "5.5.0" },
|
255
|
+
{ "name" => "puppetlabs-puppetdb", "version_requirement" => "7.x" },
|
256
|
+
{ "name" => "puppetlabs-firewall", "version_requirement" => ">= 1.0.0 < 3.0.0" }
|
257
|
+
]
|
258
|
+
},
|
230
259
|
"name" => {
|
231
260
|
description: "The name of the Bolt project. When this option is configured, the project is considered a "\
|
232
261
|
"[Bolt project](experimental_features.md#bolt-projects), allowing Bolt to load content from "\
|
@@ -476,6 +505,7 @@ module Bolt
|
|
476
505
|
inventoryfile
|
477
506
|
log
|
478
507
|
modulepath
|
508
|
+
modules
|
479
509
|
name
|
480
510
|
plans
|
481
511
|
plugin_hooks
|
@@ -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/executor.rb
CHANGED
data/lib/bolt/inventory.rb
CHANGED
@@ -46,7 +46,7 @@ module Bolt
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def self.from_config(config, plugins)
|
49
|
-
logger =
|
49
|
+
logger = Bolt::Logger.logger(self)
|
50
50
|
|
51
51
|
if ENV.include?(ENVIRONMENT_VAR)
|
52
52
|
begin
|
@@ -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
|
data/lib/bolt/logger.rb
CHANGED
@@ -4,6 +4,10 @@ require 'logging'
|
|
4
4
|
|
5
5
|
module Bolt
|
6
6
|
module Logger
|
7
|
+
LEVELS = %w[trace debug info notice warn error fatal].freeze
|
8
|
+
@mutex = Mutex.new
|
9
|
+
@warnings = Set.new
|
10
|
+
|
7
11
|
# This method provides a single point-of-entry to setup logging for both
|
8
12
|
# the CLI and for tests. This is necessary because we define custom log
|
9
13
|
# levels which create corresponding methods on the logger instances;
|
@@ -11,20 +15,25 @@ module Bolt
|
|
11
15
|
# will fail.
|
12
16
|
def self.initialize_logging
|
13
17
|
# Initialization isn't idempotent and will result in warnings about const
|
14
|
-
# redefs, so skip it if it's
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
18
|
+
# redefs, so skip it if the log levels we expect are present. If it's
|
19
|
+
# already been initialized with an insufficient set of levels, go ahead
|
20
|
+
# and call init anyway or we'll have failures when calling log methods
|
21
|
+
# for missing levels.
|
22
|
+
unless levels & LEVELS == LEVELS
|
23
|
+
Logging.init(*LEVELS)
|
24
|
+
end
|
25
|
+
|
26
|
+
# As above, only create the color scheme if we haven't already created it.
|
27
|
+
unless Logging.color_scheme('bolt')
|
28
|
+
Logging.color_scheme(
|
29
|
+
'bolt',
|
30
|
+
lines: {
|
31
|
+
warn: :yellow,
|
32
|
+
error: :red,
|
33
|
+
fatal: %i[white on_red]
|
34
|
+
}
|
35
|
+
)
|
36
|
+
end
|
28
37
|
end
|
29
38
|
|
30
39
|
def self.configure(destinations, color)
|
@@ -115,14 +124,12 @@ module Bolt
|
|
115
124
|
end
|
116
125
|
|
117
126
|
def self.warn_once(type, msg)
|
118
|
-
@mutex.synchronize
|
119
|
-
@warnings ||= []
|
127
|
+
@mutex.synchronize do
|
120
128
|
@logger ||= Bolt::Logger.logger(self)
|
121
|
-
|
129
|
+
if @warnings.add?(type)
|
122
130
|
@logger.warn(msg)
|
123
|
-
@warnings << type
|
124
131
|
end
|
125
|
-
|
132
|
+
end
|
126
133
|
end
|
127
134
|
|
128
135
|
def self.deprecation_warning(type, msg)
|
@@ -0,0 +1,242 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bolt/error'
|
4
|
+
require 'bolt/logger'
|
5
|
+
|
6
|
+
module Bolt
|
7
|
+
class ModuleInstaller
|
8
|
+
def initialize(outputter, pal)
|
9
|
+
@outputter = outputter
|
10
|
+
@pal = pal
|
11
|
+
@logger = Bolt::Logger.logger(self)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Adds a single module to the project.
|
15
|
+
#
|
16
|
+
def add(name, modules, puppetfile_path, moduledir, config_path)
|
17
|
+
require 'bolt/puppetfile'
|
18
|
+
|
19
|
+
@outputter.print_message("Adding module #{name} to project\n\n")
|
20
|
+
|
21
|
+
# If the project configuration file already includes this module,
|
22
|
+
# exit early.
|
23
|
+
puppetfile = Bolt::Puppetfile.new(modules)
|
24
|
+
new_module = Bolt::Puppetfile::Module.from_hash('name' => name)
|
25
|
+
|
26
|
+
if puppetfile.modules.include?(new_module)
|
27
|
+
@outputter.print_action_step(
|
28
|
+
"Project configuration file #{config_path} already includes module #{new_module}. Nothing to do."
|
29
|
+
)
|
30
|
+
return true
|
31
|
+
end
|
32
|
+
|
33
|
+
# If the Puppetfile exists, make sure it's managed by Bolt.
|
34
|
+
if puppetfile_path.exist?
|
35
|
+
assert_managed_puppetfile(puppetfile, puppetfile_path)
|
36
|
+
existing = Bolt::Puppetfile.parse(puppetfile_path)
|
37
|
+
else
|
38
|
+
existing = Bolt::Puppetfile.new
|
39
|
+
end
|
40
|
+
|
41
|
+
# Create a Puppetfile object that includes the new module and its
|
42
|
+
# dependencies. We error early here so we don't add the new module to the
|
43
|
+
# project config or modify the Puppetfile.
|
44
|
+
puppetfile = add_new_module_to_puppetfile(new_module, modules, puppetfile_path)
|
45
|
+
|
46
|
+
# Display the diff between the existing Puppetfile and the new Puppetfile.
|
47
|
+
print_puppetfile_diff(existing, puppetfile)
|
48
|
+
|
49
|
+
# Add the module to the project configuration.
|
50
|
+
@outputter.print_action_step("Updating project configuration file at #{config_path}")
|
51
|
+
|
52
|
+
data = Bolt::Util.read_yaml_hash(config_path, 'project')
|
53
|
+
data['modules'] ||= []
|
54
|
+
data['modules'] << { 'name' => new_module.title }
|
55
|
+
|
56
|
+
begin
|
57
|
+
File.write(config_path, data.to_yaml)
|
58
|
+
rescue SystemCallError => e
|
59
|
+
raise Bolt::FileError.new(
|
60
|
+
"Unable to update project configuration file: #{e.message}",
|
61
|
+
config
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Write the Puppetfile.
|
66
|
+
@outputter.print_action_step("Writing Puppetfile at #{puppetfile_path}")
|
67
|
+
puppetfile.write(puppetfile_path, moduledir)
|
68
|
+
|
69
|
+
# Install the modules.
|
70
|
+
install_puppetfile(puppetfile_path, moduledir)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Creates a new Puppetfile that includes the new module and its dependencies.
|
74
|
+
#
|
75
|
+
private def add_new_module_to_puppetfile(new_module, modules, path)
|
76
|
+
@outputter.print_action_step("Resolving module dependencies, this may take a moment")
|
77
|
+
|
78
|
+
# If there is an existing Puppetfile, add the new module and attempt
|
79
|
+
# to resolve. This will not update the versions of any installed modules.
|
80
|
+
if path.exist?
|
81
|
+
puppetfile = Bolt::Puppetfile.parse(path)
|
82
|
+
puppetfile.add_modules(new_module)
|
83
|
+
|
84
|
+
begin
|
85
|
+
puppetfile.resolve
|
86
|
+
return puppetfile
|
87
|
+
rescue Bolt::Error
|
88
|
+
@logger.debug "Unable to find a version of #{new_module} compatible "\
|
89
|
+
"with installed modules. Attempting to re-resolve modules "\
|
90
|
+
"from project configuration; some versions of installed "\
|
91
|
+
"modules may change."
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# If there is not an existing Puppetfile, or resolving with pinned
|
96
|
+
# modules fails, resolve all of the module declarations with the new
|
97
|
+
# module.
|
98
|
+
puppetfile = Bolt::Puppetfile.new(modules)
|
99
|
+
puppetfile.add_modules(new_module)
|
100
|
+
puppetfile.resolve
|
101
|
+
puppetfile
|
102
|
+
end
|
103
|
+
|
104
|
+
# Outputs a diff of an old Puppetfile and a new Puppetfile.
|
105
|
+
#
|
106
|
+
def print_puppetfile_diff(old, new)
|
107
|
+
# Build hashes mapping the module title to the module object. This makes it
|
108
|
+
# a little easier to determine which modules have been added, removed, or
|
109
|
+
# modified.
|
110
|
+
old = old.modules.each_with_object({}) do |mod, acc|
|
111
|
+
acc[mod.title] = mod
|
112
|
+
end
|
113
|
+
|
114
|
+
new = new.modules.each_with_object({}) do |mod, acc|
|
115
|
+
acc[mod.title] = mod
|
116
|
+
end
|
117
|
+
|
118
|
+
# New modules are those present in new but not in old.
|
119
|
+
added = new.reject { |title, _mod| old.include?(title) }.values
|
120
|
+
|
121
|
+
if added.any?
|
122
|
+
diff = "Adding the following modules:\n"
|
123
|
+
added.each { |mod| diff += "#{mod.title} #{mod.version}\n" }
|
124
|
+
@outputter.print_action_step(diff)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Upgraded modules are those that have a newer version in new than old.
|
128
|
+
upgraded = new.select do |title, mod|
|
129
|
+
if old.include?(title)
|
130
|
+
SemanticPuppet::Version.parse(mod.version) > SemanticPuppet::Version.parse(old[title].version)
|
131
|
+
end
|
132
|
+
end.keys
|
133
|
+
|
134
|
+
if upgraded.any?
|
135
|
+
diff = "Upgrading the following modules:\n"
|
136
|
+
upgraded.each { |title| diff += "#{title} #{old[title].version} to #{new[title].version}\n" }
|
137
|
+
@outputter.print_action_step(diff)
|
138
|
+
end
|
139
|
+
|
140
|
+
# Downgraded modules are those that have an older version in new than old.
|
141
|
+
downgraded = new.select do |title, mod|
|
142
|
+
if old.include?(title)
|
143
|
+
SemanticPuppet::Version.parse(mod.version) < SemanticPuppet::Version.parse(old[title].version)
|
144
|
+
end
|
145
|
+
end.keys
|
146
|
+
|
147
|
+
if downgraded.any?
|
148
|
+
diff = "Downgrading the following modules: \n"
|
149
|
+
downgraded.each { |title| diff += "#{title} #{old[title].version} to #{new[title].version}\n" }
|
150
|
+
@outputter.print_action_step(diff)
|
151
|
+
end
|
152
|
+
|
153
|
+
# Removed modules are those present in old but not in new.
|
154
|
+
removed = old.reject { |title, _mod| new.include?(title) }.values
|
155
|
+
|
156
|
+
if removed.any?
|
157
|
+
diff = "Removing the following modules:\n"
|
158
|
+
removed.each { |mod| diff += "#{mod.title} #{mod.version}\n" }
|
159
|
+
@outputter.print_action_step(diff)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# Installs a project's module dependencies.
|
164
|
+
#
|
165
|
+
def install(modules, path, moduledir, force: false, resolve: true)
|
166
|
+
require 'bolt/puppetfile'
|
167
|
+
|
168
|
+
@outputter.print_message("Installing project modules\n\n")
|
169
|
+
|
170
|
+
puppetfile = Bolt::Puppetfile.new(modules)
|
171
|
+
|
172
|
+
# If the Puppetfile exists, check if it includes specs for each declared
|
173
|
+
# module, erroring if there are any missing. Otherwise, resolve the
|
174
|
+
# module dependencies and write a new Puppetfile. Users can forcibly
|
175
|
+
# overwrite an existing Puppetfile with the '--force' option, or opt to
|
176
|
+
# install the Puppetfile as-is with --no-resolve.
|
177
|
+
#
|
178
|
+
# This is just if resolve is not false (nil should default to true)
|
179
|
+
if resolve != false
|
180
|
+
if path.exist? && !force
|
181
|
+
assert_managed_puppetfile(puppetfile, path)
|
182
|
+
else
|
183
|
+
@outputter.print_action_step("Resolving module dependencies, this may take a moment")
|
184
|
+
puppetfile.resolve
|
185
|
+
|
186
|
+
@outputter.print_action_step("Writing Puppetfile at #{path}")
|
187
|
+
# We get here either through 'bolt module install' which uses the
|
188
|
+
# managed modulepath (which isn't configurable) or through bolt
|
189
|
+
# project init --modules, which uses the default modulepath. This
|
190
|
+
# should be safe to assume that if `.modules/` is the moduledir the
|
191
|
+
# user is using the new workflow
|
192
|
+
if moduledir.basename.to_s == '.modules'
|
193
|
+
puppetfile.write(path, moduledir)
|
194
|
+
else
|
195
|
+
puppetfile.write(path)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# Install the modules.
|
201
|
+
install_puppetfile(path, moduledir)
|
202
|
+
end
|
203
|
+
|
204
|
+
# Installs the Puppetfile and generates types.
|
205
|
+
#
|
206
|
+
def install_puppetfile(path, moduledir, config = {})
|
207
|
+
require 'bolt/puppetfile/installer'
|
208
|
+
|
209
|
+
@outputter.print_action_step("Syncing modules from #{path} to #{moduledir}")
|
210
|
+
ok = Bolt::Puppetfile::Installer.new(config).install(path, moduledir)
|
211
|
+
|
212
|
+
# Automatically generate types after installing modules
|
213
|
+
@pal.generate_types
|
214
|
+
|
215
|
+
@outputter.print_puppetfile_result(ok, path, moduledir)
|
216
|
+
|
217
|
+
ok
|
218
|
+
end
|
219
|
+
|
220
|
+
# Asserts that an existing Puppetfile is managed by Bolt.
|
221
|
+
#
|
222
|
+
private def assert_managed_puppetfile(puppetfile, path)
|
223
|
+
existing_puppetfile = Bolt::Puppetfile.parse(path)
|
224
|
+
|
225
|
+
unless existing_puppetfile.modules.superset? puppetfile.modules
|
226
|
+
missing_modules = puppetfile.modules - existing_puppetfile.modules
|
227
|
+
|
228
|
+
message = <<~MESSAGE.chomp
|
229
|
+
Puppetfile #{path} is missing specifications for the following
|
230
|
+
module declarations:
|
231
|
+
|
232
|
+
#{missing_modules.map(&:to_hash).to_yaml.lines.drop(1).join.chomp}
|
233
|
+
|
234
|
+
This may not be a Puppetfile managed by Bolt. To forcibly overwrite the
|
235
|
+
Puppetfile, run 'bolt module install --force'.
|
236
|
+
MESSAGE
|
237
|
+
|
238
|
+
raise Bolt::Error.new(message, 'bolt/missing-module-specs')
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|