nomade 0.0.2 → 0.0.3
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 +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
|