nomade 0.0.5 → 0.1.0

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: 85557a8305dae1d56eaf0f9d8497948f928f270b8f43d28860836a1ad1fb0b3e
4
- data.tar.gz: 92e9afd8c92efb363edf7daf7c3f04f40dd71ca243c58dddfd9d4cd71925bd65
3
+ metadata.gz: c6c3684724566430b8c0af280a5be1e03be57a5c7bcac2298c22d14d03098565
4
+ data.tar.gz: ae59d84da529ab3e4041d52a9216f0cf4e68cd7cd39751d895907d05f52b19cf
5
5
  SHA512:
6
- metadata.gz: 0f33f910a59f67c4dcf63ba394a4d4a6d3e48ea555a562d73f5ee2d0dc59e98489270b9502a5e3dc8a2f56398a4d605e0ee11a135d26332a74a5186e3b162d44
7
- data.tar.gz: 172af74987917d6a0b2cea45d2e461991a5bc7af46de64a738edd220ecd0e829a25293013fcc45e864c1e7e4eeb74cbcc4da813b86188403a57016bb3f813266
6
+ metadata.gz: 1fb1d40654d23c00694ca29e9423050e3e829dd543dd293b5655c7def2885fa0c73593bc06a35a7f3c7f53869b3f4afc470077d9e9613cb8b0d113d1328ee49f
7
+ data.tar.gz: be3a100801b40b10a38f162095a86f3f36e386b9ff17e46ee7597e7ab37c373e059c8472acbfa6262bd56d37743252d5bb7780925812cfef6227a7f18c63d54f
@@ -1,66 +1,103 @@
1
1
  module Nomade
2
2
  class Deployer
3
- def initialize(nomad_endpoint, nomad_job, opts = {})
4
- @nomad_job = nomad_job
5
- @evaluation_id = nil
6
- @deployment_id = nil
7
- @timeout = Time.now.utc + 60 * 3 # minutes
3
+ attr_reader :nomad_job
4
+
5
+ def initialize(nomad_endpoint, opts = {})
8
6
  @nomad_endpoint = nomad_endpoint
9
7
  @http = Nomade::Http.new(@nomad_endpoint)
8
+ @job_builder = Nomade::JobBuilder.new(@http)
10
9
  @logger = opts.fetch(:logger, Nomade.logger)
11
10
 
12
- @on_success = opts.fetch(:on_success, [])
13
- @on_failure = opts.fetch(:on_failure, [])
14
- @on_failure << method(:print_errors)
11
+ @timeout = 60 * 3 # seconds
12
+
13
+ @hooks = {
14
+ Nomade::Hooks::DEPLOY_RUNNING => [],
15
+ Nomade::Hooks::DEPLOY_FINISHED => [],
16
+ Nomade::Hooks::DEPLOY_FAILED => [],
17
+ }
18
+
19
+ self
20
+ end
21
+
22
+ def init_job(template_file, image_full_name, template_variables = {})
23
+ @nomad_job = @job_builder.build(template_file, image_full_name, template_variables)
24
+ @evaluation_id = nil
25
+ @deployment_id = nil
26
+
27
+ self
28
+ end
29
+
30
+ def add_hook(hook, hook_method)
31
+ if Nomade::Hooks::DEPLOY_RUNNING == hook
32
+ @hooks[Nomade::Hooks::DEPLOY_RUNNING] << hook_method
33
+ elsif Nomade::Hooks::DEPLOY_FINISHED == hook
34
+ @hooks[Nomade::Hooks::DEPLOY_FINISHED] << hook_method
35
+ elsif Nomade::Hooks::DEPLOY_FAILED == hook
36
+ @hooks[Nomade::Hooks::DEPLOY_FAILED] << hook_method
37
+ else
38
+ raise "#{hook} not supported!"
39
+ end
15
40
  end
16
41
 
17
42
  def deploy!
