nomade 0.1.2 → 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/nomade/deployer.rb +222 -35
- data/lib/nomade/exceptions.rb +15 -0
- data/lib/nomade/hooks.rb +4 -0
- data/lib/nomade/http.rb +33 -7
- data/lib/nomade/logger.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed05d51537667ac01f3e77adf01ae2b614ae1d40e06fd4461c3def6a21171936
|
4
|
+
data.tar.gz: ca64489b697185037f1921838878963d3f3dbf585228c7f980e616db1a524d14
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd50b280e996fea8c141242bd094b78cb4ecb23271402aa8a55a939d9b8ca6a988a9775d12d9d823db8a402f67ec2e789270eee95e7c8bbc5397e11352f2dfa6
|
7
|
+
data.tar.gz: 54117827d93c75f13c6ae2b79ee6c9eb58d3d3514f6ffaa481a6177a4d0b123a013aae063768e942a02067aee4014b47979465d3525902bc18f942b33d7fb709
|
data/lib/nomade/deployer.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require "base64"
|
2
|
+
|
1
3
|
module Nomade
|
2
4
|
class Deployer
|
3
5
|
attr_reader :nomad_job
|
@@ -8,21 +10,32 @@ module Nomade
|
|
8
10
|
@job_builder = Nomade::JobBuilder.new(@http)
|
9
11
|
@logger = opts.fetch(:logger, Nomade.logger)
|
10
12
|
|
11
|
-
@timeout = 60 * 3
|
13
|
+
@timeout = opts.fetch(:timeout, 60 * 3)
|
14
|
+
|
15
|
+
@linger = opts.fetch(:linger, 8..28)
|
16
|
+
raise GeneralError.new("Linger needs to be a range, supplied with: #{@linger.class}") unless @linger.class == Range
|
12
17
|
|
13
18
|
@hooks = {
|
14
19
|
Nomade::Hooks::DEPLOY_RUNNING => [],
|
15
20
|
Nomade::Hooks::DEPLOY_FINISHED => [],
|
16
21
|
Nomade::Hooks::DEPLOY_FAILED => [],
|
22
|
+
|
23
|
+
Nomade::Hooks::DISPATCH_RUNNING => [],
|
24
|
+
Nomade::Hooks::DISPATCH_FINISHED => [],
|
25
|
+
Nomade::Hooks::DISPATCH_FAILED => [],
|
17
26
|
}
|
18
|
-
add_hook(Nomade::Hooks::DEPLOY_FAILED, lambda {|
|
27
|
+
add_hook(Nomade::Hooks::DEPLOY_FAILED, lambda {|_hook_type, _nomad_job, messages|
|
19
28
|
@logger.error "Failing deploy:"
|
20
29
|
messages.each do |message|
|
21
30
|
@logger.error "- #{message}"
|
22
31
|
end
|
23
32
|
})
|
24
|
-
|
25
|
-
|
33
|
+
add_hook(Nomade::Hooks::DISPATCH_FAILED, lambda {|_hook_type, _nomad_job, messages|
|
34
|
+
@logger.error "Failing dispatch:"
|
35
|
+
messages.each do |message|
|
36
|
+
@logger.error "- #{message}"
|
37
|
+
end
|
38
|
+
})
|
26
39
|
end
|
27
40
|
|
28
41
|
def init_job(template_file, image_full_name, template_variables = {})
|
@@ -31,6 +44,15 @@ module Nomade
|
|
31
44
|
@deployment_id = nil
|
32
45
|
|
33
46
|
self
|
47
|
+
rescue Nomade::HttpConnectionError => e
|
48
|
+
[e.class.to_s, e.message, "Http connection error, exiting!"].compact.uniq.map{|l| @logger.error(l)}
|
49
|
+
exit(7)
|
50
|
+
rescue Nomade::HttpBadResponse => e
|
51
|
+
[e.class.to_s, e.message, "Http bad response, exiting!"].compact.uniq.map{|l| @logger.error(l)}
|
52
|
+
exit(8)
|
53
|
+
rescue Nomade::HttpBadContentType => e
|
54
|
+
[e.class.to_s, e.message, "Http unexpected content type!"].compact.uniq.map{|l| @logger.error(l)}
|
55
|
+
exit(9)
|
34
56
|
end
|
35
57
|
|
36
58
|
def add_hook(hook, hook_method)
|
@@ -40,12 +62,20 @@ module Nomade
|
|
40
62
|
@hooks[Nomade::Hooks::DEPLOY_FINISHED] << hook_method
|
41
63
|
elsif Nomade::Hooks::DEPLOY_FAILED == hook
|
42
64
|
@hooks[Nomade::Hooks::DEPLOY_FAILED] << hook_method
|
65
|
+
elsif Nomade::Hooks::DISPATCH_RUNNING == hook
|
66
|
+
@hooks[Nomade::Hooks::DISPATCH_RUNNING] << hook_method
|
67
|
+
elsif Nomade::Hooks::DISPATCH_FINISHED == hook
|
68
|
+
@hooks[Nomade::Hooks::DISPATCH_FINISHED] << hook_method
|
69
|
+
elsif Nomade::Hooks::DISPATCH_FAILED == hook
|
70
|
+
@hooks[Nomade::Hooks::DISPATCH_FAILED] << hook_method
|
43
71
|
else
|
44
72
|
raise "#{hook} not supported!"
|
45
73
|
end
|
46
74
|
end
|
47
75
|
|
48
76
|
def deploy!
|
77
|
+
check_for_job_init
|
78
|
+
|
49
79
|
run_hooks(Nomade::Hooks::DEPLOY_RUNNING, @nomad_job, nil)
|
50
80
|
_plan
|
51
81
|
_deploy
|
@@ -67,14 +97,78 @@ module Nomade
|
|
67
97
|
rescue Nomade::DeploymentFailedError => e
|
68
98
|
run_hooks(Nomade::Hooks::DEPLOY_FAILED, @nomad_job, [e.class.to_s, e.message, "Couldn't deploy succesfully, exiting!"].compact.uniq)
|
69
99
|
exit(6)
|
100
|
+
rescue Nomade::HttpConnectionError => e
|
101
|
+
run_hooks(Nomade::Hooks::DEPLOY_FAILED, @nomad_job, [e.class.to_s, e.message, "Http connection error, exiting!"].compact.uniq)
|
102
|
+
exit(7)
|
103
|
+
rescue Nomade::HttpBadResponse => e
|
104
|
+
run_hooks(Nomade::Hooks::DEPLOY_FAILED, @nomad_job, [e.class.to_s, e.message, "Http bad response, exiting!"].compact.uniq)
|
105
|
+
exit(8)
|
106
|
+
rescue Nomade::HttpBadContentType => e
|
107
|
+
run_hooks(Nomade::Hooks::DEPLOY_FAILED, @nomad_job, [e.class.to_s, e.message, "Http unexpected content type!"].compact.uniq)
|
108
|
+
exit(9)
|
109
|
+
end
|
110
|
+
|
111
|
+
def dispatch!(payload_data: nil, payload_metadata: {})
|
112
|
+
check_for_job_init
|
113
|
+
|
114
|
+
run_hooks(Nomade::Hooks::DISPATCH_RUNNING, @nomad_job, nil)
|
115
|
+
_dispatch(payload_data, payload_metadata)
|
116
|
+
run_hooks(Nomade::Hooks::DISPATCH_FINISHED, @nomad_job, nil)
|
117
|
+
rescue Nomade::DispatchMetaDataFormattingError => e
|
118
|
+
run_hooks(Nomade::Hooks::DISPATCH_FAILED, @nomad_job, [e.class.to_s, e.message, "Metadata wrongly formatted, exiting!"].compact.uniq)
|
119
|
+
exit(10)
|
120
|
+
rescue Nomade::DispatchMissingMetaData => e
|
121
|
+
run_hooks(Nomade::Hooks::DISPATCH_FAILED, @nomad_job, [e.class.to_s, e.message, "Required metadata missing, exiting!"].compact.uniq)
|
122
|
+
exit(11)
|
123
|
+
rescue Nomade::DispatchUnknownMetaData => e
|
124
|
+
run_hooks(Nomade::Hooks::DISPATCH_FAILED, @nomad_job, [e.class.to_s, e.message, "Unknown metadata sent to server, exiting!"].compact.uniq)
|
125
|
+
exit(12)
|
126
|
+
rescue Nomade::DispatchMissingPayload => e
|
127
|
+
run_hooks(Nomade::Hooks::DISPATCH_FAILED, @nomad_job, [e.class.to_s, e.message, "Job requires payload, but payload isn't set!"].compact.uniq)
|
128
|
+
exit(20)
|
129
|
+
rescue Nomade::DispatchPayloadNotAllowed => e
|
130
|
+
run_hooks(Nomade::Hooks::DISPATCH_FAILED, @nomad_job, [e.class.to_s, e.message, "Job does not allow payload!"].compact.uniq)
|
131
|
+
exit(21)
|
132
|
+
rescue Nomade::DispatchPayloadUnknown => e
|
133
|
+
run_hooks(Nomade::Hooks::DISPATCH_FAILED, @nomad_job, [e.class.to_s, e.message, "API error!"].compact.uniq)
|
134
|
+
exit(22)
|
135
|
+
rescue Nomade::DispatchWrongJobType => e
|
136
|
+
run_hooks(Nomade::Hooks::DISPATCH_FAILED, @nomad_job, [e.class.to_s, e.message, "Job has wrong job-type"].compact.uniq)
|
137
|
+
exit(30)
|
138
|
+
rescue Nomade::DispatchNotParamaterized => e
|
139
|
+
run_hooks(Nomade::Hooks::DISPATCH_FAILED, @nomad_job, [e.class.to_s, e.message, "Job is not paramaterized"].compact.uniq)
|
140
|
+
exit(31)
|
141
|
+
rescue Nomade::AllocationFailedError => e
|
142
|
+
run_hooks(Nomade::Hooks::DISPATCH_FAILED, @nomad_job, [e.class.to_s, e.message, "Allocation failed with errors, exiting!"].compact.uniq)
|
143
|
+
exit(40)
|
144
|
+
rescue Nomade::GeneralError => e
|
145
|
+
run_hooks(Nomade::Hooks::DISPATCH_FAILED, @nomad_job, [e.class.to_s, e.message, "GeneralError hit, exiting!"].compact.uniq)
|
146
|
+
exit(1)
|
147
|
+
rescue Nomade::HttpConnectionError => e
|
148
|
+
run_hooks(Nomade::Hooks::DISPATCH_FAILED, @nomad_job, [e.class.to_s, e.message, "Http connection error, exiting!"].compact.uniq)
|
149
|
+
exit(7)
|
150
|
+
rescue Nomade::HttpBadResponse => e
|
151
|
+
run_hooks(Nomade::Hooks::DISPATCH_FAILED, @nomad_job, [e.class.to_s, e.message, "Http bad response, exiting!"].compact.uniq)
|
152
|
+
exit(8)
|
153
|
+
rescue Nomade::HttpBadContentType => e
|
154
|
+
run_hooks(Nomade::Hooks::DISPATCH_FAILED, @nomad_job, [e.class.to_s, e.message, "Http unexpected content type!"].compact.uniq)
|
155
|
+
exit(9)
|
70
156
|
end
|
71
157
|
|
72
158
|
def stop!(purge = false)
|
159
|
+
check_for_job_init
|
160
|
+
|
73
161
|
@http.stop_job(@nomad_job, purge)
|
74
162
|
end
|
75
163
|
|
76
164
|
private
|
77
165
|
|
166
|
+
def check_for_job_init
|
167
|
+
unless @nomad_job
|
168
|
+
raise Nomade::GeneralError.new("Did you forget to run init_job?")
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
78
172
|
def run_hooks(hook, job, messages)
|
79
173
|
@hooks[hook].each do |hook_method|
|
80
174
|
hook_method.call(hook, job, messages)
|
@@ -92,7 +186,7 @@ module Nomade
|
|
92
186
|
@logger.info "Checking cluster for connectivity and capacity.."
|
93
187
|
plan_data = @http.plan_job(@nomad_job)
|
94
188
|
|
95
|
-
sum_of_changes = plan_data["Annotations"]["DesiredTGUpdates"].map { |
|
189
|
+
sum_of_changes = plan_data["Annotations"]["DesiredTGUpdates"].map { |_group_name, task_group_updates|
|
96
190
|
task_group_updates["Stop"] +
|
97
191
|
task_group_updates["Place"] +
|
98
192
|
task_group_updates["Migrate"] +
|
@@ -112,32 +206,36 @@ module Nomade
|
|
112
206
|
@http.create_job(@nomad_job)
|
113
207
|
end
|
114
208
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
eval_status
|
122
|
-
|
123
|
-
|
124
|
-
|
209
|
+
if @evaluation_id.empty?
|
210
|
+
@logger.info "Parameterized job without evaluation, no more work needed"
|
211
|
+
else
|
212
|
+
@logger.info "EvaluationID: #{@evaluation_id}"
|
213
|
+
@logger.info "#{@evaluation_id} Waiting until evaluation is complete"
|
214
|
+
eval_status = nil
|
215
|
+
while(eval_status != "complete") do
|
216
|
+
evaluation = @http.evaluation_request(@evaluation_id)
|
217
|
+
@deployment_id ||= evaluation["DeploymentID"]
|
218
|
+
eval_status = evaluation["Status"]
|
219
|
+
@logger.info "."
|
220
|
+
sleep(1)
|
221
|
+
end
|
125
222
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
223
|
+
@logger.info "Waiting until allocations are no longer pending"
|
224
|
+
allocations = []
|
225
|
+
until !allocations.empty? && allocations.all?{|a| a["ClientStatus"] != "pending"}
|
226
|
+
@logger.info "."
|
227
|
+
sleep(2)
|
228
|
+
allocations = @http.allocations_from_evaluation_request(@evaluation_id)
|
229
|
+
end
|
133
230
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
231
|
+
case @nomad_job.job_type
|
232
|
+
when "service"
|
233
|
+
service_deploy
|
234
|
+
when "batch"
|
235
|
+
batch_deploy
|
236
|
+
else
|
237
|
+
raise Nomade::GeneralError.new("Job-type '#{@nomad_job.job_type}' not implemented")
|
238
|
+
end
|
141
239
|
end
|
142
240
|
rescue Nomade::AllocationFailedError => e
|
143
241
|
e.allocations.each do |allocation|
|
@@ -187,6 +285,96 @@ module Nomade
|
|
187
285
|
raise
|
188
286
|
end
|
189
287
|
|
288
|
+
def _dispatch(payload_data, payload_metadata)
|
289
|
+
@logger.info "Dispatching #{@nomad_job.job_name} (#{@nomad_job.job_type}) with #{@nomad_job.image_name_and_version}"
|
290
|
+
@logger.info "URL: #{@nomad_endpoint}/ui/jobs/#{@nomad_job.job_name}"
|
291
|
+
|
292
|
+
@logger.info "Running sanity checks.."
|
293
|
+
|
294
|
+
if @nomad_job.job_type != "batch"
|
295
|
+
raise DispatchWrongJobType.new("Job-type for #{@nomad_job.job_name} is \"#{@nomad_job.job_type}\" but should be \"batch\"")
|
296
|
+
end
|
297
|
+
|
298
|
+
if @nomad_job.configuration(:hash)["ParameterizedJob"] == nil
|
299
|
+
raise DispatchNotParamaterized.new("Job doesn't seem to be a paramaterized job, returned JobHash doesn't contain ParameterizedJob-key")
|
300
|
+
end
|
301
|
+
|
302
|
+
payload_data = if payload_data
|
303
|
+
Base64.encode64(payload_data)
|
304
|
+
else
|
305
|
+
nil
|
306
|
+
end
|
307
|
+
|
308
|
+
payload_metadata = if payload_metadata == nil
|
309
|
+
{}
|
310
|
+
else
|
311
|
+
Hash[payload_metadata.collect{|k,v| [k.to_s, v]}]
|
312
|
+
payload_metadata.each do |key, value|
|
313
|
+
unless [key, value].map(&:class) == [String, String]
|
314
|
+
raise Nomade::DispatchMetaDataFormattingError.new("Dispatch metadata must only be strings: #{key}(#{key.class}) = #{value}(#{value.class})")
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
meta_required = @nomad_job.configuration(:hash)["ParameterizedJob"]["MetaRequired"]
|
320
|
+
meta_optional = @nomad_job.configuration(:hash)["ParameterizedJob"]["MetaOptional"]
|
321
|
+
payload = @nomad_job.configuration(:hash)["ParameterizedJob"]["Payload"]
|
322
|
+
|
323
|
+
if meta_required
|
324
|
+
@logger.info "Dispatch job expects the following metakeys: #{meta_required.join(", ")}"
|
325
|
+
meta_required.each do |required_key|
|
326
|
+
unless payload_metadata.keys.include?(required_key)
|
327
|
+
raise Nomade::DispatchMissingMetaData.new("Dispatch job expects metakey #{required_key} but it was not set")
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
allowed_meta_tags = [meta_required, meta_optional].flatten.uniq
|
333
|
+
@logger.info "Dispatch job allows the following metakeys: #{allowed_meta_tags.join(", ")}"
|
334
|
+
if payload_metadata
|
335
|
+
payload_metadata.keys.each do |metadata_key|
|
336
|
+
unless allowed_meta_tags.include?(metadata_key)
|
337
|
+
raise Nomade::DispatchUnknownMetaData.new("Dispatch job does not allow #{metadata_key} to be set!")
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
case payload
|
343
|
+
when "optional", ""
|
344
|
+
@logger.info "Expectation for Payload is: optional"
|
345
|
+
when "required"
|
346
|
+
@logger.info "Expectation for Payload is: required"
|
347
|
+
|
348
|
+
unless payload_data
|
349
|
+
raise Nomade::DispatchMissingPayload.new("Dispatch job expects payload_data, but we don't supply any!")
|
350
|
+
end
|
351
|
+
when "forbidden"
|
352
|
+
@logger.info "Expectation for Payload is: forbidden"
|
353
|
+
|
354
|
+
if payload_data
|
355
|
+
raise Nomade::DispatchPayloadNotAllowed.new("Dispatch job do not allow payload_data!")
|
356
|
+
end
|
357
|
+
else
|
358
|
+
raise Nomade::DispatchPayloadUnknown.new("Invalid value for [\"ParameterizedJob\"][\"Payload\"] = #{payload}")
|
359
|
+
end
|
360
|
+
|
361
|
+
@logger.info "Checking cluster for connectivity and capacity.."
|
362
|
+
_plan_data = @http.plan_job(@nomad_job)
|
363
|
+
|
364
|
+
dispatch_job = @http.dispatch_job(@nomad_job, payload_data: payload_data, payload_metadata: payload_metadata)
|
365
|
+
@evaluation_id = dispatch_job["EvalID"]
|
366
|
+
|
367
|
+
@logger.info "Waiting until allocations are no longer pending"
|
368
|
+
allocations = []
|
369
|
+
until !allocations.empty? && allocations.all?{|a| a["ClientStatus"] != "pending"}
|
370
|
+
@logger.info "."
|
371
|
+
sleep(2)
|
372
|
+
allocations = @http.allocations_from_evaluation_request(@evaluation_id)
|
373
|
+
end
|
374
|
+
|
375
|
+
batch_deploy
|
376
|
+
end
|
377
|
+
|
190
378
|
def service_deploy
|
191
379
|
@logger.info "Waiting until tasks are placed"
|
192
380
|
deploy_timeout = Time.now.utc + @timeout
|
@@ -213,7 +401,6 @@ module Nomade
|
|
213
401
|
|
214
402
|
announced_completed = []
|
215
403
|
promoted = false
|
216
|
-
failed = false
|
217
404
|
succesful_deployment = nil
|
218
405
|
while(succesful_deployment == nil) do
|
219
406
|
json = @http.deployment_request(@deployment_id)
|
@@ -223,13 +410,13 @@ module Nomade
|
|
223
410
|
|
224
411
|
desired_canaries = task_data["DesiredCanaries"]
|
225
412
|
desired_total = task_data["DesiredTotal"]
|
226
|
-
|
413
|
+
_placed_allocations = task_data["PlacedAllocs"]
|
227
414
|
healthy_allocations = task_data["HealthyAllocs"]
|
228
|
-
|
415
|
+
_unhealthy_allocations = task_data["UnhealthyAllocs"]
|
229
416
|
|
230
417
|
if manual_work_required
|
231
418
|
@logger.info "#{json["ID"]} #{task_name}: #{healthy_allocations}/#{desired_canaries}/#{desired_total} (Healthy/WantedCanaries/Total)"
|
232
|
-
announced_completed << task_name if healthy_allocations == desired_canaries
|
419
|
+
announced_completed << task_name if healthy_allocations == desired_canaries && desired_canaries > 0
|
233
420
|
else
|
234
421
|
@logger.info "#{json["ID"]} #{task_name}: #{healthy_allocations}/#{desired_total} (Healthy/Total)"
|
235
422
|
announced_completed << task_name if healthy_allocations == desired_total
|
@@ -250,7 +437,7 @@ module Nomade
|
|
250
437
|
|
251
438
|
if succesful_deployment == nil && json["TaskGroups"].values.all?{|tg| tg["HealthyAllocs"] >= tg["DesiredCanaries"]}
|
252
439
|
if !promoted
|
253
|
-
random_linger = rand(
|
440
|
+
random_linger = rand(@linger)
|
254
441
|
@logger.info "Lingering around for #{random_linger} seconds before deployment.."
|
255
442
|
sleep(random_linger)
|
256
443
|
|
@@ -319,7 +506,7 @@ module Nomade
|
|
319
506
|
|
320
507
|
tasks = get_tasks(allocations)
|
321
508
|
upcoming_tasks = get_upcoming_tasks(tasks)
|
322
|
-
|
509
|
+
_succesful_tasks = get_succesful_tasks(tasks)
|
323
510
|
failed_tasks = get_failed_tasks(tasks)
|
324
511
|
|
325
512
|
if upcoming_tasks.size == 0
|
data/lib/nomade/exceptions.rb
CHANGED
@@ -16,4 +16,19 @@ module Nomade
|
|
16
16
|
|
17
17
|
class UnsupportedDeploymentMode < StandardError; end
|
18
18
|
class FailedTaskGroupPlan < StandardError; end
|
19
|
+
|
20
|
+
class DispatchWrongJobType < StandardError; end
|
21
|
+
class DispatchNotParamaterized < StandardError; end
|
22
|
+
|
23
|
+
class DispatchMetaDataFormattingError < StandardError; end
|
24
|
+
class DispatchMissingMetaData < StandardError; end
|
25
|
+
class DispatchUnknownMetaData < StandardError; end
|
26
|
+
|
27
|
+
class DispatchMissingPayload < StandardError; end
|
28
|
+
class DispatchPayloadNotAllowed < StandardError; end
|
29
|
+
class DispatchPayloadUnknown < StandardError; end
|
30
|
+
|
31
|
+
class HttpConnectionError < StandardError; end
|
32
|
+
class HttpBadResponse < StandardError; end
|
33
|
+
class HttpBadContentType < StandardError; end
|
19
34
|
end
|
data/lib/nomade/hooks.rb
CHANGED
data/lib/nomade/http.rb
CHANGED
@@ -90,7 +90,7 @@ module Nomade
|
|
90
90
|
"DeploymentID" => deployment_id,
|
91
91
|
"All" => true,
|
92
92
|
}.to_json
|
93
|
-
|
93
|
+
_request(:post, "/v1/deployment/promote/#{deployment_id}", body: req_body)
|
94
94
|
|
95
95
|
return true
|
96
96
|
rescue StandardError => e
|
@@ -99,7 +99,7 @@ module Nomade
|
|
99
99
|
end
|
100
100
|
|
101
101
|
def fail_deployment(deployment_id)
|
102
|
-
|
102
|
+
_request(:post, "/v1/deployment/fail/#{deployment_id}")
|
103
103
|
return true
|
104
104
|
rescue StandardError => e
|
105
105
|
Nomade.logger.fatal "HTTP Request failed (#{e.message})"
|
@@ -125,7 +125,7 @@ module Nomade
|
|
125
125
|
end
|
126
126
|
|
127
127
|
true
|
128
|
-
rescue Nomade::FailedTaskGroupPlan
|
128
|
+
rescue Nomade::FailedTaskGroupPlan
|
129
129
|
raise
|
130
130
|
rescue StandardError => e
|
131
131
|
Nomade.logger.fatal "HTTP Request failed (#{e.message})"
|
@@ -154,12 +154,34 @@ module Nomade
|
|
154
154
|
raise
|
155
155
|
end
|
156
156
|
|
157
|
+
def dispatch_job(nomad_job, payload_data: nil, payload_metadata: nil)
|
158
|
+
if payload_metadata.class != Hash
|
159
|
+
raise DispatchMetaDataFormattingError.new("Expected #{payload_metadata} to be a Hash, but received #{payload_metadata.class}")
|
160
|
+
end
|
161
|
+
|
162
|
+
req_body = JSON.generate({
|
163
|
+
"Payload": payload_data,
|
164
|
+
"Meta": payload_metadata,
|
165
|
+
}.delete_if { |_k, v| v.nil? })
|
166
|
+
|
167
|
+
res_body = _request(:post, "/v1/job/#{nomad_job.job_name}/dispatch", body: req_body)
|
168
|
+
JSON.parse(res_body)
|
169
|
+
rescue StandardError => e
|
170
|
+
Nomade.logger.fatal "HTTP Request failed (#{e.message})"
|
171
|
+
raise
|
172
|
+
end
|
173
|
+
|
157
174
|
private
|
158
175
|
|
159
176
|
def _request(request_type, path, body: nil, total_retries: 0, expected_content_type: "application/json")
|
160
177
|
uri = URI("#{@nomad_endpoint}#{path}")
|
161
178
|
|
162
179
|
http = Net::HTTP.new(uri.host, uri.port)
|
180
|
+
http.open_timeout = 10
|
181
|
+
http.read_timeout = 10
|
182
|
+
http.write_timeout = 10 if Net::HTTP.method_defined?(:write_timeout)
|
183
|
+
http.ssl_timeout = 10
|
184
|
+
|
163
185
|
if @nomad_endpoint.include?("https://")
|
164
186
|
http.use_ssl = true
|
165
187
|
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
@@ -175,30 +197,34 @@ module Nomade
|
|
175
197
|
else
|
176
198
|
raise "#{request_type} not supported"
|
177
199
|
end
|
200
|
+
|
178
201
|
req.add_field "Content-Type", "application/json"
|
179
202
|
req.body = body if body
|
180
203
|
|
181
204
|
res = begin
|
182
205
|
retries ||= 0
|
183
206
|
http.request(req)
|
184
|
-
rescue Timeout::Error, Errno::ETIMEDOUT, Errno::EINVAL, Errno::ECONNRESET, EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError, SocketError
|
207
|
+
rescue Timeout::Error, Errno::ETIMEDOUT, Errno::EINVAL, Errno::ECONNRESET, EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError, SocketError => e
|
185
208
|
if retries < total_retries
|
186
209
|
retries += 1
|
187
210
|
sleep 1
|
188
211
|
retry
|
189
212
|
else
|
190
|
-
raise
|
213
|
+
raise HttpConnectionError.new("#{e.class} - #{e.message}")
|
191
214
|
end
|
192
215
|
end
|
193
216
|
|
194
|
-
|
217
|
+
if res.code != "200"
|
218
|
+
raise HttpBadResponse.new("Bad response (not 200) but #{res.code}: #{res.body}")
|
219
|
+
end
|
220
|
+
|
195
221
|
if res.content_type != expected_content_type
|
196
222
|
# Sometimes the log endpoint doesn't set content_type on no content
|
197
223
|
# https://github.com/hashicorp/nomad/issues/7264
|
198
224
|
if res.content_type == nil && expected_content_type == "text/plain"
|
199
225
|
# don't raise
|
200
226
|
else
|
201
|
-
raise
|
227
|
+
raise HttpBadContentType.new("Expected #{expected_content_type} but got #{res.content_type}")
|
202
228
|
end
|
203
229
|
end
|
204
230
|
|
data/lib/nomade/logger.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nomade
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kasper Grubbe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-05-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: yell
|
@@ -114,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
114
114
|
- !ruby/object:Gem::Version
|
115
115
|
version: '0'
|
116
116
|
requirements: []
|
117
|
-
rubygems_version: 3.
|
117
|
+
rubygems_version: 3.1.2
|
118
118
|
signing_key:
|
119
119
|
specification_version: 4
|
120
120
|
summary: Gem that deploys nomad jobs
|