bolt 3.16.0 → 3.16.1
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/lib/bolt/module_installer/puppetfile.rb +24 -10
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/file_cache.rb +12 -0
- data/lib/bolt_server/schemas/action-apply.json +32 -0
- data/lib/bolt_server/schemas/action-apply_prep.json +19 -0
- data/lib/bolt_server/transport_app.rb +112 -23
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 71d383b473f9356ff41f574bb0abe4aea9a9f8c3ac5055a459acffe0da290af1
|
4
|
+
data.tar.gz: 00d10803d865a9d6f0cb6eb7162e4a17f619b88e6702b559e0153b3796d732d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eaad9c12aab69e9d7c9f1d8b312623b8bcca4f26f983beb08b1d09c4568aafe0e430d639b88903df4e1a498a58c4c9d8add5d4b8b3930fe1dec3124bc15afad3
|
7
|
+
data.tar.gz: a05ec6c181fc6aa51c73ebfd928d73513d5506c1b0705bed4637bfa9490a6f1c010019c9209f7ed28c134f003a063ff6f4add490a55d658998f566d00c5ff017
|
data/Puppetfile
CHANGED
@@ -35,7 +35,7 @@ mod 'puppetlabs-stdlib', '7.1.0'
|
|
35
35
|
mod 'puppetlabs-aws_inventory', '0.7.0'
|
36
36
|
mod 'puppetlabs-azure_inventory', '0.5.0'
|
37
37
|
mod 'puppetlabs-gcloud_inventory', '0.3.0'
|
38
|
-
mod 'puppetlabs-http_request', '0.3.
|
38
|
+
mod 'puppetlabs-http_request', '0.3.1'
|
39
39
|
mod 'puppetlabs-pkcs7', '0.1.2'
|
40
40
|
mod 'puppetlabs-secure_env_vars', '0.2.0'
|
41
41
|
mod 'puppetlabs-terraform', '0.6.1'
|
@@ -97,20 +97,34 @@ module Bolt
|
|
97
97
|
end
|
98
98
|
end
|
99
99
|
|
100
|
-
|
101
|
-
|
100
|
+
versionless_mods = @modules.select { |mod| mod.is_a?(ForgeModule) && mod.version.nil? }
|
102
101
|
command = Bolt::Util.windows? ? 'Install-BoltModule -Force' : 'bolt module install --force'
|
103
102
|
|
104
|
-
|
105
|
-
|
103
|
+
if unsatisfied_specs.any?
|
104
|
+
message = <<~MESSAGE.chomp
|
105
|
+
Puppetfile does not include modules that satisfy the following specifications:
|
106
|
+
|
107
|
+
#{unsatisfied_specs.map(&:to_hash).to_yaml.lines.drop(1).join.chomp}
|
108
|
+
|
109
|
+
This Puppetfile might not be managed by Bolt. To forcibly overwrite the
|
110
|
+
Puppetfile, run '#{command}'.
|
111
|
+
MESSAGE
|
106
112
|
|
107
|
-
|
108
|
-
|
109
|
-
This Puppetfile might not be managed by Bolt. To forcibly overwrite the
|
110
|
-
Puppetfile, run '#{command}'.
|
111
|
-
MESSAGE
|
113
|
+
raise Bolt::Error.new(message, 'bolt/missing-module-specs')
|
114
|
+
end
|
112
115
|
|
113
|
-
|
116
|
+
if versionless_mods.any?
|
117
|
+
message = <<~MESSAGE.chomp
|
118
|
+
Puppetfile includes Forge modules without a version requirement:
|
119
|
+
|
120
|
+
#{versionless_mods.map(&:to_spec).join.chomp}
|
121
|
+
|
122
|
+
This Puppetfile might not be managed by Bolt. To forcibly overwrite the
|
123
|
+
Puppetfile, run '#{command}'.
|
124
|
+
MESSAGE
|
125
|
+
|
126
|
+
raise Bolt::Error.new(message, 'bolt/missing-module-version-specs')
|
127
|
+
end
|
114
128
|
end
|
115
129
|
end
|
116
130
|
end
|
data/lib/bolt/version.rb
CHANGED
@@ -182,5 +182,17 @@ module BoltServer
|
|
182
182
|
end
|
183
183
|
end
|
184
184
|
end
|
185
|
+
|
186
|
+
def get_cached_project_file(versioned_project, file_name)
|
187
|
+
file_dir = create_cache_dir(versioned_project)
|
188
|
+
file_path = File.join(file_dir, file_name)
|
189
|
+
serial_execute { File.read(file_path) if File.exist?(file_path) }
|
190
|
+
end
|
191
|
+
|
192
|
+
def cache_project_file(versioned_project, file_name, data)
|
193
|
+
file_dir = create_cache_dir(versioned_project)
|
194
|
+
file_path = File.join(file_dir, file_name)
|
195
|
+
serial_execute { File.open(file_path, 'w') { |f| f.write(data) } }
|
196
|
+
end
|
185
197
|
end
|
186
198
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "http://json-schema.org/draft-04/schema#",
|
3
|
+
"title": "apply request",
|
4
|
+
"description": "POST <transport>/apply request schema",
|
5
|
+
"type": "object",
|
6
|
+
"properties": {
|
7
|
+
"versioned_project": {
|
8
|
+
"type": "string",
|
9
|
+
"description": "Project from which to load code"
|
10
|
+
},
|
11
|
+
"parameters": {
|
12
|
+
"type": "object",
|
13
|
+
"properties": {
|
14
|
+
"catalog": {
|
15
|
+
"type": "object",
|
16
|
+
"description": "Compiled catalog to apply"
|
17
|
+
},
|
18
|
+
"apply_options": {
|
19
|
+
"type": "object",
|
20
|
+
"description": "Options for application of a catalog"
|
21
|
+
}
|
22
|
+
}
|
23
|
+
},
|
24
|
+
"job_id": {
|
25
|
+
"type": "integer",
|
26
|
+
"description": "job-id associated with request"
|
27
|
+
},
|
28
|
+
"target": { "$ref": "partial:target-any" }
|
29
|
+
},
|
30
|
+
"required": ["target", "versioned_project", "parameters", "job_id"],
|
31
|
+
"additionalProperties": false
|
32
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "http://json-schema.org/draft-04/schema#",
|
3
|
+
"title": "apply_prep request",
|
4
|
+
"description": "POST <transport>/apply_prep request schema",
|
5
|
+
"type": "object",
|
6
|
+
"properties": {
|
7
|
+
"versioned_project": {
|
8
|
+
"type": "String",
|
9
|
+
"description": "Project from which to load code"
|
10
|
+
},
|
11
|
+
"target": { "$ref": "partial:target-any" },
|
12
|
+
"job_id": {
|
13
|
+
"type": "integer",
|
14
|
+
"description": "job-id associated with request"
|
15
|
+
}
|
16
|
+
},
|
17
|
+
"required": ["target", "versioned_project", "job_id"],
|
18
|
+
"additionalProperties": false
|
19
|
+
}
|
@@ -43,6 +43,8 @@ module BoltServer
|
|
43
43
|
transport-ssh
|
44
44
|
transport-winrm
|
45
45
|
connect-data
|
46
|
+
action-apply_prep
|
47
|
+
action-apply
|
46
48
|
].freeze
|
47
49
|
|
48
50
|
# PE_BOLTLIB_PATH is intended to function exactly like the BOLTLIB_PATH used
|
@@ -75,6 +77,12 @@ module BoltServer
|
|
75
77
|
# This is needed until the PAL is threadsafe.
|
76
78
|
@pal_mutex = Mutex.new
|
77
79
|
|
80
|
+
# Avoid redundant plugin tarbal construction
|
81
|
+
@plugin_mutex = Mutex.new
|
82
|
+
|
83
|
+
# Avoid redundant project_task metadata construction
|
84
|
+
@task_metadata_mutex = Mutex.new
|
85
|
+
|
78
86
|
@logger = Bolt::Logger.logger(self)
|
79
87
|
|
80
88
|
super(nil)
|
@@ -118,12 +126,7 @@ module BoltServer
|
|
118
126
|
end
|
119
127
|
end
|
120
128
|
|
121
|
-
def
|
122
|
-
validate_schema(@schemas["action-run_task"], body)
|
123
|
-
|
124
|
-
task_data = body['task']
|
125
|
-
task = Bolt::Task::PuppetServer.new(task_data['name'], task_data['metadata'], task_data['files'], @file_cache)
|
126
|
-
parameters = body['parameters'] || {}
|
129
|
+
def task_helper(target, task, parameters)
|
127
130
|
# Wrap parameters marked with '"sensitive": true' in the task metadata with a
|
128
131
|
# Sensitive wrapper type. This way it's not shown in logs.
|
129
132
|
if (param_spec = task.parameters)
|
@@ -142,6 +145,101 @@ module BoltServer
|
|
142
145
|
end
|
143
146
|
end
|
144
147
|
|
148
|
+
def run_task(target, body)
|
149
|
+
validate_schema(@schemas["action-run_task"], body)
|
150
|
+
|
151
|
+
task_data = body['task']
|
152
|
+
task = Bolt::Task::PuppetServer.new(task_data['name'], task_data['metadata'], task_data['files'], @file_cache)
|
153
|
+
task_helper(target, task, body['parameters'] || {})
|
154
|
+
end
|
155
|
+
|
156
|
+
def extract_install_task(target)
|
157
|
+
unless target.plugin_hooks['puppet_library']['task']
|
158
|
+
raise BoltServer::RequestError,
|
159
|
+
"Target must have 'task' plugin hook"
|
160
|
+
end
|
161
|
+
install_task = target.plugin_hooks['puppet_library']['task'].split('::', 2)
|
162
|
+
install_task << 'init' if install_task.count == 1
|
163
|
+
install_task
|
164
|
+
end
|
165
|
+
|
166
|
+
# This helper is responsible for computing or retrieving from the cache a plugin tarball. There are
|
167
|
+
# two supported plugin types 'fact_plugins', and 'all_plugins'. Note that this is cached based on
|
168
|
+
# versioned_project as there are no plugins in the "builtin content" directory
|
169
|
+
def plugin_tarball(versioned_project, tarball_type)
|
170
|
+
tarball_types = %w[fact_plugins all_plugins]
|
171
|
+
unless tarball_types.include?(tarball_type)
|
172
|
+
raise ArgumentError,
|
173
|
+
"tarball_type must be one of: #{tarball_types.join(', ')}"
|
174
|
+
end
|
175
|
+
# lock this so that in the case an apply/apply_prep with multiple targets hits this endpoint
|
176
|
+
# the tarball computation only happens once (all the other targets will just need to read the cached data)
|
177
|
+
@plugin_mutex.synchronize do
|
178
|
+
if (tarball = @file_cache.get_cached_project_file(versioned_project, tarball_type))
|
179
|
+
tarball
|
180
|
+
else
|
181
|
+
new_tarball = build_project_plugins_tarball(versioned_project) do |mod|
|
182
|
+
search_dirs = []
|
183
|
+
search_dirs << mod.plugins if mod.plugins?
|
184
|
+
search_dirs << mod.pluginfacts if mod.pluginfacts?
|
185
|
+
if tarball_type == 'all_plugins'
|
186
|
+
search_dirs << mod.files if mod.files?
|
187
|
+
type_files = "#{mod.path}/types"
|
188
|
+
search_dirs << type_files if File.exist?(type_files)
|
189
|
+
end
|
190
|
+
search_dirs
|
191
|
+
end
|
192
|
+
@file_cache.cache_project_file(versioned_project, tarball_type, new_tarball)
|
193
|
+
new_tarball
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
# This helper is responsible for computing or retrieving task metadata for a project.
|
199
|
+
# It expects task name in segments and uses the combination of task name and versioned_project
|
200
|
+
# as a unique identifier for caching in addition to the job_id. The job id is added to protect against
|
201
|
+
# a case where the buildtin content is update (where the apply_helpers would be managed)
|
202
|
+
def project_task_metadata(versioned_project, task_name_segments, job_id)
|
203
|
+
cached_file_name = "#{task_name_segments.join('_')}_#{job_id}"
|
204
|
+
# lock this so that in the case an apply/apply_prep with multiple targets hits this endpoint the
|
205
|
+
# metadata computation will only be computed once, then the cache will be read.
|
206
|
+
@task_metadata_mutex.synchronize do
|
207
|
+
if (metadata = @file_cache.get_cached_project_file(versioned_project, cached_file_name))
|
208
|
+
JSON.parse(metadata)
|
209
|
+
else
|
210
|
+
new_metadata = in_bolt_project(versioned_project) do |context|
|
211
|
+
ps_parameters = {
|
212
|
+
'versioned_project' => versioned_project
|
213
|
+
}
|
214
|
+
pe_task_info(context[:pal], *task_name_segments, ps_parameters)
|
215
|
+
end
|
216
|
+
@file_cache.cache_project_file(versioned_project, cached_file_name, new_metadata.to_json)
|
217
|
+
new_metadata
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def apply_prep(target, body)
|
223
|
+
validate_schema(@schemas["action-apply_prep"], body)
|
224
|
+
plugins_tarball = plugin_tarball(body['versioned_project'], 'fact_plugins')
|
225
|
+
install_task_segments = extract_install_task(target.first)
|
226
|
+
task_data = project_task_metadata(body['versioned_project'], install_task_segments, body["job_id"])
|
227
|
+
task = Bolt::Task::PuppetServer.new(task_data['name'], task_data['metadata'], task_data['files'], @file_cache)
|
228
|
+
install_task_result = task_helper(target, task, target.first.plugin_hooks['puppet_library']['parameters'] || {})
|
229
|
+
return install_task_result unless install_task_result.ok
|
230
|
+
task_data = project_task_metadata(body['versioned_project'], %w[apply_helpers custom_facts], body["job_id"])
|
231
|
+
task = Bolt::Task::PuppetServer.new(task_data['name'], task_data['metadata'], task_data['files'], @file_cache)
|
232
|
+
task_helper(target, task, { 'plugins' => plugins_tarball })
|
233
|
+
end
|
234
|
+
|
235
|
+
def apply(target, body)
|
236
|
+
validate_schema(@schemas["action-apply"], body)
|
237
|
+
plugins_tarball = plugin_tarball(body['versioned_project'], 'all_plugins')
|
238
|
+
task_data = project_task_metadata(body['versioned_project'], %w[apply_helpers apply_catalog], body["job_id"])
|
239
|
+
task = Bolt::Task::PuppetServer.new(task_data['name'], task_data['metadata'], task_data['files'], @file_cache)
|
240
|
+
task_helper(target, task, body['parameters'].merge({ 'plugins' => plugins_tarball }))
|
241
|
+
end
|
242
|
+
|
145
243
|
def run_command(target, body)
|
146
244
|
validate_schema(@schemas["action-run_command"], body)
|
147
245
|
command = body['command']
|
@@ -476,6 +574,8 @@ module BoltServer
|
|
476
574
|
run_task
|
477
575
|
run_script
|
478
576
|
upload_file
|
577
|
+
apply
|
578
|
+
apply_prep
|
479
579
|
].freeze
|
480
580
|
|
481
581
|
def make_ssh_target(target_hash)
|
@@ -499,7 +599,8 @@ module BoltServer
|
|
499
599
|
'config' => {
|
500
600
|
'transport' => 'ssh',
|
501
601
|
'ssh' => opts.slice(*Bolt::Config::Transport::SSH.options)
|
502
|
-
}
|
602
|
+
},
|
603
|
+
'plugin_hooks' => target_hash['plugin_hooks']
|
503
604
|
}
|
504
605
|
|
505
606
|
inventory = Bolt::Inventory.empty
|
@@ -537,7 +638,8 @@ module BoltServer
|
|
537
638
|
'config' => {
|
538
639
|
'transport' => 'winrm',
|
539
640
|
'winrm' => opts.slice(*Bolt::Config::Transport::WinRM.options)
|
540
|
-
}
|
641
|
+
},
|
642
|
+
'plugin_hooks' => target_hash['plugin_hooks']
|
541
643
|
}
|
542
644
|
|
543
645
|
inventory = Bolt::Inventory.empty
|
@@ -756,12 +858,7 @@ module BoltServer
|
|
756
858
|
raise BoltServer::RequestError, "'versioned_project' is a required argument" if params['versioned_project'].nil?
|
757
859
|
content_type :json
|
758
860
|
|
759
|
-
plugins_tarball =
|
760
|
-
search_dirs = []
|
761
|
-
search_dirs << mod.plugins if mod.plugins?
|
762
|
-
search_dirs << mod.pluginfacts if mod.pluginfacts?
|
763
|
-
search_dirs
|
764
|
-
end
|
861
|
+
plugins_tarball = plugin_tarball(params['versioned_project'], 'fact_plugins')
|
765
862
|
|
766
863
|
[200, plugins_tarball.to_json]
|
767
864
|
end
|
@@ -773,15 +870,7 @@ module BoltServer
|
|
773
870
|
raise BoltServer::RequestError, "'versioned_project' is a required argument" if params['versioned_project'].nil?
|
774
871
|
content_type :json
|
775
872
|
|
776
|
-
plugins_tarball =
|
777
|
-
search_dirs = []
|
778
|
-
search_dirs << mod.plugins if mod.plugins?
|
779
|
-
search_dirs << mod.pluginfacts if mod.pluginfacts?
|
780
|
-
search_dirs << mod.files if mod.files?
|
781
|
-
type_files = "#{mod.path}/types"
|
782
|
-
search_dirs << type_files if File.exist?(type_files)
|
783
|
-
search_dirs
|
784
|
-
end
|
873
|
+
plugins_tarball = plugin_tarball(params['versioned_project'], 'all_plugins')
|
785
874
|
|
786
875
|
[200, plugins_tarball.to_json]
|
787
876
|
end
|
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: 3.16.
|
4
|
+
version: 3.16.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Puppet
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-08-
|
11
|
+
date: 2021-08-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -610,6 +610,8 @@ files:
|
|
610
610
|
- lib/bolt_server/plugin.rb
|
611
611
|
- lib/bolt_server/plugin/puppet_connect_data.rb
|
612
612
|
- lib/bolt_server/request_error.rb
|
613
|
+
- lib/bolt_server/schemas/action-apply.json
|
614
|
+
- lib/bolt_server/schemas/action-apply_prep.json
|
613
615
|
- lib/bolt_server/schemas/action-check_node_connections.json
|
614
616
|
- lib/bolt_server/schemas/action-run_command.json
|
615
617
|
- lib/bolt_server/schemas/action-run_script.json
|