18
- plan
19
- deploy
43
+ run_hooks(Nomade::Hooks::DEPLOY_RUNNING, @nomad_job, nil)
44
+ _plan
45
+ _deploy
46
+ run_hooks(Nomade::Hooks::DEPLOY_FINISHED, @nomad_job, nil)
20
47
  rescue Nomade::NoModificationsError => e
21
- call_failure_handlers ["No modifications to make, exiting!"]
48
+ run_hooks(Nomade::Hooks::DEPLOY_FAILED, @nomad_job, [e.message, "No modifications to make, exiting!"])
22
49
  exit(0)
23
50
  rescue Nomade::GeneralError => e
24
- call_failure_handlers [e.message, "GeneralError hit, exiting!"]
51
+ run_hooks(Nomade::Hooks::DEPLOY_FAILED, @nomad_job, [e.message, "GeneralError hit, exiting!"])
25
52
  exit(1)
26
- rescue Nomade::PlanningError => e
27
- call_failure_handlers ["Couldn't make a plan, maybe a bad connection to Nomad server, exiting!"]
28
- exit(2)
29
53
  rescue Nomade::AllocationFailedError => e
30
- call_failure_handlers ["Allocation failed with errors, exiting!"]
54
+ run_hooks(Nomade::Hooks::DEPLOY_FAILED, @nomad_job, [e.message, "Allocation failed with errors, exiting!"])
31
55
  exit(3)
32
56
  rescue Nomade::UnsupportedDeploymentMode => e
33
- call_failure_handlers [e.message, "Deployment failed with errors, exiting!"]
57
+ run_hooks(Nomade::Hooks::DEPLOY_FAILED, @nomad_job, [e.message, "Deployment failed with errors, exiting!"])
34
58
  exit(4)
35
59
  rescue Nomade::FailedTaskGroupPlan => e
36
- call_failure_handlers [e.message, "Couldn't plan correctly, exiting!"]
60
+ run_hooks(Nomade::Hooks::DEPLOY_FAILED, @nomad_job, [e.message, "Couldn't plan correctly, exiting!"])
37
61
  exit(5)
62
+ rescue Nomade::DeploymentFailedError => e
63
+ run_hooks(Nomade::Hooks::DEPLOY_FAILED, @nomad_job, [e.message, "Couldn't deploy succesfully, exiting!"])
64
+ exit(6)
38
65
  end
39
66
 
40
- private
41
-
42
- def call_failure_handlers(messages)
43
- @on_failure.each do |failure_handler|
44
- failure_handler.call(messages)
45
- end
67
+ def stop!(purge = false)
68
+ @http.stop_job(@nomad_job, purge)
46
69
  end
47
70
 
48
- def print_errors(errors)
49
- errors.each do |error|
50
- @logger.warn(error)
71
+ private
72
+
73
+ def run_hooks(hook, job, messages)
74
+ @hooks[hook].each do |hook_method|
75
+ hook_method.call(hook, job, messages)
51
76
  end
52
77
  end
53
78
 
54
- def plan
79
+ def _plan
55
80
  @http.capacity_plan_job(@nomad_job)
56
81
  end
57
82
 
58
- def deploy
83
+ def _deploy
59
84
  @logger.info "Deploying #{@nomad_job.job_name} (#{@nomad_job.job_type}) with #{@nomad_job.image_name_and_version}"
60
85
  @logger.info "URL: #{@nomad_endpoint}/ui/jobs/#{@nomad_job.job_name}"
61
86
 
62
87
  @logger.info "Checking cluster for connectivity and capacity.."
63
- @http.plan_job(@nomad_job)
88
+ plan_data = @http.plan_job(@nomad_job)
89
+
90
+ sum_of_changes = plan_data["Annotations"]["DesiredTGUpdates"].map { |group_name, task_group_updates|
91
+ task_group_updates["Stop"] +
92
+ task_group_updates["Place"] +
93
+ task_group_updates["Migrate"] +
94
+ task_group_updates["DestructiveUpdate"] +
95
+ task_group_updates["Canary"]
96
+ }.sum
97
+
98
+ if sum_of_changes == 0
99
+ raise Nomade::NoModificationsError.new
100
+ end
64
101
 
