nomade 0.0.2 → 0.0.3
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 +60 -55
- data/lib/nomade/http.rb +36 -18
- data/lib/nomade/job.rb +6 -5
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 66623cdf7c89395ba7cd5ec0e44da3f7f528acb9
|
4
|
+
data.tar.gz: 74babd5bdb5d5defa0f8d43c48b58122d0e9ed62
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c82745d63012c33c98e7e23f178deb9caeb071189aa9b6e317c2251efdc10bebae3bbf96c6f4d89861492f9bc88c081d7947f27d7c70dd6993965fc56dcb50ff
|
7
|
+
data.tar.gz: 29da63fc9823646b42605d759c989b7bc30d19c1677acb9d38b11c8fe444f817a1302df7d7cb024f8674ec3ccddabe9ed9bfa7548cbf3b06d249d8c09a27ff94
|
data/lib/nomade/deployer.rb
CHANGED
@@ -1,64 +1,65 @@
|
|
1
1
|
module Nomade
|
2
2
|
class Deployer
|
3
|
-
def initialize(nomad_endpoint, nomad_job)
|
3
|
+
def initialize(nomad_endpoint, nomad_job, opts = {})
|
4
4
|
@nomad_job = nomad_job
|
5
5
|
@evaluation_id = nil
|
6
6
|
@deployment_id = nil
|
7
7
|
@timeout = Time.now.utc + 60 * 9 # minutes
|
8
8
|
@nomad_endpoint = nomad_endpoint
|
9
9
|
@http = Nomade::Http.new(@nomad_endpoint)
|
10
|
+
@logger = opts.fetch(:logger, Nomade.logger)
|
10
11
|
end
|
11
12
|
|
12
13
|
def deploy!
|
13
14
|
deploy
|
14
15
|
rescue Nomade::NoModificationsError => e
|
15
|
-
|
16
|
+
@logger.warn "No modifications to make, exiting!"
|
16
17
|
exit(0)
|
17
18
|
rescue Nomade::GeneralError => e
|
18
|
-
|
19
|
-
|
19
|
+
@logger.warn e.message
|
20
|
+
@logger.warn "GeneralError hit, exiting!"
|
20
21
|
exit(1)
|
21
22
|
rescue Nomade::PlanningError => e
|
22
|
-
|
23
|
+
@logger.warn "Couldn't make a plan, maybe a bad connection to Nomad server, exiting!"
|
23
24
|
exit(2)
|
24
25
|
rescue Nomade::AllocationFailedError => e
|
25
|
-
|
26
|
+
@logger.warn "Allocation failed with errors, exiting!"
|
26
27
|
exit(3)
|
27
28
|
rescue Nomade::UnsupportedDeploymentMode => e
|
28
|
-
|
29
|
-
|
29
|
+
@logger.warn e.message
|
30
|
+
@logger.warn "Deployment failed with errors, exiting!"
|
30
31
|
exit(4)
|
31
32
|
end
|
32
33
|
|
33
34
|
private
|
34
35
|
|
35
36
|
def deploy
|
36
|
-
|
37
|
-
|
37
|
+
@logger.info "Deploying #{@nomad_job.job_name} (#{@nomad_job.job_type}) with #{@nomad_job.image_name_and_version}"
|
38
|
+
@logger.info "URL: #{@nomad_endpoint}/ui/jobs/#{@nomad_job.job_name}"
|
38
39
|
|
39
|
-
|
40
|
+
@logger.info "Checking cluster for connectivity and capacity.."
|
40
41
|
@http.plan_job(@nomad_job)
|
41
42
|
|
42
43
|
@evaluation_id = if @http.check_if_job_exists?(@nomad_job)
|
43
|
-
|
44
|
+
@logger.info "Updating existing job"
|
44
45
|
@http.update_job(@nomad_job)
|
45
46
|
else
|
46
|
-
|
47
|
+
@logger.info "Creating new job"
|
47
48
|
@http.create_job(@nomad_job)
|
48
49
|
end
|
49
50
|
|
50
|
-
|
51
|
-
|
51
|
+
@logger.info "EvaluationID: #{@evaluation_id}"
|
52
|
+
@logger.info "#{@evaluation_id} Waiting until evaluation is complete"
|
52
53
|
eval_status = nil
|
53
54
|
while(eval_status != "complete") do
|
54
55
|
evaluation = @http.evaluation_request(@evaluation_id)
|
55
56
|
@deployment_id ||= evaluation["DeploymentID"]
|
56
57
|
eval_status = evaluation["Status"]
|
57
|
-
|
58
|
+
@logger.info "."
|
58
59
|
sleep(1)
|
59
60
|
end
|
60
61
|
|
61
|
-
|
62
|
+
@logger.info "Waiting until allocations are complete"
|
62
63
|
case @nomad_job.job_type
|
63
64
|
when "service"
|
64
65
|
service_deploy
|
@@ -72,28 +73,28 @@ module Nomade
|
|
72
73
|
allocation["TaskStates"].sort.each do |task_name, task_data|
|
73
74
|
pretty_state = Nomade::Decorator.task_state_decorator(task_data["State"], task_data["Failed"])
|
74
75
|
|
75
|
-
|
76
|
-
|
76
|
+
@logger.info ""
|
77
|
+
@logger.info "#{allocation["ID"]} #{allocation["Name"]} #{task_name}: #{pretty_state}"
|
77
78
|
unless task_data["Failed"]
|
78
|
-
|
79
|
+
@logger.info "Task \"#{task_name}\" was succesfully run, skipping log-printing because it isn't relevant!"
|
79
80
|
next
|
80
81
|
end
|
81
82
|
|
82
83
|
stdout = @http.get_allocation_logs(allocation["ID"], task_name, "stdout")
|
83
84
|
if stdout != ""
|
84
|
-
|
85
|
-
|
85
|
+
@logger.info
|
86
|
+
@logger.info "stdout:"
|
86
87
|
stdout.lines do |logline|
|
87
|
-
|
88
|
+
@logger.info(logline.strip)
|
88
89
|
end
|
89
90
|
end
|
90
91
|
|
91
92
|
stderr = @http.get_allocation_logs(allocation["ID"], task_name, "stderr")
|
92
93
|
if stderr != ""
|
93
|
-
|
94
|
-
|
94
|
+
@logger.info
|
95
|
+
@logger.info "stderr:"
|
95
96
|
stderr.lines do |logline|
|
96
|
-
|
97
|
+
@logger.info(logline.strip)
|
97
98
|
end
|
98
99
|
end
|
99
100
|
|
@@ -107,7 +108,7 @@ module Nomade
|
|
107
108
|
"(#{dts})"
|
108
109
|
end
|
109
110
|
|
110
|
-
|
111
|
+
@logger.info "[#{event_time}] #{event_type}: #{event_message} #{event_details}"
|
111
112
|
end
|
112
113
|
end
|
113
114
|
end
|
@@ -116,21 +117,21 @@ module Nomade
|
|
116
117
|
end
|
117
118
|
|
118
119
|
def service_deploy
|
119
|
-
|
120
|
-
|
120
|
+
@logger.info "Waiting until tasks are placed"
|
121
|
+
@logger.info ".. deploy timeout is #{@timeout}"
|
121
122
|
|
122
123
|
json = @http.deployment_request(@deployment_id)
|
123
|
-
|
124
|
+
@logger.info "#{json["JobID"]} version #{json["JobVersion"]}"
|
124
125
|
|
125
126
|
need_manual_promotion = json["TaskGroups"].values.any?{|tg| tg["DesiredCanaries"] > 0 && tg["AutoPromote"] == false}
|
126
127
|
need_manual_rollback = json["TaskGroups"].values.any?{|tg| tg["DesiredCanaries"] > 0 && tg["AutoRevert"] == false}
|
127
128
|
|
128
129
|
manual_work_required = case [need_manual_promotion, need_manual_rollback]
|
129
130
|
when [true, true]
|
130
|
-
|
131
|
+
@logger.info "Job needs manual promotion/rollback, we'll take care of that!"
|
131
132
|
true
|
132
133
|
when [false, false]
|
133
|
-
|
134
|
+
@logger.info "Job manages its own promotion/rollback, we will just monitor in a hands-off mode!"
|
134
135
|
false
|
135
136
|
when [false, true]
|
136
137
|
raise UnsupportedDeploymentMode.new("Unsupported deployment-mode, manual-promotion=#{need_manual_promotion}, manual-rollback=#{need_manual_rollback}")
|
@@ -155,37 +156,41 @@ module Nomade
|
|
155
156
|
unhealthy_allocations = task_data["UnhealthyAllocs"]
|
156
157
|
|
157
158
|
if manual_work_required
|
158
|
-
|
159
|
+
@logger.info "#{json["ID"]} #{task_name}: #{healthy_allocations}/#{desired_canaries}/#{desired_total} (Healthy/WantedCanaries/Total)"
|
159
160
|
announced_completed << task_name if healthy_allocations == desired_canaries
|
160
161
|
else
|
161
|
-
|
162
|
+
@logger.info "#{json["ID"]} #{task_name}: #{healthy_allocations}/#{desired_total} (Healthy/Total)"
|
162
163
|
announced_completed << task_name if healthy_allocations == desired_total
|
163
164
|
end
|
164
165
|
end
|
165
166
|
|
166
167
|
if manual_work_required
|
167
168
|
if json["Status"] == "failed"
|
168
|
-
|
169
|
+
@logger.info "#{json["Status"]}: #{json["StatusDescription"]}"
|
169
170
|
succesful_deployment = false
|
170
171
|
end
|
171
172
|
|
172
173
|
if succesful_deployment == nil && Time.now.utc > @timeout
|
173
|
-
|
174
|
+
@logger.info "Timeout hit, rolling back deploy!"
|
174
175
|
@http.fail_deployment(@deployment_id)
|
175
176
|
succesful_deployment = false
|
176
177
|
end
|
177
178
|
|
178
179
|
if succesful_deployment == nil && json["TaskGroups"].values.all?{|tg| tg["HealthyAllocs"] >= tg["DesiredCanaries"]}
|
179
180
|
if !promoted
|
180
|
-
|
181
|
+
random_linger = rand(60..185)
|
182
|
+
@logger.info "Lingering around for #{random_linger} seconds before deployment.."
|
183
|
+
sleep(random_linger)
|
184
|
+
|
185
|
+
@logger.info "Promoting #{@deployment_id} (version #{json["JobVersion"]})"
|
181
186
|
@http.promote_deployment(@deployment_id)
|
182
187
|
promoted = true
|
183
|
-
|
188
|
+
@logger.info ".. promoted!"
|
184
189
|
else
|
185
190
|
if json["Status"] == "successful"
|
186
191
|
succesful_deployment = true
|
187
192
|
else
|
188
|
-
|
193
|
+
@logger.info "Waiting for promotion to complete #{@deployment_id} (version #{json["JobVersion"]})"
|
189
194
|
end
|
190
195
|
end
|
191
196
|
end
|
@@ -194,10 +199,10 @@ module Nomade
|
|
194
199
|
when "running"
|
195
200
|
# no-op
|
196
201
|
when "failed"
|
197
|
-
|
202
|
+
@logger.info "#{json["Status"]}: #{json["StatusDescription"]}"
|
198
203
|
succesful_deployment = false
|
199
204
|
when "successful"
|
200
|
-
|
205
|
+
@logger.info "#{json["Status"]}: #{json["StatusDescription"]}"
|
201
206
|
succesful_deployment = true
|
202
207
|
end
|
203
208
|
end
|
@@ -206,11 +211,11 @@ module Nomade
|
|
206
211
|
end
|
207
212
|
|
208
213
|
if succesful_deployment
|
209
|
-
|
210
|
-
|
214
|
+
@logger.info ""
|
215
|
+
@logger.info "#{@deployment_id} (version #{json["JobVersion"]}) was succesfully deployed!"
|
211
216
|
else
|
212
|
-
|
213
|
-
|
217
|
+
@logger.warn ""
|
218
|
+
@logger.warn "#{@deployment_id} (version #{json["JobVersion"]}) deployment _failed_!"
|
214
219
|
end
|
215
220
|
end
|
216
221
|
|
@@ -227,7 +232,7 @@ module Nomade
|
|
227
232
|
pretty_state = Nomade::Decorator.task_state_decorator(task_data["State"], task_data["Failed"])
|
228
233
|
|
229
234
|
unless announced_dead.include?(full_task_address)
|
230
|
-
|
235
|
+
@logger.info "#{allocation["ID"]} #{allocation["Name"]} #{task_name}: #{pretty_state}"
|
231
236
|
|
232
237
|
if task_data["State"] == "dead"
|
233
238
|
announced_dead << full_task_address
|
@@ -246,30 +251,30 @@ module Nomade
|
|
246
251
|
raise Nomade::AllocationFailedError.new(@evaluation_id, allocations)
|
247
252
|
end
|
248
253
|
|
249
|
-
|
254
|
+
@logger.info "Deployment complete"
|
250
255
|
|
251
256
|
allocations.each do |allocation|
|
252
257
|
allocation["TaskStates"].sort.each do |task_name, task_data|
|
253
258
|
pretty_state = Nomade::Decorator.task_state_decorator(task_data["State"], task_data["Failed"])
|
254
259
|
|
255
|
-
|
256
|
-
|
260
|
+
@logger.info ""
|
261
|
+
@logger.info "#{allocation["ID"]} #{allocation["Name"]} #{task_name}: #{pretty_state}"
|
257
262
|
|
258
263
|
stdout = @http.get_allocation_logs(allocation["ID"], task_name, "stdout")
|
259
264
|
if stdout != ""
|
260
|
-
|
261
|
-
|
265
|
+
@logger.info
|
266
|
+
@logger.info "stdout:"
|
262
267
|
stdout.lines do |logline|
|
263
|
-
|
268
|
+
@logger.info(logline.strip)
|
264
269
|
end
|
265
270
|
end
|
266
271
|
|
267
272
|
stderr = @http.get_allocation_logs(allocation["ID"], task_name, "stderr")
|
268
273
|
if stderr != ""
|
269
|
-
|
270
|
-
|
274
|
+
@logger.info
|
275
|
+
@logger.info "stderr:"
|
271
276
|
stderr.lines do |logline|
|
272
|
-
|
277
|
+
@logger.info(logline.strip)
|
273
278
|
end
|
274
279
|
end
|
275
280
|
end
|
data/lib/nomade/http.rb
CHANGED
@@ -16,8 +16,10 @@ module Nomade
|
|
16
16
|
uri = URI("#{@nomad_endpoint}/v1/jobs#{search_prefix}")
|
17
17
|
|
18
18
|
http = Net::HTTP.new(uri.host, uri.port)
|
19
|
-
|
20
|
-
|
19
|
+
if @nomad_endpoint.include?("https://")
|
20
|
+
http.use_ssl = true
|
21
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
22
|
+
end
|
21
23
|
|
22
24
|
req = Net::HTTP::Get.new(uri)
|
23
25
|
req.add_field "Content-Type", "application/json"
|
@@ -37,8 +39,10 @@ module Nomade
|
|
37
39
|
uri = URI("#{@nomad_endpoint}/v1/evaluation/#{evaluation_id}")
|
38
40
|
|
39
41
|
http = Net::HTTP.new(uri.host, uri.port)
|
40
|
-
|
41
|
-
|
42
|
+
if @nomad_endpoint.include?("https://")
|
43
|
+
http.use_ssl = true
|
44
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
45
|
+
end
|
42
46
|
|
43
47
|
req = Net::HTTP::Get.new(uri)
|
44
48
|
req.add_field "Content-Type", "application/json"
|
@@ -58,8 +62,10 @@ module Nomade
|
|
58
62
|
uri = URI("#{@nomad_endpoint}/v1/evaluation/#{evaluation_id}/allocations")
|
59
63
|
|
60
64
|
http = Net::HTTP.new(uri.host, uri.port)
|
61
|
-
|
62
|
-
|
65
|
+
if @nomad_endpoint.include?("https://")
|
66
|
+
http.use_ssl = true
|
67
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
68
|
+
end
|
63
69
|
|
64
70
|
req = Net::HTTP::Get.new(uri)
|
65
71
|
req.add_field "Content-Type", "application/json"
|
@@ -79,8 +85,10 @@ module Nomade
|
|
79
85
|
uri = URI("#{@nomad_endpoint}/v1/deployment/#{deployment_id}")
|
80
86
|
|
81
87
|
http = Net::HTTP.new(uri.host, uri.port)
|
82
|
-
|
83
|
-
|
88
|
+
if @nomad_endpoint.include?("https://")
|
89
|
+
http.use_ssl = true
|
90
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
91
|
+
end
|
84
92
|
|
85
93
|
req = Net::HTTP::Get.new(uri)
|
86
94
|
req.add_field "Content-Type", "application/json"
|
@@ -105,8 +113,10 @@ module Nomade
|
|
105
113
|
uri = URI("#{@nomad_endpoint}/v1/jobs")
|
106
114
|
|
107
115
|
http = Net::HTTP.new(uri.host, uri.port)
|
108
|
-
|
109
|
-
|
116
|
+
if @nomad_endpoint.include?("https://")
|
117
|
+
http.use_ssl = true
|
118
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
119
|
+
end
|
110
120
|
|
111
121
|
req = Net::HTTP::Post.new(uri)
|
112
122
|
req.add_field "Content-Type", "application/json"
|
@@ -126,8 +136,10 @@ module Nomade
|
|
126
136
|
uri = URI("#{@nomad_endpoint}/v1/job/#{nomad_job.job_name}")
|
127
137
|
|
128
138
|
http = Net::HTTP.new(uri.host, uri.port)
|
129
|
-
|
130
|
-
|
139
|
+
if @nomad_endpoint.include?("https://")
|
140
|
+
http.use_ssl = true
|
141
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
142
|
+
end
|
131
143
|
|
132
144
|
req = Net::HTTP::Post.new(uri)
|
133
145
|
req.add_field "Content-Type", "application/json"
|
@@ -147,8 +159,10 @@ module Nomade
|
|
147
159
|
uri = URI("#{@nomad_endpoint}/v1/deployment/promote/#{deployment_id}")
|
148
160
|
|
149
161
|
http = Net::HTTP.new(uri.host, uri.port)
|
150
|
-
|
151
|
-
|
162
|
+
if @nomad_endpoint.include?("https://")
|
163
|
+
http.use_ssl = true
|
164
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
165
|
+
end
|
152
166
|
|
153
167
|
req = Net::HTTP::Post.new(uri)
|
154
168
|
req.add_field "Content-Type", "application/json"
|
@@ -171,8 +185,10 @@ module Nomade
|
|
171
185
|
uri = URI("#{@nomad_endpoint}/v1/deployment/fail/#{deployment_id}")
|
172
186
|
|
173
187
|
http = Net::HTTP.new(uri.host, uri.port)
|
174
|
-
|
175
|
-
|
188
|
+
if @nomad_endpoint.include?("https://")
|
189
|
+
http.use_ssl = true
|
190
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
191
|
+
end
|
176
192
|
|
177
193
|
req = Net::HTTP::Post.new(uri)
|
178
194
|
req.add_field "Content-Type", "application/json"
|
@@ -191,8 +207,10 @@ module Nomade
|
|
191
207
|
uri = URI("#{@nomad_endpoint}/v1/client/fs/logs/#{allocation_id}?task=#{task_name}&type=#{logtype}&plain=true&origin=end")
|
192
208
|
|
193
209
|
http = Net::HTTP.new(uri.host, uri.port)
|
194
|
-
|
195
|
-
|
210
|
+
if @nomad_endpoint.include?("https://")
|
211
|
+
http.use_ssl = true
|
212
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
213
|
+
end
|
196
214
|
|
197
215
|
req = Net::HTTP::Get.new(uri)
|
198
216
|
res = http.request(req)
|
data/lib/nomade/job.rb
CHANGED
@@ -5,14 +5,15 @@ module Nomade
|
|
5
5
|
class Job
|
6
6
|
class FormattingError < StandardError; end
|
7
7
|
|
8
|
-
def initialize(template_file, image_full_name,
|
8
|
+
def initialize(template_file, image_full_name, template_variables = {})
|
9
9
|
@image_full_name = image_full_name
|
10
|
-
@
|
10
|
+
@template_variables = template_variables
|
11
11
|
|
12
12
|
# image_full_name should be in the form of:
|
13
13
|
# redis:4.0.1
|
14
14
|
# kaspergrubbe/secretimage:latest
|
15
|
-
|
15
|
+
# billetto/billetto-rails:4.2.24
|
16
|
+
unless @image_full_name.match(/\A[a-zA-Z0-9\/\-\_]+\:[a-zA-Z0-9\.\-\_]+\z/)
|
16
17
|
raise Nomade::Job::FormattingError.new("Image-format wrong: #{@image_full_name}")
|
17
18
|
end
|
18
19
|
|
@@ -52,8 +53,8 @@ module Nomade
|
|
52
53
|
image_name_and_version.split(":").last
|
53
54
|
end
|
54
55
|
|
55
|
-
def
|
56
|
-
@
|
56
|
+
def template_variables
|
57
|
+
@template_variables
|
57
58
|
end
|
58
59
|
|
59
60
|
private
|
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.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kasper Grubbe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-11-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: yell
|