nomade 0.1.2 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e55097372de361a10d732fb15534044a7f61e2d7d3f99bcdbc32d247aa38fe15
4
- data.tar.gz: 3eb026188607bb0dd4814f996d7a5290733832cd669bdc73942a8c3c3f825115
3
+ metadata.gz: ed05d51537667ac01f3e77adf01ae2b614ae1d40e06fd4461c3def6a21171936
4
+ data.tar.gz: ca64489b697185037f1921838878963d3f3dbf585228c7f980e616db1a524d14
5
5
  SHA512:
6
- metadata.gz: e048c5df4f909bfdb575c12740a12b7e2985a74782eb6b54689f203356684754ea52f7b8f2eebabe0f44de24d1f7bc22815c6a86b19fdeddbbdfb9fd943ab1e9
7
- data.tar.gz: 1bbd0a9dcf2417651dfab2a64c41c3ffd39a80795d55f92dcc155f10d7c6e5b03f01a6982d11515eb79a54098ca2f7ad387098e3fa83400b6dffad9e7b5600ef
6
+ metadata.gz: fd50b280e996fea8c141242bd094b78cb4ecb23271402aa8a55a939d9b8ca6a988a9775d12d9d823db8a402f67ec2e789270eee95e7c8bbc5397e11352f2dfa6
7
+ data.tar.gz: 54117827d93c75f13c6ae2b79ee6c9eb58d3d3514f6ffaa481a6177a4d0b123a013aae063768e942a02067aee4014b47979465d3525902bc18f942b33d7fb709
@@ -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 # seconds
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 {|hook_type, nomad_job, messages|
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
- self
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 { |group_name, task_group_updates|
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
- @logger.info "EvaluationID: #{@evaluation_id}"
116
- @logger.info "#{@evaluation_id} Waiting until evaluation is complete"
117
- eval_status = nil
118
- while(eval_status != "complete") do
119
- evaluation = @http.evaluation_request(@evaluation_id)
120
- @deployment_id ||= evaluation["DeploymentID"]
121
- eval_status = evaluation["Status"]
122
- @logger.info "."
123
- sleep(1)
124
- end
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
- @logger.info "Waiting until allocations are no longer pending"
127
- allocations = @http.allocations_from_evaluation_request(@evaluation_id)
128
- until allocations.all?{|a| a["ClientStatus"] != "pending"}
129
- @logger.info "."
130
- sleep(2)
131
- allocations = @http.allocations_from_evaluation_request(@evaluation_id)
132
- end
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
- case @nomad_job.job_type
135
- when "service"
136
- service_deploy
137
- when "batch"
138
- batch_deploy
139
- else
140
- raise Nomade::GeneralError.new("Job-type '#{@nomad_job.job_type}' not implemented")
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
- placed_allocations = task_data["PlacedAllocs"]
413
+ _placed_allocations = task_data["PlacedAllocs"]
227
414
  healthy_allocations = task_data["HealthyAllocs"]
228
- unhealthy_allocations = task_data["UnhealthyAllocs"]
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(8..28)
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
- succesful_tasks = get_succesful_tasks(tasks)
509
+ _succesful_tasks = get_succesful_tasks(tasks)
323
510
  failed_tasks = get_failed_tasks(tasks)
324
511
 
325
512
  if upcoming_tasks.size == 0
@@ -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
@@ -3,5 +3,9 @@ module Nomade
3
3
  DEPLOY_RUNNING = Class.new
4
4
  DEPLOY_FINISHED = Class.new
5
5
  DEPLOY_FAILED = Class.new
6
+
7
+ DISPATCH_RUNNING = Class.new
8
+ DISPATCH_FINISHED = Class.new
9
+ DISPATCH_FAILED = Class.new
6
10
  end
7
11
  end
@@ -90,7 +90,7 @@ module Nomade
90
90
  "DeploymentID" => deployment_id,
91
91
  "All" => true,
92
92
  }.to_json
93
- res_body = _request(:post, "/v1/deployment/promote/#{deployment_id}", body: req_body)
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
- res_body = _request(:post, "/v1/deployment/fail/#{deployment_id}")
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 => e
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
- raise if res.code != "200"
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
 
@@ -10,7 +10,7 @@ module Nomade
10
10
  end
11
11
 
12
12
  Yell.new do |l|
13
- unless ARGV.include?("-q")
13
+ unless ENV["QUIET_NOMADE"] == "1"
14
14
  l.adapter STDOUT, level: stdout
15
15
  l.adapter STDERR, level: [:error, :fatal]
16
16
  end
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.2
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-03-06 00:00:00.000000000 Z
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.0.1
117
+ rubygems_version: 3.1.2
118
118
  signing_key:
119
119
  specification_version: 4
120
120
  summary: Gem that deploys nomad jobs