65
102
  @evaluation_id = if @http.check_if_job_exists?(@nomad_job)
66
103
  @logger.info "Updating existing job"
@@ -81,7 +118,14 @@ module Nomade
81
118
  sleep(1)
82
119
  end
83
120
 
84
- @logger.info "Waiting until allocations are complete"
121
+ @logger.info "Waiting until allocations are no longer pending"
122
+ allocations = @http.allocations_from_evaluation_request(@evaluation_id)
123
+ until allocations.all?{|a| a["ClientStatus"] != "pending"}
124
+ @logger.info "."
125
+ sleep(2)
126
+ allocations = @http.allocations_from_evaluation_request(@evaluation_id)
127
+ end
128
+
85
129
  case @nomad_job.job_type
86
130
  when "service"
87
131
  service_deploy
@@ -106,7 +150,7 @@ module Nomade
106
150
  if stdout != ""
107
151
  @logger.info
108
152
  @logger.info "stdout:"
109
- stdout.lines do |logline|
153
+ stdout.lines.each do |logline|
110
154
  @logger.info(logline.strip)
111
155
  end
112
156
  end
@@ -115,7 +159,7 @@ module Nomade
115
159
  if stderr != ""
116
160
  @logger.info
117
161
  @logger.info "stderr:"
118
- stderr.lines do |logline|
162
+ stderr.lines.each do |logline|
119
163
  @logger.info(logline.strip)
120
164
  end
121
165
  end
@@ -140,7 +184,8 @@ module Nomade
140
184
 
141
185
  def service_deploy
142
186
  @logger.info "Waiting until tasks are placed"
143
- @logger.info ".. deploy timeout is #{@timeout}"
187
+ deploy_timeout = Time.now.utc + @timeout
188
+ @logger.info ".. deploy timeout is #{deploy_timeout}"
144
189
 
145
190
  json = @http.deployment_request(@deployment_id)
146
191
  @logger.info "#{json["JobID"]} version #{json["JobVersion"]}"
@@ -192,7 +237,7 @@ module Nomade
192
237
  succesful_deployment = false
193
238
  end
194
239
 
195
- if succesful_deployment == nil && Time.now.utc > @timeout
240
+ if succesful_deployment == nil && Time.now.utc > deploy_timeout
196
241
  @logger.info "Timeout hit, rolling back deploy!"
197
242
  @http.fail_deployment(@deployment_id)
198
243
  succesful_deployment = false
@@ -235,9 +280,13 @@ module Nomade
235
280
  if succesful_deployment
236
281
  @logger.info ""
237
282
  @logger.info "#{@deployment_id} (version #{json["JobVersion"]}) was succesfully deployed!"
283
+
284
+ true
238
285
  else
239
286
  @logger.warn ""
240
287
  @logger.warn "#{@deployment_id} (version #{json["JobVersion"]}) deployment _failed_!"
288
+
289
+ raise DeploymentFailedError.new
241
290
  end
242
291
  end
243
292
 
@@ -286,7 +335,7 @@ module Nomade
286
335
  if stdout != ""
287
336
  @logger.info
288
337
  @logger.info "stdout:"
289
- stdout.lines do |logline|
338
+ stdout.lines.each do |logline|
290
339
  @logger.info(logline.strip)
291
340
  end
292
341
  end
@@ -295,7 +344,7 @@ module Nomade
295
344
  if stderr != ""
296
345
  @logger.info
297
346
  @logger.info "stderr:"
298
- stderr.lines do |logline|
347
+ stderr.lines.each do |logline|
299
348
  @logger.info(logline.strip)
300
349
  end
