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 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