bolt 2.30.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 +9 -9
- data/bolt-modules/boltlib/lib/puppet/functions/write_file.rb +2 -2
- data/lib/bolt/cli.rb +23 -6
- data/lib/bolt/config/modulepath.rb +30 -0
- data/lib/bolt/config/transport/options.rb +1 -1
- data/lib/bolt/inventory.rb +10 -9
- data/lib/bolt/module_installer.rb +79 -9
- data/lib/bolt/outputter/human.rb +26 -8
- data/lib/bolt/outputter/json.rb +16 -7
- data/lib/bolt/pal.rb +22 -16
- data/lib/bolt/plugin.rb +1 -1
- data/lib/bolt/project.rb +1 -1
- data/lib/bolt/project_migrator.rb +1 -1
- data/lib/bolt/project_migrator/base.rb +2 -2
- data/lib/bolt/project_migrator/config.rb +3 -3
- data/lib/bolt/project_migrator/inventory.rb +1 -1
- data/lib/bolt/project_migrator/modules.rb +13 -13
- data/lib/bolt/puppetfile.rb +9 -2
- data/lib/bolt/puppetfile/module.rb +4 -1
- data/lib/bolt/shell/bash.rb +3 -2
- data/lib/bolt/transport/ssh/connection.rb +1 -1
- data/lib/bolt/version.rb +1 -1
- 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/run.rb +1 -1
- metadata +3 -3
- data/lib/bolt_server/pe/pal.rb +0 -67
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4b9f29b79c8544029c9a69f6dc76b083857a87e178c9aae0359e49c59ce3cfdb
|
4
|
+
data.tar.gz: 02166a6dda2dc381365b7556f506a419e2717267e88f6015af430f7f725d75d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3a282194ca9ccf988e7282afc3a3a0b57b4edc16bb5bf61790fb0eb0ef234e0c7a76c0ea6cd44915047a99e6d423311be1307f435d8000c568d0552268f6afa6
|
7
|
+
data.tar.gz: 957e6be1a72af03bd448fe070e6f9bb0b78aa1bb65e90a8bda251ef0f6c56e5ffaa8ff64aa0c5852963d9fecb87144b61ffd24494fe0aabcbdff43ecde9947a3
|
data/Puppetfile
CHANGED
@@ -7,28 +7,28 @@ moduledir File.join(File.dirname(__FILE__), 'modules')
|
|
7
7
|
# Core modules used by 'apply'
|
8
8
|
mod 'puppetlabs-service', '1.3.0'
|
9
9
|
mod 'puppetlabs-puppet_agent', '4.1.1'
|
10
|
-
mod 'puppetlabs-facts', '1.
|
10
|
+
mod 'puppetlabs-facts', '1.1.0'
|
11
11
|
|
12
12
|
# Core types and providers for Puppet 6
|
13
|
-
mod 'puppetlabs-augeas_core', '1.
|
13
|
+
mod 'puppetlabs-augeas_core', '1.1.1'
|
14
14
|
mod 'puppetlabs-host_core', '1.0.3'
|
15
|
-
mod 'puppetlabs-scheduled_task', '2.
|
16
|
-
mod 'puppetlabs-sshkeys_core', '1.0
|
17
|
-
mod 'puppetlabs-zfs_core', '1.0
|
18
|
-
mod 'puppetlabs-cron_core', '1.0.
|
15
|
+
mod 'puppetlabs-scheduled_task', '2.2.1'
|
16
|
+
mod 'puppetlabs-sshkeys_core', '2.1.0'
|
17
|
+
mod 'puppetlabs-zfs_core', '1.1.0'
|
18
|
+
mod 'puppetlabs-cron_core', '1.0.4'
|
19
19
|
mod 'puppetlabs-mount_core', '1.0.4'
|
20
20
|
mod 'puppetlabs-selinux_core', '1.0.4'
|
21
|
-
mod 'puppetlabs-yumrepo_core', '1.0.
|
21
|
+
mod 'puppetlabs-yumrepo_core', '1.0.7'
|
22
22
|
mod 'puppetlabs-zone_core', '1.0.3'
|
23
23
|
|
24
24
|
# Useful additional modules
|
25
|
-
mod 'puppetlabs-package', '1.
|
25
|
+
mod 'puppetlabs-package', '1.3.0'
|
26
26
|
mod 'puppetlabs-puppet_conf', '0.6.0'
|
27
27
|
mod 'puppetlabs-python_task_helper', '0.4.3'
|
28
28
|
mod 'puppetlabs-reboot', '3.0.0'
|
29
29
|
mod 'puppetlabs-ruby_task_helper', '0.5.1'
|
30
30
|
mod 'puppetlabs-ruby_plugin_helper', '0.1.0'
|
31
|
-
mod 'puppetlabs-stdlib', '6.
|
31
|
+
mod 'puppetlabs-stdlib', '6.5.0'
|
32
32
|
|
33
33
|
# Plugin modules
|
34
34
|
mod 'puppetlabs-aws_inventory', '0.5.2'
|
@@ -6,15 +6,15 @@ require 'tempfile'
|
|
6
6
|
#
|
7
7
|
# > **Note:** Not available in apply block
|
8
8
|
Puppet::Functions.create_function(:write_file) do
|
9
|
-
# @param targets A pattern identifying zero or more targets. See {get_targets} for accepted patterns.
|
10
9
|
# @param content File content to write.
|
11
10
|
# @param destination An absolute path on the target(s).
|
11
|
+
# @param targets A pattern identifying zero or more targets. See {get_targets} for accepted patterns.
|
12
12
|
# @option options [Boolean] _catch_errors Whether to catch raised errors.
|
13
13
|
# @option options [String] _run_as User to run as using privilege escalation.
|
14
14
|
# @return A list of results, one entry per target.
|
15
15
|
# @example Write a file to a target
|
16
16
|
# $content = 'Hello, world!'
|
17
|
-
# write_file($
|
17
|
+
# write_file($content, '/Users/me/hello.txt', $targets)
|
18
18
|
dispatch :write_file do
|
19
19
|
required_param 'String', :content
|
20
20
|
required_param 'String[1]', :destination
|
data/lib/bolt/cli.rb
CHANGED
@@ -587,8 +587,24 @@ module Bolt
|
|
587
587
|
end
|
588
588
|
|
589
589
|
def list_targets
|
590
|
+
inventoryfile = config.inventoryfile || config.default_inventoryfile
|
591
|
+
|
592
|
+
# Retrieve the known group and target names. This needs to be done before
|
593
|
+
# updating targets, as that will add adhoc targets to the inventory.
|
594
|
+
known_names = inventory.target_names
|
595
|
+
|
590
596
|
update_targets(options)
|
591
|
-
|
597
|
+
|
598
|
+
inventory_targets, adhoc_targets = options[:targets].partition do |target|
|
599
|
+
known_names.include?(target.name)
|
600
|
+
end
|
601
|
+
|
602
|
+
target_list = {
|
603
|
+
inventory: inventory_targets,
|
604
|
+
adhoc: adhoc_targets
|
605
|
+
}
|
606
|
+
|
607
|
+
outputter.print_targets(target_list, inventoryfile)
|
592
608
|
end
|
593
609
|
|
594
610
|
def show_targets
|
@@ -617,10 +633,10 @@ module Bolt
|
|
617
633
|
message = <<~MESSAGE.chomp
|
618
634
|
Invalid plan name '#{plan_name}'. Plan names are composed of one or more name segments
|
619
635
|
separated by double colons '::'.
|
620
|
-
|
636
|
+
|
621
637
|
Each name segment must begin with a lowercase letter, and may only include lowercase
|
622
638
|
letters, digits, and underscores.
|
623
|
-
|
639
|
+
|
624
640
|
Examples of valid plan names:
|
625
641
|
- #{config.project.name}
|
626
642
|
- #{config.project.name}::my_plan
|
@@ -938,6 +954,7 @@ module Bolt
|
|
938
954
|
# Loads a Puppetfile and installs its modules.
|
939
955
|
#
|
940
956
|
def install_puppetfile(config, puppetfile, moduledir)
|
957
|
+
outputter.print_message("Installing modules from Puppetfile")
|
941
958
|
installer = Bolt::ModuleInstaller.new(outputter, pal)
|
942
959
|
ok = installer.install_puppetfile(puppetfile, moduledir, config)
|
943
960
|
ok ? 0 : 1
|
@@ -962,7 +979,7 @@ module Bolt
|
|
962
979
|
end
|
963
980
|
|
964
981
|
def pal
|
965
|
-
@pal ||= Bolt::PAL.new(config.modulepath,
|
982
|
+
@pal ||= Bolt::PAL.new(Bolt::Config::Modulepath.new(config.modulepath),
|
966
983
|
config.hiera_config,
|
967
984
|
config.project.resource_types,
|
968
985
|
config.compile_concurrency,
|
@@ -1061,7 +1078,7 @@ module Bolt
|
|
1061
1078
|
'Task' => [],
|
1062
1079
|
'Plugin' => Bolt::Plugin::BUILTIN_PLUGINS }
|
1063
1080
|
if %w[plan task].include?(options[:subcommand]) && options[:action] == 'run'
|
1064
|
-
default_content = Bolt::PAL.new([], nil, nil)
|
1081
|
+
default_content = Bolt::PAL.new(Bolt::Config::Modulepath.new([]), nil, nil)
|
1065
1082
|
content['Plan'] = default_content.list_plans.each_with_object([]) do |iter, col|
|
1066
1083
|
col << iter&.first
|
1067
1084
|
end
|
@@ -1076,7 +1093,7 @@ module Bolt
|
|
1076
1093
|
# Gem installs include the aggregate, canary, and puppetdb_fact modules, while
|
1077
1094
|
# package installs include modules listed in the Bolt repo Puppetfile
|
1078
1095
|
def incomplete_install?
|
1079
|
-
(Dir.children(Bolt::
|
1096
|
+
(Dir.children(Bolt::Config::Modulepath::MODULES_PATH) - %w[aggregate canary puppetdb_fact secure_env_vars]).empty?
|
1080
1097
|
end
|
1081
1098
|
|
1082
1099
|
# Mimicks the output from Outputter::Human#fatal_error. This should be used to print
|
@@ -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
|
@@ -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/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
|
@@ -16,20 +16,26 @@ module Bolt
|
|
16
16
|
def add(name, modules, puppetfile_path, moduledir, config_path)
|
17
17
|
require 'bolt/puppetfile'
|
18
18
|
|
19
|
+
@outputter.print_message("Adding module #{name} to project\n\n")
|
20
|
+
|
19
21
|
# If the project configuration file already includes this module,
|
20
22
|
# exit early.
|
21
23
|
puppetfile = Bolt::Puppetfile.new(modules)
|
22
24
|
new_module = Bolt::Puppetfile::Module.from_hash('name' => name)
|
23
25
|
|
24
26
|
if puppetfile.modules.include?(new_module)
|
25
|
-
@outputter.
|
26
|
-
|
27
|
+
@outputter.print_action_step(
|
28
|
+
"Project configuration file #{config_path} already includes module #{new_module}. Nothing to do."
|
29
|
+
)
|
27
30
|
return true
|
28
31
|
end
|
29
32
|
|
30
33
|
# If the Puppetfile exists, make sure it's managed by Bolt.
|
31
34
|
if puppetfile_path.exist?
|
32
35
|
assert_managed_puppetfile(puppetfile, puppetfile_path)
|
36
|
+
existing = Bolt::Puppetfile.parse(puppetfile_path)
|
37
|
+
else
|
38
|
+
existing = Bolt::Puppetfile.new
|
33
39
|
end
|
34
40
|
|
35
41
|
# Create a Puppetfile object that includes the new module and its
|
@@ -37,8 +43,11 @@ module Bolt
|
|
37
43
|
# project config or modify the Puppetfile.
|
38
44
|
puppetfile = add_new_module_to_puppetfile(new_module, modules, puppetfile_path)
|
39
45
|
|
46
|
+
# Display the diff between the existing Puppetfile and the new Puppetfile.
|
47
|
+
print_puppetfile_diff(existing, puppetfile)
|
48
|
+
|
40
49
|
# Add the module to the project configuration.
|
41
|
-
@outputter.
|
50
|
+
@outputter.print_action_step("Updating project configuration file at #{config_path}")
|
42
51
|
|
43
52
|
data = Bolt::Util.read_yaml_hash(config_path, 'project')
|
44
53
|
data['modules'] ||= []
|
@@ -54,7 +63,7 @@ module Bolt
|
|
54
63
|
end
|
55
64
|
|
56
65
|
# Write the Puppetfile.
|
57
|
-
@outputter.
|
66
|
+
@outputter.print_action_step("Writing Puppetfile at #{puppetfile_path}")
|
58
67
|
puppetfile.write(puppetfile_path, moduledir)
|
59
68
|
|
60
69
|
# Install the modules.
|
@@ -64,7 +73,7 @@ module Bolt
|
|
64
73
|
# Creates a new Puppetfile that includes the new module and its dependencies.
|
65
74
|
#
|
66
75
|
private def add_new_module_to_puppetfile(new_module, modules, path)
|
67
|
-
@outputter.
|
76
|
+
@outputter.print_action_step("Resolving module dependencies, this may take a moment")
|
68
77
|
|
69
78
|
# If there is an existing Puppetfile, add the new module and attempt
|
70
79
|
# to resolve. This will not update the versions of any installed modules.
|
@@ -92,11 +101,72 @@ module Bolt
|
|
92
101
|
puppetfile
|
93
102
|
end
|
94
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
|
+
|
95
163
|
# Installs a project's module dependencies.
|
96
164
|
#
|
97
165
|
def install(modules, path, moduledir, force: false, resolve: true)
|
98
166
|
require 'bolt/puppetfile'
|
99
167
|
|
168
|
+
@outputter.print_message("Installing project modules\n\n")
|
169
|
+
|
100
170
|
puppetfile = Bolt::Puppetfile.new(modules)
|
101
171
|
|
102
172
|
# If the Puppetfile exists, check if it includes specs for each declared
|
@@ -110,16 +180,16 @@ module Bolt
|
|
110
180
|
if path.exist? && !force
|
111
181
|
assert_managed_puppetfile(puppetfile, path)
|
112
182
|
else
|
113
|
-
@outputter.
|
183
|
+
@outputter.print_action_step("Resolving module dependencies, this may take a moment")
|
114
184
|
puppetfile.resolve
|
115
185
|
|
116
|
-
@outputter.
|
186
|
+
@outputter.print_action_step("Writing Puppetfile at #{path}")
|
117
187
|
# We get here either through 'bolt module install' which uses the
|
118
188
|
# managed modulepath (which isn't configurable) or through bolt
|
119
189
|
# project init --modules, which uses the default modulepath. This
|
120
190
|
# should be safe to assume that if `.modules/` is the moduledir the
|
121
191
|
# user is using the new workflow
|
122
|
-
if moduledir.basename == '.modules'
|
192
|
+
if moduledir.basename.to_s == '.modules'
|
123
193
|
puppetfile.write(path, moduledir)
|
124
194
|
else
|
125
195
|
puppetfile.write(path)
|
@@ -136,7 +206,7 @@ module Bolt
|
|
136
206
|
def install_puppetfile(path, moduledir, config = {})
|
137
207
|
require 'bolt/puppetfile/installer'
|
138
208
|
|
139
|
-
@outputter.
|
209
|
+
@outputter.print_action_step("Syncing modules from #{path} to #{moduledir}")
|
140
210
|
ok = Bolt::Puppetfile::Installer.new(config).install(path, moduledir)
|
141
211
|
|
142
212
|
# Automatically generate types after installing modules
|
data/lib/bolt/outputter/human.rb
CHANGED
@@ -248,7 +248,7 @@ module Bolt
|
|
248
248
|
task_info << "MODULE:\n"
|
249
249
|
|
250
250
|
path = task.files.first['path'].chomp("/tasks/#{task.files.first['name']}")
|
251
|
-
task_info << if path.start_with?(Bolt::
|
251
|
+
task_info << if path.start_with?(Bolt::Config::Modulepath::MODULES_PATH)
|
252
252
|
"built-in module"
|
253
253
|
else
|
254
254
|
path
|
@@ -278,7 +278,7 @@ module Bolt
|
|
278
278
|
plan_info << "MODULE:\n"
|
279
279
|
|
280
280
|
path = plan['module']
|
281
|
-
plan_info << if path.start_with?(Bolt::
|
281
|
+
plan_info << if path.start_with?(Bolt::Config::Modulepath::MODULES_PATH)
|
282
282
|
"built-in module"
|
283
283
|
else
|
284
284
|
path
|
@@ -331,10 +331,28 @@ module Bolt
|
|
331
331
|
end
|
332
332
|
end
|
333
333
|
|
334
|
-
def print_targets(
|
335
|
-
|
336
|
-
|
337
|
-
|
334
|
+
def print_targets(target_list, inventoryfile)
|
335
|
+
adhoc = colorize(:yellow, "(Not found in inventory file)")
|
336
|
+
|
337
|
+
targets = []
|
338
|
+
targets += target_list[:inventory].map { |target| [target.name, nil] }
|
339
|
+
targets += target_list[:adhoc].map { |target| [target.name, adhoc] }
|
340
|
+
|
341
|
+
if targets.any?
|
342
|
+
print_table(targets, 0, 2)
|
343
|
+
@stream.puts
|
344
|
+
end
|
345
|
+
|
346
|
+
@stream.puts "INVENTORY FILE:"
|
347
|
+
if inventoryfile.exist?
|
348
|
+
@stream.puts inventoryfile
|
349
|
+
else
|
350
|
+
@stream.puts wrap("Tried to load inventory from #{inventoryfile}, but the file does not exist")
|
351
|
+
end
|
352
|
+
|
353
|
+
@stream.puts "\nTARGET COUNT:"
|
354
|
+
@stream.puts "#{targets.count} total, #{target_list[:inventory].count} from inventory, "\
|
355
|
+
"#{target_list[:adhoc].count} adhoc"
|
338
356
|
end
|
339
357
|
|
340
358
|
def print_target_info(targets)
|
@@ -413,7 +431,7 @@ module Bolt
|
|
413
431
|
@stream.puts(colorize(:red, indent(4, message)))
|
414
432
|
end
|
415
433
|
|
416
|
-
def
|
434
|
+
def print_action_step(step)
|
417
435
|
first, *remaining = wrap(step, 76).lines
|
418
436
|
|
419
437
|
first = indent(2, "→ #{first}")
|
@@ -423,7 +441,7 @@ module Bolt
|
|
423
441
|
@stream.puts(step)
|
424
442
|
end
|
425
443
|
|
426
|
-
def
|
444
|
+
def print_action_error(error)
|
427
445
|
# Running everything through 'wrap' messes with newlines. Separating
|
428
446
|
# into lines and wrapping each individually ensures separate errors are
|
429
447
|
# distinguishable.
|
data/lib/bolt/outputter/json.rb
CHANGED
@@ -48,7 +48,7 @@ module Bolt
|
|
48
48
|
|
49
49
|
def print_task_info(task)
|
50
50
|
path = task.files.first['path'].chomp("/tasks/#{task.files.first['name']}")
|
51
|
-
module_dir = if path.start_with?(Bolt::
|
51
|
+
module_dir = if path.start_with?(Bolt::Config::Modulepath::MODULES_PATH)
|
52
52
|
"built-in module"
|
53
53
|
else
|
54
54
|
path
|
@@ -62,7 +62,7 @@ module Bolt
|
|
62
62
|
|
63
63
|
def print_plan_info(plan)
|
64
64
|
path = plan.delete('module')
|
65
|
-
plan['module_dir'] = if path.start_with?(Bolt::
|
65
|
+
plan['module_dir'] = if path.start_with?(Bolt::Config::Modulepath::MODULES_PATH)
|
66
66
|
"built-in module"
|
67
67
|
else
|
68
68
|
path
|
@@ -100,10 +100,19 @@ module Bolt
|
|
100
100
|
"moduledir": moduledir.to_s }.to_json)
|
101
101
|
end
|
102
102
|
|
103
|
-
def print_targets(
|
103
|
+
def print_targets(target_list, inventoryfile)
|
104
104
|
@stream.puts ::JSON.pretty_generate(
|
105
|
-
"
|
106
|
-
|
105
|
+
"inventory": {
|
106
|
+
"targets": target_list[:inventory].map(&:name),
|
107
|
+
"count": target_list[:inventory].count,
|
108
|
+
"file": inventoryfile.to_s
|
109
|
+
},
|
110
|
+
"adhoc": {
|
111
|
+
"targets": target_list[:adhoc].map(&:name),
|
112
|
+
"count": target_list[:adhoc].count
|
113
|
+
},
|
114
|
+
"targets": target_list.values.flatten.map(&:name),
|
115
|
+
"count": target_list.values.flatten.count
|
107
116
|
)
|
108
117
|
end
|
109
118
|
|
@@ -137,10 +146,10 @@ module Bolt
|
|
137
146
|
end
|
138
147
|
alias print_error print_message
|
139
148
|
|
140
|
-
def
|
149
|
+
def print_action_step(step)
|
141
150
|
$stderr.puts(step)
|
142
151
|
end
|
143
|
-
alias
|
152
|
+
alias print_action_error print_action_step
|
144
153
|
end
|
145
154
|
end
|
146
155
|
end
|
data/lib/bolt/pal.rb
CHANGED
@@ -5,18 +5,16 @@ require 'bolt/executor'
|
|
5
5
|
require 'bolt/error'
|
6
6
|
require 'bolt/plan_result'
|
7
7
|
require 'bolt/util'
|
8
|
+
require 'bolt/config/modulepath'
|
8
9
|
require 'etc'
|
9
10
|
|
10
11
|
module Bolt
|
11
12
|
class PAL
|
12
|
-
BOLTLIB_PATH = File.expand_path('../../bolt-modules', __dir__)
|
13
|
-
MODULES_PATH = File.expand_path('../../modules', __dir__)
|
14
|
-
|
15
13
|
# PALError is used to convert errors from executing puppet code into
|
16
14
|
# Bolt::Errors
|
17
15
|
class PALError < Bolt::Error
|
18
16
|
def self.from_preformatted_error(err)
|
19
|
-
if err.cause
|
17
|
+
if err.cause.is_a? Bolt::Error
|
20
18
|
err.cause
|
21
19
|
else
|
22
20
|
from_error(err)
|
@@ -45,16 +43,16 @@ module Bolt
|
|
45
43
|
end
|
46
44
|
end
|
47
45
|
|
48
|
-
attr_reader :modulepath, :user_modulepath
|
49
|
-
|
50
46
|
def initialize(modulepath, hiera_config, resource_types, max_compiles = Etc.nprocessors,
|
51
47
|
trusted_external = nil, apply_settings = {}, project = nil)
|
48
|
+
unless modulepath.is_a?(Bolt::Config::Modulepath)
|
49
|
+
msg = "Type error in PAL: modulepath must be a Bolt::Config::Modulepath"
|
50
|
+
raise Bolt::Error.new(msg, "bolt/execution-error")
|
51
|
+
end
|
52
52
|
# Nothing works without initialized this global state. Reinitializing
|
53
53
|
# is safe and in practice only happens in tests
|
54
54
|
self.class.load_puppet
|
55
|
-
|
56
|
-
@user_modulepath = modulepath
|
57
|
-
@modulepath = [BOLTLIB_PATH, *modulepath, MODULES_PATH]
|
55
|
+
@modulepath = modulepath
|
58
56
|
@hiera_config = hiera_config
|
59
57
|
@trusted_external = trusted_external
|
60
58
|
@apply_settings = apply_settings
|
@@ -63,13 +61,21 @@ module Bolt
|
|
63
61
|
@project = project
|
64
62
|
|
65
63
|
@logger = Bolt::Logger.logger(self)
|
66
|
-
|
67
|
-
@logger.debug("Loading modules from #{
|
64
|
+
unless user_modulepath.empty?
|
65
|
+
@logger.debug("Loading modules from #{full_modulepath.join(File::PATH_SEPARATOR)}")
|
68
66
|
end
|
69
67
|
|
70
68
|
@loaded = false
|
71
69
|
end
|
72
70
|
|
71
|
+
def full_modulepath
|
72
|
+
@modulepath.full_modulepath
|
73
|
+
end
|
74
|
+
|
75
|
+
def user_modulepath
|
76
|
+
@modulepath.user_modulepath
|
77
|
+
end
|
78
|
+
|
73
79
|
# Puppet logging is global so this is class method to avoid confusion
|
74
80
|
def self.configure_logging
|
75
81
|
Puppet::Util::Log.destinations.clear
|
@@ -157,7 +163,7 @@ module Bolt
|
|
157
163
|
def in_bolt_compiler
|
158
164
|
# TODO: If we always call this inside a bolt_executor we can remove this here
|
159
165
|
setup
|
160
|
-
r = Puppet::Pal.in_tmp_environment('bolt', modulepath:
|
166
|
+
r = Puppet::Pal.in_tmp_environment('bolt', modulepath: full_modulepath, facts: {}) do |pal|
|
161
167
|
# Only load the project if it a) exists, b) has a name it can be loaded with
|
162
168
|
Puppet.override(bolt_project: @project,
|
163
169
|
yaml_plan_instantiator: Bolt::PAL::YamlPlan::Loader) do
|
@@ -212,11 +218,11 @@ module Bolt
|
|
212
218
|
apply_executor: applicator || Applicator.new(
|
213
219
|
inventory,
|
214
220
|
executor,
|
215
|
-
|
221
|
+
full_modulepath,
|
216
222
|
# Skip syncing built-in plugins, since we vendor some Puppet 6
|
217
223
|
# versions of "core" types, which are already present on the agent,
|
218
224
|
# but may cause issues on Puppet 5 agents.
|
219
|
-
|
225
|
+
user_modulepath,
|
220
226
|
@project,
|
221
227
|
pdb_client,
|
222
228
|
@hiera_config,
|
@@ -443,8 +449,8 @@ module Bolt
|
|
443
449
|
# The information hash provides the name, version, and a string
|
444
450
|
# indicating whether the module belongs to an internal module group.
|
445
451
|
def list_modules
|
446
|
-
internal_module_groups = { BOLTLIB_PATH => 'Plan Language Modules',
|
447
|
-
MODULES_PATH => 'Packaged Modules',
|
452
|
+
internal_module_groups = { Bolt::Config::Modulepath::BOLTLIB_PATH => 'Plan Language Modules',
|
453
|
+
Bolt::Config::Modulepath::MODULES_PATH => 'Packaged Modules',
|
448
454
|
@project.managed_moduledir.to_s => 'Project Dependencies' }
|
449
455
|
|
450
456
|
in_bolt_compiler do
|
data/lib/bolt/plugin.rb
CHANGED
data/lib/bolt/project.rb
CHANGED
@@ -190,7 +190,7 @@ module Bolt
|
|
190
190
|
Invalid project name '#{name}' in bolt-project.yaml; project name must begin with a lowercase letter
|
191
191
|
and can include lowercase letters, numbers, and underscores.
|
192
192
|
ERROR_STRING
|
193
|
-
elsif Dir.children(Bolt::
|
193
|
+
elsif Dir.children(Bolt::Config::Modulepath::BOLTLIB_PATH).include?(name)
|
194
194
|
raise Bolt::ValidationError, "The project '#{name}' will not be loaded. The project name conflicts "\
|
195
195
|
"with a built-in Bolt module of the same name."
|
196
196
|
end
|
@@ -21,7 +21,7 @@ module Bolt
|
|
21
21
|
|
22
22
|
@outputter.print_message("Migrating project #{@config.project.path}\n\n")
|
23
23
|
|
24
|
-
@outputter.
|
24
|
+
@outputter.print_action_step(
|
25
25
|
"Migrating a Bolt project may make irreversible changes to the project's "\
|
26
26
|
"configuration and inventory files. Before continuing, make sure the "\
|
27
27
|
"project has a backup or uses a version control system."
|
@@ -12,7 +12,7 @@ module Bolt
|
|
12
12
|
|
13
13
|
protected def backup_file(origin_path, backup_dir)
|
14
14
|
unless File.exist?(origin_path)
|
15
|
-
@outputter.
|
15
|
+
@outputter.print_action_step(
|
16
16
|
"Could not find file #{origin_path}, skipping backup."
|
17
17
|
)
|
18
18
|
return
|
@@ -24,7 +24,7 @@ module Bolt
|
|
24
24
|
filename = File.basename(origin_path)
|
25
25
|
backup_path = File.join(backup_dir, "#{filename}.#{date}.bak")
|
26
26
|
|
27
|
-
@outputter.
|
27
|
+
@outputter.print_action_step(
|
28
28
|
"Backing up #{filename} from #{origin_path} to #{backup_path}"
|
29
29
|
)
|
30
30
|
|
@@ -39,7 +39,7 @@ module Bolt
|
|
39
39
|
backup_file(config_file, backup_dir)
|
40
40
|
|
41
41
|
begin
|
42
|
-
@outputter.
|
42
|
+
@outputter.print_action_step(
|
43
43
|
"Moving transportation configuration options '#{transport_data.keys.join(', ')}' "\
|
44
44
|
"from bolt.yaml to inventory.yaml"
|
45
45
|
)
|
@@ -51,10 +51,10 @@ module Bolt
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
-
@outputter.
|
54
|
+
@outputter.print_action_step("Renaming bolt.yaml to bolt-project.yaml")
|
55
55
|
FileUtils.mv(config_file, project_file)
|
56
56
|
|
57
|
-
@outputter.
|
57
|
+
@outputter.print_action_step(
|
58
58
|
"Successfully migrated config. Please add a 'name' key to bolt-project.yaml "\
|
59
59
|
"to use project-level tasks and plans. Learn more about projects by running "\
|
60
60
|
"'bolt guide project'."
|
@@ -19,7 +19,7 @@ module Bolt
|
|
19
19
|
|
20
20
|
# Notify user to manually migrate modules if using non-default modulepath
|
21
21
|
if configured_modulepath != modulepath
|
22
|
-
@outputter.
|
22
|
+
@outputter.print_action_step(
|
23
23
|
"Project has a non-default configured modulepath, unable to automatically "\
|
24
24
|
"migrate project modules. To migrate project modules manually, see "\
|
25
25
|
"http://pup.pt/bolt-modules"
|
@@ -46,10 +46,10 @@ module Bolt
|
|
46
46
|
require 'bolt/puppetfile/installer'
|
47
47
|
|
48
48
|
begin
|
49
|
-
@outputter.
|
49
|
+
@outputter.print_action_step("Parsing Puppetfile at #{puppetfile_path}")
|
50
50
|
puppetfile = Bolt::Puppetfile.parse(puppetfile_path, skip_unsupported_modules: true)
|
51
51
|
rescue Bolt::Error => e
|
52
|
-
@outputter.
|
52
|
+
@outputter.print_action_error("#{e.message}\nSkipping module migration.")
|
53
53
|
return false
|
54
54
|
end
|
55
55
|
|
@@ -62,10 +62,10 @@ module Bolt
|
|
62
62
|
# Attempt to resolve dependencies
|
63
63
|
begin
|
64
64
|
@outputter.print_message('')
|
65
|
-
@outputter.
|
65
|
+
@outputter.print_action_step("Resolving module dependencies, this may take a moment")
|
66
66
|
puppetfile.resolve
|
67
67
|
rescue Bolt::Error => e
|
68
|
-
@outputter.
|
68
|
+
@outputter.print_action_error("#{e.message}\nSkipping module migration.")
|
69
69
|
return false
|
70
70
|
end
|
71
71
|
|
@@ -90,17 +90,17 @@ module Bolt
|
|
90
90
|
# Show the new Puppetfile content
|
91
91
|
message = "Generated new Puppetfile content:\n\n"
|
92
92
|
message += puppetfile.modules.map(&:to_spec).join("\n").to_s
|
93
|
-
@outputter.
|
93
|
+
@outputter.print_action_step(message)
|
94
94
|
|
95
95
|
# Write Puppetfile
|
96
|
-
@outputter.
|
96
|
+
@outputter.print_action_step("Updating Puppetfile at #{puppetfile_path}")
|
97
97
|
puppetfile.write(puppetfile_path, managed_moduledir)
|
98
98
|
|
99
99
|
# Install Puppetfile
|
100
|
-
@outputter.
|
100
|
+
@outputter.print_action_step("Syncing modules from #{puppetfile_path} to #{managed_moduledir}")
|
101
101
|
Bolt::Puppetfile::Installer.new({}).install(puppetfile_path, managed_moduledir)
|
102
102
|
else
|
103
|
-
@outputter.
|
103
|
+
@outputter.print_action_step(
|
104
104
|
"Project does not include any managed modules, deleting Puppetfile "\
|
105
105
|
"at #{puppetfile_path}"
|
106
106
|
)
|
@@ -112,7 +112,7 @@ module Bolt
|
|
112
112
|
# the selected modules.
|
113
113
|
#
|
114
114
|
private def select_modules(modules)
|
115
|
-
@outputter.
|
115
|
+
@outputter.print_action_step(
|
116
116
|
"Select modules that are direct dependencies of your project. Bolt will "\
|
117
117
|
"automatically manage dependencies for each module selected, so do not "\
|
118
118
|
"select a module's dependencies unless you use content from it directly "\
|
@@ -135,7 +135,7 @@ module Bolt
|
|
135
135
|
sources.select! { |source| Dir.exist?(source) }
|
136
136
|
|
137
137
|
if sources.any?
|
138
|
-
@outputter.
|
138
|
+
@outputter.print_action_step(
|
139
139
|
"Moving modules from #{sources.join(', ')} to #{moduledir}"
|
140
140
|
)
|
141
141
|
|
@@ -166,7 +166,7 @@ module Bolt
|
|
166
166
|
# Deletes modules from a specified directory.
|
167
167
|
#
|
168
168
|
private def delete_modules(moduledir, modules)
|
169
|
-
@outputter.
|
169
|
+
@outputter.print_action_step("Cleaning up #{moduledir}")
|
170
170
|
moduledir = Pathname.new(moduledir)
|
171
171
|
|
172
172
|
modules.each do |mod|
|
@@ -178,7 +178,7 @@ module Bolt
|
|
178
178
|
# Adds a list of modules to the project configuration file.
|
179
179
|
#
|
180
180
|
private def update_project_config(modules, config_file)
|
181
|
-
@outputter.
|
181
|
+
@outputter.print_action_step("Updating project configuration at #{config_file}")
|
182
182
|
data = Bolt::Util.read_optional_yaml_hash(config_file, 'project')
|
183
183
|
data.merge!('modules' => modules)
|
184
184
|
data.delete('modulepath')
|
data/lib/bolt/puppetfile.rb
CHANGED
@@ -61,8 +61,15 @@ module Bolt
|
|
61
61
|
#
|
62
62
|
def write(path, moduledir = nil)
|
63
63
|
File.open(path, 'w') do |file|
|
64
|
-
|
65
|
-
|
64
|
+
if moduledir
|
65
|
+
file.puts "# This Puppetfile is managed by Bolt. Do not edit."
|
66
|
+
file.puts "# For more information, see https://pup.pt/bolt-modules"
|
67
|
+
file.puts
|
68
|
+
file.puts "# The following directive installs modules to the managed moduledir."
|
69
|
+
file.puts "moduledir '#{moduledir.basename}'"
|
70
|
+
file.puts
|
71
|
+
end
|
72
|
+
|
66
73
|
modules.each { |mod| file.puts mod.to_spec }
|
67
74
|
end
|
68
75
|
rescue SystemCallError => e
|
@@ -13,7 +13,10 @@ module Bolt
|
|
13
13
|
def initialize(owner, name, version = nil)
|
14
14
|
@owner = owner
|
15
15
|
@name = name
|
16
|
-
|
16
|
+
|
17
|
+
if version.is_a?(String)
|
18
|
+
@version = version[0] == '=' ? version[1..-1] : version
|
19
|
+
end
|
17
20
|
end
|
18
21
|
|
19
22
|
# Creates a new module from a hash.
|
data/lib/bolt/shell/bash.rb
CHANGED
@@ -202,13 +202,14 @@ module Bolt
|
|
202
202
|
end
|
203
203
|
|
204
204
|
def handle_sudo_errors(err)
|
205
|
-
|
205
|
+
case err
|
206
|
+
when /^#{conn.user} is not in the sudoers file\./
|
206
207
|
@logger.trace { err }
|
207
208
|
raise Bolt::Node::EscalateError.new(
|
208
209
|
"User #{conn.user} does not have sudo permission on #{target}",
|
209
210
|
'SUDO_DENIED'
|
210
211
|
)
|
211
|
-
|
212
|
+
when /^Sorry, try again\./
|
212
213
|
@logger.trace { err }
|
213
214
|
raise Bolt::Node::EscalateError.new(
|
214
215
|
"Sudo password for user #{conn.user} not recognized on #{target}",
|
@@ -30,7 +30,7 @@ module Bolt
|
|
30
30
|
@transport_logger = transport_logger
|
31
31
|
@logger.trace("Initializing ssh connection to #{@target.safe_name}")
|
32
32
|
|
33
|
-
if target.options['private-key']
|
33
|
+
if target.options['private-key'].instance_of?(String)
|
34
34
|
begin
|
35
35
|
Bolt::Util.validate_file('ssh key', target.options['private-key'])
|
36
36
|
rescue Bolt::FileError => e
|
data/lib/bolt/version.rb
CHANGED
@@ -14,7 +14,9 @@ require 'json-schema'
|
|
14
14
|
|
15
15
|
# These are only needed for the `/plans` endpoint.
|
16
16
|
require 'puppet'
|
17
|
-
|
17
|
+
|
18
|
+
# Needed by the `/project_file_metadatas` endpoint
|
19
|
+
require 'puppet/file_serving/fileset'
|
18
20
|
|
19
21
|
module BoltServer
|
20
22
|
class TransportApp < Sinatra::Base
|
@@ -35,6 +37,17 @@ module BoltServer
|
|
35
37
|
transport-winrm
|
36
38
|
].freeze
|
37
39
|
|
40
|
+
# PE_BOLTLIB_PATH is intended to function exactly like the BOLTLIB_PATH used
|
41
|
+
# in Bolt::PAL. Paths and variable names are similar to what exists in
|
42
|
+
# Bolt::PAL, but with a 'PE' prefix.
|
43
|
+
PE_BOLTLIB_PATH = '/opt/puppetlabs/server/apps/bolt-server/pe-bolt-modules'
|
44
|
+
|
45
|
+
# For now at least, we maintain an entirely separate codedir from
|
46
|
+
# puppetserver by default, so that filesync can work properly. If filesync
|
47
|
+
# is not used, this can instead match the usual puppetserver codedir.
|
48
|
+
# See the `orchestrator.bolt.codedir` tk config setting.
|
49
|
+
DEFAULT_BOLT_CODEDIR = '/opt/puppetlabs/server/data/orchestration-services/code'
|
50
|
+
|
38
51
|
def initialize(config)
|
39
52
|
@config = config
|
40
53
|
@schemas = Hash[REQUEST_SCHEMAS.map do |basename|
|
@@ -191,10 +204,52 @@ module BoltServer
|
|
191
204
|
[@executor.run_script(target, file_location, body['arguments'])]
|
192
205
|
end
|
193
206
|
|
207
|
+
# This function is nearly identical to Bolt::Pal's `with_puppet_settings` with the
|
208
|
+
# one difference that we set the codedir to point to actual code, rather than the
|
209
|
+
# tmpdir. We only use this funtion inside the Modulepath initializer so that Puppet
|
210
|
+
# is correctly configured to pull environment configuration correctly. If we don't
|
211
|
+
# set codedir in this way: when we try to load and interpolate the modulepath it
|
212
|
+
# won't correctly load.
|
213
|
+
#
|
214
|
+
# WARNING: THIS FUNCTION SHOULD ONLY BE CALLED INSIDE A SYNCHRONIZED PAL MUTEX
|
215
|
+
def with_pe_pal_init_settings(codedir, environmentpath, basemodulepath)
|
216
|
+
Dir.mktmpdir('pe-bolt') do |dir|
|
217
|
+
cli = []
|
218
|
+
Puppet::Settings::REQUIRED_APP_SETTINGS.each do |setting|
|
219
|
+
dir = setting == :codedir ? codedir : dir
|
220
|
+
cli << "--#{setting}" << dir
|
221
|
+
end
|
222
|
+
cli << "--environmentpath" << environmentpath
|
223
|
+
cli << "--basemodulepath" << basemodulepath
|
224
|
+
Puppet.settings.send(:clear_everything_for_tests)
|
225
|
+
Puppet.initialize_settings(cli)
|
226
|
+
yield
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
# Use puppet to identify the modulepath from an environment.
|
231
|
+
#
|
232
|
+
# WARNING: THIS FUNCTION SHOULD ONLY BE CALLED INSIDE A SYNCHRONIZED PAL MUTEX
|
233
|
+
def modulepath_from_environment(environment_name)
|
234
|
+
codedir = DEFAULT_BOLT_CODEDIR
|
235
|
+
environmentpath = "#{codedir}/environments"
|
236
|
+
basemodulepath = "#{codedir}/modules:/opt/puppetlabs/puppet/modules"
|
237
|
+
modulepath_dirs = nil
|
238
|
+
with_pe_pal_init_settings(codedir, environmentpath, basemodulepath) do
|
239
|
+
environment = Puppet.lookup(:environments).get!(environment_name)
|
240
|
+
modulepath_dirs = environment.modulepath
|
241
|
+
end
|
242
|
+
modulepath_dirs
|
243
|
+
end
|
244
|
+
|
194
245
|
def in_pe_pal_env(environment)
|
195
246
|
return [400, '`environment` is a required argument'] if environment.nil?
|
196
247
|
@pal_mutex.synchronize do
|
197
|
-
|
248
|
+
modulepath_obj = Bolt::Config::Modulepath.new(
|
249
|
+
modulepath_from_environment(environment),
|
250
|
+
boltlib_path: [PE_BOLTLIB_PATH, Bolt::Config::Modulepath::BOLTLIB_PATH]
|
251
|
+
)
|
252
|
+
pal = Bolt::PAL.new(modulepath_obj, nil, nil)
|
198
253
|
yield pal
|
199
254
|
rescue Puppet::Environments::EnvironmentNotFound
|
200
255
|
[400, {
|
@@ -213,16 +268,11 @@ module BoltServer
|
|
213
268
|
@pal_mutex.synchronize do
|
214
269
|
project = Bolt::Project.create_project(project_dir)
|
215
270
|
bolt_config = Bolt::Config.from_project(project, { log: { 'bolt-debug.log' => 'disable' } })
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
Bolt::PAL::MODULES_PATH
|
222
|
-
]
|
223
|
-
# CODEREVIEW: I *think* this is the only thing we need to make different between bolt's PAL. Is it acceptable
|
224
|
-
# to hack this? Modulepath is currently a readable attribute, could we make it writeable?
|
225
|
-
pal.instance_variable_set(:@modulepath, module_path)
|
271
|
+
modulepath_object = Bolt::Config::Modulepath.new(
|
272
|
+
bolt_config.modulepath,
|
273
|
+
boltlib_path: [PE_BOLTLIB_PATH, Bolt::Config::Modulepath::BOLTLIB_PATH]
|
274
|
+
)
|
275
|
+
pal = Bolt::PAL.new(modulepath_object, nil, nil, nil, nil, nil, bolt_config.project)
|
226
276
|
context = {
|
227
277
|
pal: pal,
|
228
278
|
config: bolt_config
|
@@ -307,6 +357,23 @@ module BoltServer
|
|
307
357
|
plans.map { |plan_name| { 'name' => plan_name } }
|
308
358
|
end
|
309
359
|
|
360
|
+
def file_metadatas(pal, module_name, file)
|
361
|
+
pal.in_bolt_compiler do
|
362
|
+
mod = Puppet.lookup(:current_environment).module(module_name)
|
363
|
+
raise ArgumentError, "`module_name`: #{module_name} does not exist" unless mod
|
364
|
+
abs_file_path = mod.file(file)
|
365
|
+
raise ArgumentError, "`file`: #{file} does not exist inside the module's 'files' directory" unless abs_file_path
|
366
|
+
fileset = Puppet::FileServing::Fileset.new(abs_file_path, 'recurse' => 'yes')
|
367
|
+
Puppet::FileServing::Fileset.merge(fileset).collect do |relative_file_path, base_path|
|
368
|
+
metadata = Puppet::FileServing::Metadata.new(base_path, relative_path: relative_file_path)
|
369
|
+
metadata.checksum_type = 'sha256'
|
370
|
+
metadata.links = 'follow'
|
371
|
+
metadata.collect
|
372
|
+
metadata.to_data_hash
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
310
377
|
get '/' do
|
311
378
|
200
|
312
379
|
end
|
@@ -550,6 +617,19 @@ module BoltServer
|
|
550
617
|
end
|
551
618
|
end
|
552
619
|
|
620
|
+
# Implements puppetserver's file_metadatas endpoint for projects.
|
621
|
+
#
|
622
|
+
# @param project_ref [String] the project_ref to fetch the file metadatas from
|
623
|
+
get '/project_file_metadatas/:module_name/*' do
|
624
|
+
in_bolt_project(params['project_ref']) do |context|
|
625
|
+
file = params[:splat].first
|
626
|
+
metadatas = file_metadatas(context[:pal], params[:module_name], file)
|
627
|
+
[200, metadatas.to_json]
|
628
|
+
end
|
629
|
+
rescue ArgumentError => e
|
630
|
+
[400, e.message]
|
631
|
+
end
|
632
|
+
|
553
633
|
error 404 do
|
554
634
|
err = Bolt::Error.new("Could not find route #{request.path}",
|
555
635
|
'boltserver/not-found')
|
@@ -105,7 +105,7 @@ module BoltSpec
|
|
105
105
|
|
106
106
|
# Set the things
|
107
107
|
Puppet[:tasks] = true
|
108
|
-
RSpec.configuration.module_path = [modulepath, Bolt::
|
108
|
+
RSpec.configuration.module_path = [modulepath, Bolt::Config::Modulepath::BOLTLIB_PATH].join(File::PATH_SEPARATOR)
|
109
109
|
opts = {
|
110
110
|
bolt_executor: executor,
|
111
111
|
bolt_inventory: inventory,
|
@@ -153,7 +153,9 @@ module BoltSpec
|
|
153
153
|
end
|
154
154
|
|
155
155
|
def pal
|
156
|
-
@pal ||= Bolt::PAL.new(config.modulepath,
|
156
|
+
@pal ||= Bolt::PAL.new(Bolt::Config::Modulepath.new(config.modulepath),
|
157
|
+
config.hiera_config,
|
158
|
+
config.project.resource_types)
|
157
159
|
end
|
158
160
|
|
159
161
|
BoltSpec::Plans::MOCKED_ACTIONS.each do |action|
|
data/lib/bolt_spec/plans.rb
CHANGED
data/lib/bolt_spec/run.rb
CHANGED
@@ -179,7 +179,7 @@ module BoltSpec
|
|
179
179
|
end
|
180
180
|
|
181
181
|
def pal
|
182
|
-
@pal ||= Bolt::PAL.new(config.modulepath,
|
182
|
+
@pal ||= Bolt::PAL.new(Bolt::Config::Modulepath.new(config.modulepath),
|
183
183
|
config.hiera_config,
|
184
184
|
config.project.resource_types,
|
185
185
|
config.compile_concurrency)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bolt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.31.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Puppet
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-10-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -444,6 +444,7 @@ files:
|
|
444
444
|
- lib/bolt/catalog/logging.rb
|
445
445
|
- lib/bolt/cli.rb
|
446
446
|
- lib/bolt/config.rb
|
447
|
+
- lib/bolt/config/modulepath.rb
|
447
448
|
- lib/bolt/config/options.rb
|
448
449
|
- lib/bolt/config/transport/base.rb
|
449
450
|
- lib/bolt/config/transport/docker.rb
|
@@ -542,7 +543,6 @@ files:
|
|
542
543
|
- lib/bolt_server/base_config.rb
|
543
544
|
- lib/bolt_server/config.rb
|
544
545
|
- lib/bolt_server/file_cache.rb
|
545
|
-
- lib/bolt_server/pe/pal.rb
|
546
546
|
- lib/bolt_server/schemas/action-check_node_connections.json
|
547
547
|
- lib/bolt_server/schemas/action-run_command.json
|
548
548
|
- lib/bolt_server/schemas/action-run_script.json
|
data/lib/bolt_server/pe/pal.rb
DELETED
@@ -1,67 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'bolt/pal'
|
4
|
-
require 'bolt/util'
|
5
|
-
|
6
|
-
module BoltServer
|
7
|
-
module PE
|
8
|
-
class PAL < Bolt::PAL
|
9
|
-
# PE_BOLTLIB_PATH is intended to function exactly like the BOLTLIB_PATH used
|
10
|
-
# in Bolt::PAL. Paths and variable names are similar to what exists in
|
11
|
-
# Bolt::PAL, but with a 'PE' prefix.
|
12
|
-
PE_BOLTLIB_PATH = '/opt/puppetlabs/server/apps/bolt-server/pe-bolt-modules'
|
13
|
-
|
14
|
-
# For now at least, we maintain an entirely separate codedir from
|
15
|
-
# puppetserver by default, so that filesync can work properly. If filesync
|
16
|
-
# is not used, this can instead match the usual puppetserver codedir.
|
17
|
-
# See the `orchestrator.bolt.codedir` tk config setting.
|
18
|
-
DEFAULT_BOLT_CODEDIR = '/opt/puppetlabs/server/data/orchestration-services/code'
|
19
|
-
|
20
|
-
# This function is nearly identical to Bolt::Pal's `with_puppet_settings` with the
|
21
|
-
# one difference that we set the codedir to point to actual code, rather than the
|
22
|
-
# tmpdir. We only use this funtion inside the PEBolt::PAL initializer so that Puppet
|
23
|
-
# is correctly configured to pull environment configuration correctly. If we don't
|
24
|
-
# set codedir in this way: when we try to load and interpolate the modulepath it
|
25
|
-
# won't correctly load.
|
26
|
-
def with_pe_pal_init_settings(codedir, environmentpath, basemodulepath)
|
27
|
-
Dir.mktmpdir('pe-bolt') do |dir|
|
28
|
-
cli = []
|
29
|
-
Puppet::Settings::REQUIRED_APP_SETTINGS.each do |setting|
|
30
|
-
dir = setting == :codedir ? codedir : dir
|
31
|
-
cli << "--#{setting}" << dir
|
32
|
-
end
|
33
|
-
cli << "--environmentpath" << environmentpath
|
34
|
-
cli << "--basemodulepath" << basemodulepath
|
35
|
-
Puppet.settings.send(:clear_everything_for_tests)
|
36
|
-
Puppet.initialize_settings(cli)
|
37
|
-
yield
|
38
|
-
# Ensure the puppet settings go back to what bolt expects after
|
39
|
-
# we finish with the settings we need for PEBolt::PAL init.
|
40
|
-
with_puppet_settings { |_| nil }
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def initialize(plan_executor_config, environment_name, hiera_config = nil, max_compiles = nil)
|
45
|
-
# Bolt::PAL#initialize takes the modulepath as its first argument, but we
|
46
|
-
# want to customize it later, so we pass an empty value:
|
47
|
-
super([], hiera_config, max_compiles)
|
48
|
-
|
49
|
-
codedir = plan_executor_config['codedir'] || DEFAULT_BOLT_CODEDIR
|
50
|
-
environmentpath = plan_executor_config['environmentpath'] || "#{codedir}/environments"
|
51
|
-
basemodulepath = plan_executor_config['basemodulepath'] || "#{codedir}/modules:/opt/puppetlabs/puppet/modules"
|
52
|
-
|
53
|
-
with_pe_pal_init_settings(codedir, environmentpath, basemodulepath) do
|
54
|
-
environment = Puppet.lookup(:environments).get!(environment_name)
|
55
|
-
# A new modulepath is created from scratch (rather than using super's @modulepath)
|
56
|
-
# so that we can have full control over all the entries in modulepath. In the future
|
57
|
-
# it's likely we will need to preceed _both_ Bolt::PAL::BOLTLIB_PATH _and_
|
58
|
-
# Bolt::PAL::MODULES_PATH which would be more complex if we tried to use @modulepath since
|
59
|
-
# we need to append our modulepaths and exclude modules shiped in bolt gem code
|
60
|
-
modulepath_dirs = environment.modulepath
|
61
|
-
@user_modulepath = modulepath_dirs
|
62
|
-
@modulepath = [PE_BOLTLIB_PATH, Bolt::PAL::BOLTLIB_PATH, *modulepath_dirs]
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|