301
350
  end
@@ -307,6 +356,8 @@ module Nomade
307
356
 
308
357
  sleep(1)
309
358
  end
359
+
360
+ true
310
361
  end
311
362
 
312
363
  # Task-helpers
@@ -1,7 +1,8 @@
1
1
  module Nomade
2
+ class FormattingError < StandardError; end
3
+
2
4
  class GeneralError < StandardError; end
3
5
  class NoModificationsError < StandardError; end
4
- class PlanningError < StandardError; end
5
6
 
6
7
  class AllocationFailedError < StandardError
7
8
  def initialize(evaluation_id, allocations)
@@ -10,6 +11,9 @@ module Nomade
10
11
  end
11
12
  attr_reader :evaluation_id, :allocations
12
13
  end
14
+
15
+ class DeploymentFailedError < StandardError;end
16
+
13
17
  class UnsupportedDeploymentMode < StandardError; end
14
18
  class FailedTaskGroupPlan < StandardError; end
15
19
  end
@@ -0,0 +1,7 @@
1
+ module Nomade
2
+ module Hooks
3
+ DEPLOY_RUNNING = Class.new
4
+ DEPLOY_FINISHED = Class.new
5
+ DEPLOY_FAILED = Class.new
6
+ end
7
+ end
data/lib/nomade/http.rb CHANGED
@@ -120,9 +120,10 @@ module Nomade
120
120
 
121
121
  req = Net::HTTP::Post.new(uri)
122
122
  req.add_field "Content-Type", "application/json"
123
- req.body = nomad_job.configuration(:json)
123
+ req.body = JSON.generate({"Job" => nomad_job.configuration(:hash)})
124
124
 
125
125
  res = http.request(req)
126
+
126
127
  raise if res.code != "200"
127
128
  raise if res.content_type != "application/json"
128
129
 
@@ -143,7 +144,34 @@ module Nomade
143
144
 
144
145
  req = Net::HTTP::Post.new(uri)
145
146
  req.add_field "Content-Type", "application/json"
146
- req.body = nomad_job.configuration(:json)
147
+ req.body = JSON.generate({"Job" => nomad_job.configuration(:hash)})
148
+
149
+ res = http.request(req)
150
+
151
+ raise if res.code != "200"
152
+ raise if res.content_type != "application/json"
153
+
154
+ return JSON.parse(res.body)["EvalID"]
155
+ rescue StandardError => e
156
+ Nomade.logger.fatal "HTTP Request failed (#{e.message})"
157
+ raise
158
+ end
159
+
160
+ def stop_job(nomad_job, purge = false)
161
+ uri = if purge
162
+ URI("#{@nomad_endpoint}/v1/job/#{nomad_job.job_name}?purge=true")
163
+ else
164
+ URI("#{@nomad_endpoint}/v1/job/#{nomad_job.job_name}")
165
+ end
166
+
167
+ http = Net::HTTP.new(uri.host, uri.port)
168
+ if @nomad_endpoint.include?("https://")
169
+ http.use_ssl = true
170
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
171
+ end
172
+
173
+ req = Net::HTTP::Delete.new(uri)
174
+ req.add_field "Content-Type", "application/json"
147
175
 
148
176
  res = http.request(req)
149
177
  raise if res.code != "200"
@@ -223,7 +251,22 @@ module Nomade
223
251
  end
224
252
 
225
253
  def capacity_plan_job(nomad_job)
226
- uri = URI("#{@nomad_endpoint}/v1/job/#{nomad_job.job_name}/plan")
254
+ plan_output = plan_job(nomad_job)
255
+
256
+ if plan_output["FailedTGAllocs"]
257
+ raise Nomade::FailedTaskGroupPlan.new("Failed to plan groups: #{plan_output["FailedTGAllocs"].keys.join(",")}")
258
+ end
259
+
260
+ true
261
+ rescue Nomade::FailedTaskGroupPlan => e
262
+ raise
263
+ rescue StandardError => e
264
+ Nomade.logger.fatal "HTTP Request failed (#{e.message})"
265
+ raise
266
+ end
267
+
268
+ def convert_hcl_to_json(job_hcl)
269
+ uri = URI("#{@nomad_endpoint}/v1/jobs/parse")
227
270
 
