bolt 1.30.0 → 1.30.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/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +2 -2
- data/lib/bolt/applicator.rb +3 -0
- data/lib/bolt/transport/powershell.rb +1 -1
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/file_cache.rb +3 -3
- data/lib/bolt_server/schemas/action-check_node_connections.json +14 -0
- data/lib/bolt_server/schemas/action-upload_file.json +47 -0
- data/lib/bolt_server/schemas/transport-ssh.json +17 -2
- data/lib/bolt_server/schemas/transport-winrm.json +11 -2
- data/lib/bolt_server/transport_app.rb +130 -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: b5c70a9312d9fa6f384b140fec6cbc3c173906e9b428e0d3b19faaab91cf6590
|
4
|
+
data.tar.gz: 10fe1a0b13b4bd489cd41a9b3971d6e5a8f797fced7ddd1faeaf33c09c9f3e28
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 26f36949b058636604697ba4804e1aeb3068c94dd49890c19f336bb9afabe3256f5383661e876881d51b95c667d6c9f4f6bf149566d9d06e54c21456a6de1301
|
7
|
+
data.tar.gz: cc48faf53683fac36548175e42466a80330580942b48f3bdfd2fae060e1e91eef67b289c1e751e58bde2be3ab459bd52a5a2460e3c108468b77fc82ff4c37800
|
@@ -28,7 +28,7 @@ Puppet::Functions.create_function(:apply_prep) do
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def inventory
|
31
|
-
Puppet.lookup(:bolt_inventory)
|
31
|
+
@inventory ||= Puppet.lookup(:bolt_inventory)
|
32
32
|
end
|
33
33
|
|
34
34
|
def get_task(name, params = {})
|
@@ -61,7 +61,7 @@ Puppet::Functions.create_function(:apply_prep) do
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def executor
|
64
|
-
Puppet.lookup(:bolt_executor)
|
64
|
+
@executor ||= Puppet.lookup(:bolt_executor)
|
65
65
|
end
|
66
66
|
|
67
67
|
def apply_prep(target_spec)
|
data/lib/bolt/applicator.rb
CHANGED
@@ -195,6 +195,7 @@ module Bolt
|
|
195
195
|
arguments = {
|
196
196
|
'catalog' => Puppet::Pops::Types::PSensitiveType::Sensitive.new(catalog),
|
197
197
|
'plugins' => Puppet::Pops::Types::PSensitiveType::Sensitive.new(plugins),
|
198
|
+
'_task' => catalog_apply_task.name,
|
198
199
|
'_noop' => options['_noop']
|
199
200
|
}
|
200
201
|
|
@@ -204,6 +205,8 @@ module Bolt
|
|
204
205
|
end
|
205
206
|
@executor.publish_event(event)
|
206
207
|
end
|
208
|
+
# Respect the run_as default set on the executor
|
209
|
+
options = { '_run_as' => @executor.run_as }.merge(options) if @executor.run_as
|
207
210
|
results = transport.batch_task(batch, catalog_apply_task, arguments, options, &callback)
|
208
211
|
Array(results).map { |result| ApplyResult.from_task_result(result) }
|
209
212
|
end
|
@@ -193,7 +193,7 @@ PROCESS{
|
|
193
193
|
return $xml.Objects | ConvertFrom-Xml
|
194
194
|
}
|
195
195
|
$propbag = @{}
|
196
|
-
foreach ($name in Get-Member -InputObject $xml -MemberType Properties | Where-Object{$_.Name -notmatch "^__
|
196
|
+
foreach ($name in Get-Member -InputObject $xml -MemberType Properties | Where-Object{$_.Name -notmatch "^(__.*|type)$"} | Select-Object -ExpandProperty name) {
|
197
197
|
Write-Debug "$Name Type: $($xml.$Name.type)" -Debug:$false
|
198
198
|
$propbag."$Name" = Convert-Properties $xml."$name"
|
199
199
|
}
|
data/lib/bolt/version.rb
CHANGED
@@ -83,7 +83,7 @@ module BoltServer
|
|
83
83
|
begin
|
84
84
|
client.request(req) do |resp|
|
85
85
|
if resp.code != "200"
|
86
|
-
msg = "Failed to download
|
86
|
+
msg = "Failed to download file: #{resp.body}"
|
87
87
|
@logger.warn resp.body
|
88
88
|
raise Error, msg
|
89
89
|
end
|
@@ -96,7 +96,7 @@ module BoltServer
|
|
96
96
|
raise e
|
97
97
|
else
|
98
98
|
@logger.warn e
|
99
|
-
raise Error, "Failed to download
|
99
|
+
raise Error, "Failed to download file: #{e.message}"
|
100
100
|
end
|
101
101
|
end
|
102
102
|
ensure
|
@@ -157,7 +157,7 @@ module BoltServer
|
|
157
157
|
file_dir = create_cache_dir(file_data['sha256'])
|
158
158
|
file_path = File.join(file_dir, File.basename(file_data['filename']))
|
159
159
|
if check_file(file_path, sha)
|
160
|
-
@logger.debug("Using prexisting
|
160
|
+
@logger.debug("Using prexisting file: #{file_path}")
|
161
161
|
return file_path
|
162
162
|
end
|
163
163
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "http://json-schema.org/draft-04/schema#",
|
3
|
+
"title": "check_node_connections request",
|
4
|
+
"description": "POST <transport>/check_node_connections request schema",
|
5
|
+
"type": "object",
|
6
|
+
"properties": {
|
7
|
+
"targets": {
|
8
|
+
"type": "array",
|
9
|
+
"items": { "$ref": "partial:target-any" }
|
10
|
+
}
|
11
|
+
},
|
12
|
+
"required": ["targets"],
|
13
|
+
"additionalProperties": false
|
14
|
+
}
|
@@ -0,0 +1,47 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "http://json-schema.org/draft-04/schema#",
|
3
|
+
"title": "upload_file request",
|
4
|
+
"description": "POST <transport>/upload_file request schema",
|
5
|
+
"type": "object",
|
6
|
+
"properties": {
|
7
|
+
"files": {
|
8
|
+
"type": "array",
|
9
|
+
"items": {
|
10
|
+
"type": "object",
|
11
|
+
"properties": {
|
12
|
+
"relative_path": {
|
13
|
+
"type": "string"
|
14
|
+
},
|
15
|
+
"uri": {
|
16
|
+
"type": "object",
|
17
|
+
"properties": {
|
18
|
+
"path": {
|
19
|
+
"type": "string"
|
20
|
+
},
|
21
|
+
"params": {
|
22
|
+
"type": "object"
|
23
|
+
}
|
24
|
+
},
|
25
|
+
"required": ["path", "params"]
|
26
|
+
},
|
27
|
+
"sha256": {
|
28
|
+
"type": "string"
|
29
|
+
},
|
30
|
+
"kind": {
|
31
|
+
"type": "string"
|
32
|
+
}
|
33
|
+
},
|
34
|
+
"required": ["relative_path", "uri", "sha256", "kind"]
|
35
|
+
}
|
36
|
+
},
|
37
|
+
"job_id": {
|
38
|
+
"type": "integer"
|
39
|
+
},
|
40
|
+
"destination": {
|
41
|
+
"type": "string"
|
42
|
+
},
|
43
|
+
"target": { "$ref": "partial:target-any" }
|
44
|
+
},
|
45
|
+
"required": ["files", "job_id", "destination", "target"],
|
46
|
+
"additionalProperties": false
|
47
|
+
}
|
@@ -4,7 +4,22 @@
|
|
4
4
|
"description": "POST /ssh/<action> request schema",
|
5
5
|
"type": "object",
|
6
6
|
"properties": {
|
7
|
-
"target": { "$ref": "partial:target-ssh" }
|
7
|
+
"target": { "$ref": "partial:target-ssh" },
|
8
|
+
"targets": {
|
9
|
+
"type": "array",
|
10
|
+
"items": {
|
11
|
+
"$ref": "partial:target-ssh"
|
12
|
+
}
|
13
|
+
}
|
8
14
|
},
|
9
|
-
"
|
15
|
+
"oneOf": [
|
16
|
+
{
|
17
|
+
"type": "object",
|
18
|
+
"required": ["target"]
|
19
|
+
},
|
20
|
+
{
|
21
|
+
"type": "object",
|
22
|
+
"required": ["targets"]
|
23
|
+
}
|
24
|
+
]
|
10
25
|
}
|
@@ -4,7 +4,16 @@
|
|
4
4
|
"description": "POST /winrm/<action> request schema",
|
5
5
|
"type": "object",
|
6
6
|
"properties": {
|
7
|
-
"target": { "$ref": "partial:target-winrm" }
|
7
|
+
"target": { "$ref": "partial:target-winrm" },
|
8
|
+
"targets": {
|
9
|
+
"type": "array",
|
10
|
+
"items": {
|
11
|
+
"$ref": "partial:target-winrm"
|
12
|
+
}
|
13
|
+
}
|
8
14
|
},
|
9
|
-
"
|
15
|
+
"oneOf": [
|
16
|
+
{ "required": ["target"] },
|
17
|
+
{ "required": ["targets"] }
|
18
|
+
]
|
10
19
|
}
|
@@ -19,7 +19,14 @@ module BoltServer
|
|
19
19
|
PARTIAL_SCHEMAS = %w[target-any target-ssh target-winrm task].freeze
|
20
20
|
|
21
21
|
# These schemas combine shared schemas to describe client requests
|
22
|
-
REQUEST_SCHEMAS = %w[
|
22
|
+
REQUEST_SCHEMAS = %w[
|
23
|
+
action-check_node_connections
|
24
|
+
action-run_command
|
25
|
+
action-run_task
|
26
|
+
action-upload_file
|
27
|
+
transport-ssh
|
28
|
+
transport-winrm
|
29
|
+
].freeze
|
23
30
|
|
24
31
|
def initialize(config)
|
25
32
|
@config = config
|
@@ -56,21 +63,92 @@ module BoltServer
|
|
56
63
|
end
|
57
64
|
end
|
58
65
|
|
66
|
+
# Turns a Bolt::ResultSet object into a status hash that is fit
|
67
|
+
# to return to the client in a response.
|
68
|
+
#
|
69
|
+
# If the `result_set` has more than one result, the status hash
|
70
|
+
# will have a `status` value and a list of target `results`.
|
71
|
+
# If the `result_set` contains only one item, it will be returned
|
72
|
+
# as a single result object. Set `aggregate` to treat it as a set
|
73
|
+
# of results with length 1 instead.
|
74
|
+
def result_set_to_status_hash(result_set, aggregate: false)
|
75
|
+
scrubbed_results = result_set.map do |result|
|
76
|
+
scrub_stack_trace(result.status_hash)
|
77
|
+
end
|
78
|
+
|
79
|
+
if aggregate || scrubbed_results.length > 1
|
80
|
+
# For actions that act on multiple targets, construct a status hash for the aggregate result
|
81
|
+
all_succeeded = scrubbed_results.all? { |r| r[:status] == 'success' }
|
82
|
+
{
|
83
|
+
status: all_succeeded ? 'success' : 'failure',
|
84
|
+
result: scrubbed_results
|
85
|
+
}
|
86
|
+
else
|
87
|
+
# If there was only one target, return the first result on its own
|
88
|
+
scrubbed_results.first
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
59
92
|
def run_task(target, body)
|
60
93
|
error = validate_schema(@schemas["action-run_task"], body)
|
61
|
-
return [
|
94
|
+
return [], error unless error.nil?
|
62
95
|
|
63
96
|
task = Bolt::Task::PuppetServer.new(body['task'], @file_cache)
|
64
97
|
parameters = body['parameters'] || {}
|
65
|
-
@executor.run_task(target, task, parameters)
|
98
|
+
[@executor.run_task(target, task, parameters), nil]
|
66
99
|
end
|
67
100
|
|
68
101
|
def run_command(target, body)
|
69
102
|
error = validate_schema(@schemas["action-run_command"], body)
|
70
|
-
return [
|
103
|
+
return [], error unless error.nil?
|
71
104
|
|
72
105
|
command = body['command']
|
73
|
-
@executor.run_command(target, command)
|
106
|
+
[@executor.run_command(target, command), nil]
|
107
|
+
end
|
108
|
+
|
109
|
+
def check_node_connections(targets, body)
|
110
|
+
error = validate_schema(@schemas["action-check_node_connections"], body)
|
111
|
+
return [], error unless error.nil?
|
112
|
+
|
113
|
+
# Puppet Enterprise's orchestrator service uses the
|
114
|
+
# check_node_connections endpoint to check whether nodes that should be
|
115
|
+
# contacted over SSH or WinRM are responsive. The wait time here is 0
|
116
|
+
# because the endpoint is meant to be used for a single check of all
|
117
|
+
# nodes; External implementations of wait_until_available (like
|
118
|
+
# orchestrator's) should contact the endpoint in their own loop.
|
119
|
+
[@executor.wait_until_available(targets, wait_time: 0), nil]
|
120
|
+
end
|
121
|
+
|
122
|
+
def upload_file(target, body)
|
123
|
+
error = validate_schema(@schemas["action-upload_file"], body)
|
124
|
+
return [], error unless error.nil?
|
125
|
+
|
126
|
+
files = body['files']
|
127
|
+
destination = body['destination']
|
128
|
+
job_id = body['job_id']
|
129
|
+
cache_dir = @file_cache.create_cache_dir(job_id.to_s)
|
130
|
+
FileUtils.mkdir_p(cache_dir)
|
131
|
+
files.each do |file|
|
132
|
+
relative_path = file['relative_path']
|
133
|
+
uri = file['uri']
|
134
|
+
sha256 = file['sha256']
|
135
|
+
kind = file['kind']
|
136
|
+
path = File.join(cache_dir, relative_path)
|
137
|
+
if kind == 'file'
|
138
|
+
# The parent should already be created by `directory` entries,
|
139
|
+
# but this is to be on the safe side.
|
140
|
+
parent = File.dirname(path)
|
141
|
+
FileUtils.mkdir_p(parent)
|
142
|
+
@file_cache.download_file(path, sha256, uri)
|
143
|
+
elsif kind == 'directory'
|
144
|
+
# Create directory in cache so we can move files in.
|
145
|
+
FileUtils.mkdir_p(path)
|
146
|
+
else
|
147
|
+
return [400, Bolt::Error.new("Invalid `kind` of '#{kind}' supplied. Must be `file` or `directory`.",
|
148
|
+
'boltserver/schema-error').to_json]
|
149
|
+
end
|
150
|
+
end
|
151
|
+
[@executor.upload_file(target, cache_dir, destination), nil]
|
74
152
|
end
|
75
153
|
|
76
154
|
get '/' do
|
@@ -92,7 +170,31 @@ module BoltServer
|
|
92
170
|
raise 'Unexpected error'
|
93
171
|
end
|
94
172
|
|
95
|
-
ACTIONS = %w[
|
173
|
+
ACTIONS = %w[
|
174
|
+
check_node_connections
|
175
|
+
run_command
|
176
|
+
run_task
|
177
|
+
upload_file
|
178
|
+
].freeze
|
179
|
+
|
180
|
+
def make_ssh_target(target_hash)
|
181
|
+
defaults = {
|
182
|
+
'host-key-check' => false
|
183
|
+
}
|
184
|
+
|
185
|
+
overrides = {
|
186
|
+
'load-config' => false
|
187
|
+
}
|
188
|
+
|
189
|
+
opts = defaults.merge(target_hash.clone).merge(overrides)
|
190
|
+
|
191
|
+
if opts['private-key-content']
|
192
|
+
private_key_content = opts.delete('private-key-content')
|
193
|
+
opts['private-key'] = { 'key-data' => private_key_content }
|
194
|
+
end
|
195
|
+
|
196
|
+
Bolt::Target.new(target_hash['hostname'], opts)
|
197
|
+
end
|
96
198
|
|
97
199
|
post '/ssh/:action' do
|
98
200
|
not_found unless ACTIONS.include?(params[:action])
|
@@ -103,20 +205,24 @@ module BoltServer
|
|
103
205
|
error = validate_schema(@schemas["transport-ssh"], body)
|
104
206
|
return [400, error.to_json] unless error.nil?
|
105
207
|
|
106
|
-
|
107
|
-
|
108
|
-
if opts['private-key-content']
|
109
|
-
opts['private-key'] = { 'key-data' => opts['private-key-content'] }
|
110
|
-
opts.delete('private-key-content')
|
208
|
+
targets = (body['targets'] || [body['target']]).map do |target|
|
209
|
+
make_ssh_target(target)
|
111
210
|
end
|
112
|
-
opts['load-config'] = false
|
113
|
-
target = [Bolt::Target.new(body['target']['hostname'], opts)]
|
114
211
|
|
115
|
-
|
212
|
+
result_set, error = method(params[:action]).call(targets, body)
|
213
|
+
return [400, error.to_json] unless error.nil?
|
214
|
+
|
215
|
+
aggregate = body['target'].nil?
|
216
|
+
[200, result_set_to_status_hash(result_set, aggregate: aggregate).to_json]
|
217
|
+
end
|
218
|
+
|
219
|
+
def make_winrm_target(target_hash)
|
220
|
+
overrides = {
|
221
|
+
'protocol' => 'winrm'
|
222
|
+
}
|
116
223
|
|
117
|
-
|
118
|
-
|
119
|
-
[200, result.to_json]
|
224
|
+
opts = target_hash.clone.merge(overrides)
|
225
|
+
Bolt::Target.new(target_hash['hostname'], opts)
|
120
226
|
end
|
121
227
|
|
122
228
|
post '/winrm/:action' do
|
@@ -128,14 +234,15 @@ module BoltServer
|
|
128
234
|
error = validate_schema(@schemas["transport-winrm"], body)
|
129
235
|
return [400, error.to_json] unless error.nil?
|
130
236
|
|
131
|
-
|
132
|
-
|
237
|
+
targets = (body['targets'] || [body['target']]).map do |target|
|
238
|
+
make_winrm_target(target)
|
239
|
+
end
|
133
240
|
|
134
|
-
|
241
|
+
result_set, error = method(params[:action]).call(targets, body)
|
242
|
+
return [400, error.to_json] if error
|
135
243
|
|
136
|
-
|
137
|
-
|
138
|
-
[200, result.to_json]
|
244
|
+
aggregate = body['target'].nil?
|
245
|
+
[200, result_set_to_status_hash(result_set, aggregate: aggregate).to_json]
|
139
246
|
end
|
140
247
|
|
141
248
|
error 404 do
|
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: 1.30.
|
4
|
+
version: 1.30.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Puppet
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-09-
|
11
|
+
date: 2019-09-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -441,8 +441,10 @@ files:
|
|
441
441
|
- lib/bolt_server/base_config.rb
|
442
442
|
- lib/bolt_server/config.rb
|
443
443
|
- lib/bolt_server/file_cache.rb
|
444
|
+
- lib/bolt_server/schemas/action-check_node_connections.json
|
444
445
|
- lib/bolt_server/schemas/action-run_command.json
|
445
446
|
- lib/bolt_server/schemas/action-run_task.json
|
447
|
+
- lib/bolt_server/schemas/action-upload_file.json
|
446
448
|
- lib/bolt_server/schemas/partials/target-any.json
|
447
449
|
- lib/bolt_server/schemas/partials/target-ssh.json
|
448
450
|
- lib/bolt_server/schemas/partials/target-winrm.json
|