228
271
  http = Net::HTTP.new(uri.host, uri.port)
229
272
  if @nomad_endpoint.include?("https://")
@@ -233,46 +276,45 @@ module Nomade
233
276
 
234
277
  req = Net::HTTP::Post.new(uri)
235
278
  req.add_field "Content-Type", "application/json"
236
- req.body = nomad_job.configuration(:json)
279
+
280
+ req.body = JSON.generate({
281
+ "JobHCL": job_hcl,
282
+ "Canonicalize": false,
283
+ })
237
284
 
238
285
  res = http.request(req)
239
286
  raise if res.code != "200"
240
287
  raise if res.content_type != "application/json"
241
288
 
242
- plan_output = JSON.parse(res.body)
243
-
244
- if plan_output["FailedTGAllocs"]
245
- raise Nomade::FailedTaskGroupPlan.new("Failed to plan groups: #{plan_output["FailedTGAllocs"].keys.join(",")}")
246
- end
247
-
248
- true
249
- rescue Nomade::FailedTaskGroupPlan => e
250
- raise
289
+ res.body
251
290
  rescue StandardError => e
252
291
  Nomade.logger.fatal "HTTP Request failed (#{e.message})"
253
292
  raise
254
293
  end
255
294
 
256
295
  def plan_job(nomad_job)
257
- rendered_template = nomad_job.configuration(:hcl)
258
-
259
- # 0: No allocations created or destroyed. Nothing to do.
260
- # 1: Allocations created or destroyed.
261
- # 255: Error determining plan results. Nothing to do.
262
- allowed_exit_codes = [0, 1, 255]
263
-
264
- exit_status, stdout, stderr = Shell.exec("NOMAD_ADDR=#{@nomad_endpoint} nomad job plan -diff -verbose -no-color -", rendered_template, allowed_exit_codes)
265
-
266
- case exit_status
267
- when 0
268
- raise Nomade::NoModificationsError.new
269
- when 1
270
- # no-op
271
- when 255
272
- raise Nomade::PlanningError.new
296
+ uri = URI("#{@nomad_endpoint}/v1/job/#{nomad_job.job_name}/plan")
297
+
298
+ http = Net::HTTP.new(uri.host, uri.port)
299
+ if @nomad_endpoint.include?("https://")
300
+ http.use_ssl = true
301
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
273
302
  end
274
303
 
275
- true
304
+ req = Net::HTTP::Post.new(uri)
305
+ req.add_field "Content-Type", "application/json"
306
+ req.body = JSON.generate({"Job" => nomad_job.configuration(:hash)})
307
+
308
+ res = http.request(req)
309
+
310
+ raise if res.code != "200"
311
+ raise if res.content_type != "application/json"
312
+
313
+ JSON.parse(res.body)
314
+ rescue StandardError => e
315
+ Nomade.logger.fatal "HTTP Request failed (#{e.message})"
316
+ raise
276
317
  end
318
+
277
319
  end
278
320
  end
data/lib/nomade/job.rb CHANGED
@@ -1,25 +1,10 @@
1
- require "erb"
2
- require "json"
3
-
4
1
  module Nomade
5
2
  class Job
6
- class FormattingError < StandardError; end
7
-
8
- def initialize(template_file, image_full_name, template_variables = {})
3
+ def initialize(image_full_name, config_hcl, config_json, config_hash)
9
4
  @image_full_name = image_full_name
10
- @template_variables = template_variables
11
-
12
- # image_full_name should be in the form of:
13
- # redis:4.0.1
14
- # kaspergrubbe/secretimage:latest
15
- # billetto/billetto-rails:4.2.24
16
- unless @image_full_name.match(/\A[a-zA-Z0-9\/\-\_]+\:[a-zA-Z0-9\.\-\_]+\z/)
17
- raise Nomade::Job::FormattingError.new("Image-format wrong: #{@image_full_name}")
18
- end
19
-
20
- @config_hcl = render_erb(template_file)
21
- @config_json = convert_job_hcl_to_json(@config_hcl)
22
- @config_hash = JSON.parse(@config_json)
5
+ @config_hcl = config_hcl
6
+ @config_json = config_json
7
+ @config_hash = config_hash
23
8
  end
24
9
 
25
10
  def configuration(format)
@@ -28,17 +13,19 @@ module Nomade
28
13
  @config_hcl
29
14
  when :json
30
15
  @config_json
16
+ when :hash
17
+ @config_hash
31
18
  else
32
19
  @config_hash
33
20
  end
34
21
  end
35
22
 
36
23
  def job_name
37
- @config_hash["Job"]["ID"]
24
+ @config_hash["ID"]
38
25
  end
39
26
 
40
27
  def job_type
41
- @config_hash["Job"]["Type"]
28
+ @config_hash["Type"]
42
29
  end
43
30
 
44
31
  def image_name_and_version
@@ -53,25 +40,5 @@ module Nomade
53
40
  image_name_and_version.split(":").last
54
41
  end
55
42
 
56
- def template_variables
57
- @template_variables
58
- end
59
-
60
- private
61
-
62
- def render_erb(erb_template)
63
- file = File.open(erb_template).read
64
- rendered = ERB.new(file, nil, '-').result(binding)
65
-
66
- rendered
67
- end
68
-
69
- def convert_job_hcl_to_json(rendered_template)
70
- exit_status, stdout, stderr = Shell.exec("nomad job run -output -no-color -", rendered_template)
71
-
72
- JSON.pretty_generate({
73
- "Job": JSON.parse(stdout)["Job"],
74
- })
75
- end
76
43
  end
77
44
  end
@@ -0,0 +1,46 @@
1
+ require "erb"
2
+ require "json"
3
+
4
+ module Nomade
5
+ class JobBuilder
6
+ def initialize(http)
7
+ @http = http
8
+ end
9
+
10
+ def build(template_file, image_full_name, template_variables = {})
11
+ # image_full_name should be in the form of:
12
+ # redis:4.0.1
13
+ # kaspergrubbe/secretimage:latest
14
+ # billetto/billetto-rails:4.2.24
15
+ unless image_full_name.match(/\A[a-zA-Z0-9\/\-\_]+\:[a-zA-Z0-9\.\-\_]+\z/)
16
+ raise Nomade::FormattingError.new("Image-format wrong: #{image_full_name}")
17
+ end
18
+
19
+ job_hcl = render_erb(template_file, image_full_name, template_variables)
20
+ job_json = @http.convert_hcl_to_json(job_hcl)
21
+ job_hash = JSON.parse(job_json)
22
+
23
+ Nomade::Job.new(image_full_name, job_hcl, job_json, job_hash)
24
+ end
25
+
26
+ private
27
+
28
+ def render_erb(erb_template, image_full_name, template_variables)
29
+ file = File.open(erb_template).read
30
+
31
+ local_binding = binding
32
+ local_binding.local_variable_set(:image_name_and_version, image_full_name)
33
+ local_binding.local_variable_set(:image_full_name, image_full_name)
34
+ local_binding.local_variable_set(:template_variables, template_variables)
35
+
36
+ # https://github.com/ruby/ruby/commit/3406c5d
37
+ rendered = if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+
38
+ ERB.new(file, trim_mode: '-')
39
+ else
40
+ ERB.new(file, nil, '-')
41
+ end
42
+
43
+ rendered.result(local_binding)
44
+ end
45
+ end
46
+ end
data/lib/nomade/logger.rb CHANGED
@@ -10,8 +10,10 @@ module Nomade
10
10
  end
11
11
 
12
12
  Yell.new do |l|
13
- l.adapter STDOUT, level: stdout
14
- l.adapter STDERR, level: [:error, :fatal]
13
+ unless ARGV.include?("-q")
14
+ l.adapter STDOUT, level: stdout
15
+ l.adapter STDERR, level: [:error, :fatal]
16
+ end
15
17
  end
16
18
  end
17
19
  end
data/lib/nomade.rb CHANGED
@@ -1,12 +1,13 @@
1
1
  ENV["TZ"] = "UTC"
2
2
 
3
- require "nomade/shell"
4
- require "nomade/job"
5
- require "nomade/logger"
3
+ require "nomade/decorators"
4
+ require "nomade/deployer"
6
5
  require "nomade/exceptions"
6
+ require "nomade/hooks"
7
7
  require "nomade/http"
8
- require "nomade/deployer"
9
- require "nomade/decorators"
8
+ require "nomade/job"
9
+ require "nomade/job_builder"
10
+ require "nomade/logger"
10
11
 
11
12
  module Nomade
12
13
  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.0.5
4
+ version: 0.1.0
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-02-26 00:00:00.000000000 Z
11
+ date: 2020-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: yell
@@ -42,16 +42,44 @@ dependencies:
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.9.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.9.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
46
60
  - !ruby/object:Gem::Version
47
- version: '0'
61
+ version: 0.18.5
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
- - - ">="
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.18.5
69
+ - !ruby/object:Gem::Dependency
70
+ name: irb
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 1.0.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
53
81
  - !ruby/object:Gem::Version
54
- version: '0'
82
+ version: 1.0.0
55
83
  description:
56
84
  email: nomade@kaspergrubbe.com
57
85
  executables: []
@@ -62,10 +90,11 @@ files:
62
90
  - lib/nomade/decorators.rb
63
91
  - lib/nomade/deployer.rb
64
92
  - lib/nomade/exceptions.rb
93
+ - lib/nomade/hooks.rb
65
94
  - lib/nomade/http.rb
66
95
  - lib/nomade/job.rb
96
+ - lib/nomade/job_builder.rb
67
97
  - lib/nomade/logger.rb
68
- - lib/nomade/shell.rb
69
98
  homepage: https://billetto.com
70
99
  licenses:
71
100
  - MIT
data/lib/nomade/shell.rb DELETED
@@ -1,45 +0,0 @@
1
- require "open3"
2
-
3
- module Nomade
4
- class Shell
5
- def self.exec(command, input = nil, allowed_exit_codes = [0])
6
- Nomade.logger.debug("+: #{command}")
7
-
8
- process, status, stdout, stderr = Open3.popen3(command) do |stdin, stdout, stderr, wait_thread|
9
- if input
10
- stdin.puts(input)
11
- end
12
- stdin.close
13
-
14
- threads = {}.tap do |it|
15
- it[:stdout] = Thread.new do
16
- output = []
17
- stdout.each do |l|
18
- output << l
19
- Nomade.logger.debug(l)
20
- end
21
- Thread.current[:output] = output.join
22
- end
23
-
24
- it[:stderr] = Thread.new do
25
- output = []
26
- stderr.each do |l|
27
- output << l
28
- Nomade.logger.debug(l)
29
- end
30
- Thread.current[:output] = output.join
31
- end
32
- end
33
- threads.values.map(&:join)
34
-
35
- [wait_thread.value, wait_thread.value.exitstatus, threads[:stdout][:output], threads[:stderr][:output]]
36
- end
37
-
38
- unless allowed_exit_codes.include?(status)
39
- raise "`#{command}` failed with status=#{status}"
40
- end
41
-
42
- return [status, stdout, stderr]
43
- end
44
- end
45
- end