kubernetes-deploy 0.7.3 → 0.7.4
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/.rubocop.yml +3 -0
- data/README.md +7 -1
- data/Rakefile +1 -1
- data/exe/kubernetes-deploy +1 -1
- data/exe/kubernetes-run +1 -1
- data/kubernetes-deploy.gemspec +2 -2
- data/lib/kubernetes-deploy.rb +2 -0
- data/lib/kubernetes-deploy/deferred_summary_logging.rb +3 -3
- data/lib/kubernetes-deploy/kubernetes_resource.rb +2 -1
- data/lib/kubernetes-deploy/kubernetes_resource/pod.rb +5 -3
- data/lib/kubernetes-deploy/resource_watcher.rb +6 -6
- data/lib/kubernetes-deploy/runner.rb +33 -26
- data/lib/kubernetes-deploy/runner_task.rb +2 -5
- data/lib/kubernetes-deploy/version.rb +1 -1
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 255ea8b3ecd484e3867da8b34b4a61a927d99c1f
|
4
|
+
data.tar.gz: 79c4034b3460995f65fbeb54216688a5b1f448b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8c9b9c54dea86318add19d23123e00ec5f3195488ec0ecbf954cdfe126dd1ca780d2c7cea6687342f2df8410ef7c5a53fd8b3ebb0649b6e8488fb1f2be42f0ef
|
7
|
+
data.tar.gz: a2cc7698a3b9f9b66bf8a54b7c5ac2483946760cdb52612c8b73fbc3c57ad8f716e8cedb4e1a732ecda59a82f37815de4ba41eb212a1e75399bd461b06061ebc
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -123,7 +123,13 @@ To run the tests:
|
|
123
123
|
* Make sure you have a context named "minikube" in your kubeconfig. Minikube adds this context for you when you run `minikube start`; please do not rename it. You can check for it using `kubectl config get-contexts`.
|
124
124
|
* Run `bundle exec rake test`
|
125
125
|
|
126
|
-
To install this gem onto your local machine, run `bundle exec rake install`.
|
126
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
127
|
+
|
128
|
+
To release a new version:
|
129
|
+
|
130
|
+
* Update the version number in `version.rb`
|
131
|
+
* Tag the version with `git tag vx.y.z && git push --tags`
|
132
|
+
* A Shopify employee can use the [Shipit Stack](https://shipit.shopify.io/shopify/kubernetes-deploy/rubygems) to build the `.gem` file and upload to [rubygems.org](https://rubygems.org/gems/kubernetes-deploy).
|
127
133
|
|
128
134
|
## CI
|
129
135
|
|
data/Rakefile
CHANGED
data/exe/kubernetes-deploy
CHANGED
@@ -15,7 +15,7 @@ verbose_log_prefix = false
|
|
15
15
|
ARGV.options do |opts|
|
16
16
|
opts.on("--bindings=BINDINGS", Array, "k1=v1,k2=v2") do |binds|
|
17
17
|
bindings = binds.each_with_object({}) do |bind, acc|
|
18
|
-
k,v = bind.split('=')
|
18
|
+
k, v = bind.split('=')
|
19
19
|
raise "key for value #{v} is blank!" if k.blank?
|
20
20
|
raise "value for key #{k} is blank!" if v.blank?
|
21
21
|
acc[k] = v
|
data/exe/kubernetes-run
CHANGED
@@ -11,7 +11,7 @@ env_vars = []
|
|
11
11
|
|
12
12
|
ARGV.options do |opts|
|
13
13
|
opts.on("--template=TEMPLATE") { |n| template = n }
|
14
|
-
opts.on("--env-vars=ENV_VARS") { |vars| env_vars =
|
14
|
+
opts.on("--env-vars=ENV_VARS") { |vars| env_vars = vars.split(",") }
|
15
15
|
opts.on("--entrypoint=ENTRYPOINT") { |c| entrypoint = [c] }
|
16
16
|
opts.parse!
|
17
17
|
end
|
data/kubernetes-deploy.gemspec
CHANGED
@@ -6,10 +6,10 @@ require 'kubernetes-deploy/version'
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "kubernetes-deploy"
|
8
8
|
spec.version = KubernetesDeploy::VERSION
|
9
|
-
spec.authors = ["
|
9
|
+
spec.authors = ["Katrina Verey", "Kir Shatrov"]
|
10
10
|
spec.email = ["ops-accounts+shipit@shopify.com"]
|
11
11
|
|
12
|
-
spec.summary =
|
12
|
+
spec.summary = 'Kubernetes deploy scripts'
|
13
13
|
spec.description = spec.summary
|
14
14
|
spec.homepage = "https://github.com/Shopify/kubernetes-deploy"
|
15
15
|
spec.license = "MIT"
|
data/lib/kubernetes-deploy.rb
CHANGED
@@ -23,12 +23,12 @@ module KubernetesDeploy
|
|
23
23
|
heading("Phase #{@current_phase}: #{phase_name}")
|
24
24
|
end
|
25
25
|
|
26
|
-
def heading(text, secondary_msg = '', secondary_msg_color = :
|
26
|
+
def heading(text, secondary_msg = '', secondary_msg_color = :cyan)
|
27
27
|
padding = (100.0 - (text.length + secondary_msg.length)) / 2
|
28
28
|
blank_line
|
29
|
-
part1 = ColorizedString.new("#{'-' * padding.floor}#{text}").
|
29
|
+
part1 = ColorizedString.new("#{'-' * padding.floor}#{text}").cyan
|
30
30
|
part2 = ColorizedString.new(secondary_msg).colorize(secondary_msg_color)
|
31
|
-
part3 = ColorizedString.new('-' * padding.ceil).
|
31
|
+
part3 = ColorizedString.new('-' * padding.ceil).cyan
|
32
32
|
info(part1 + part2 + part3)
|
33
33
|
end
|
34
34
|
|
@@ -10,6 +10,7 @@ module KubernetesDeploy
|
|
10
10
|
attr_writer :type, :deploy_started
|
11
11
|
|
12
12
|
TIMEOUT = 5.minutes
|
13
|
+
LOG_LINE_COUNT = 250
|
13
14
|
|
14
15
|
DEBUG_RESOURCE_NOT_FOUND_MESSAGE = "None found. Please check your usual logging service (e.g. Splunk)."
|
15
16
|
UNUSUAL_FAILURE_MESSAGE = <<-MSG.strip_heredoc
|
@@ -138,7 +139,7 @@ module KubernetesDeploy
|
|
138
139
|
if container_logs.blank? || container_logs.values.all?(&:blank?)
|
139
140
|
helpful_info << " - Logs: #{DEBUG_RESOURCE_NOT_FOUND_MESSAGE}"
|
140
141
|
else
|
141
|
-
helpful_info << " - Logs:"
|
142
|
+
helpful_info << " - Logs (last #{LOG_LINE_COUNT} lines shown):"
|
142
143
|
container_logs.each do |identifier, logs|
|
143
144
|
logs.split("\n").each do |line|
|
144
145
|
helpful_info << " [#{identifier}]\t#{line}"
|
@@ -75,12 +75,14 @@ module KubernetesDeploy
|
|
75
75
|
return {} unless exists? && @containers.present?
|
76
76
|
|
77
77
|
@containers.each_with_object({}) do |container_name, container_logs|
|
78
|
-
|
78
|
+
cmd = [
|
79
79
|
"logs",
|
80
80
|
@name,
|
81
81
|
"--container=#{container_name}",
|
82
|
-
"--since-time=#{@deploy_started.to_datetime.rfc3339}"
|
83
|
-
|
82
|
+
"--since-time=#{@deploy_started.to_datetime.rfc3339}",
|
83
|
+
]
|
84
|
+
cmd << "--tail=#{LOG_LINE_COUNT}" unless unmanaged?
|
85
|
+
out, _err, _st = kubectl.run(*cmd)
|
84
86
|
container_logs["#{id}/#{container_name}"] = out
|
85
87
|
end
|
86
88
|
end
|
@@ -1,25 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module KubernetesDeploy
|
3
3
|
class ResourceWatcher
|
4
|
-
def initialize(resources, logger:)
|
4
|
+
def initialize(resources, logger:, deploy_started_at: Time.now.utc)
|
5
5
|
unless resources.is_a?(Enumerable)
|
6
|
-
raise ArgumentError, <<-MSG.
|
7
|
-
ResourceWatcher expects Enumerable collection, got `#{resources.class}` instead
|
8
|
-
MSG
|
6
|
+
raise ArgumentError, <<-MSG.strip_heredoc
|
7
|
+
ResourceWatcher expects Enumerable collection, got `#{resources.class}` instead
|
8
|
+
MSG
|
9
9
|
end
|
10
10
|
@resources = resources
|
11
11
|
@logger = logger
|
12
|
+
@deploy_started_at = deploy_started_at
|
12
13
|
end
|
13
14
|
|
14
15
|
def run(delay_sync: 3.seconds)
|
15
16
|
delay_sync_until = Time.now.utc
|
16
|
-
started_at = delay_sync_until
|
17
17
|
|
18
18
|
while @resources.present?
|
19
19
|
if Time.now.utc < delay_sync_until
|
20
20
|
sleep(delay_sync_until - Time.now.utc)
|
21
21
|
end
|
22
|
-
watch_time = (Time.now.utc -
|
22
|
+
watch_time = (Time.now.utc - @deploy_started_at).round(1)
|
23
23
|
delay_sync_until = Time.now.utc + delay_sync # don't pummel the API if the sync is fast
|
24
24
|
@resources.each(&:sync)
|
25
25
|
newly_finished_resources, @resources = @resources.partition(&:deploy_finished?)
|
@@ -111,21 +111,20 @@ module KubernetesDeploy
|
|
111
111
|
raise FatalDeploymentError, "Refusing to deploy to protected namespace '#{@namespace}' with pruning enabled"
|
112
112
|
end
|
113
113
|
|
114
|
-
|
115
|
-
|
116
|
-
|
114
|
+
if verify_result
|
115
|
+
deploy_resources(resources, prune: prune, verify: true)
|
116
|
+
record_statuses(resources)
|
117
|
+
success = resources.all?(&:deploy_succeeded?)
|
118
|
+
else
|
119
|
+
deploy_resources(resources, prune: prune, verify: false)
|
117
120
|
@logger.summary.add_action("deployed #{resources.length} #{'resource'.pluralize(resources.length)}")
|
118
121
|
warning = <<-MSG.strip_heredoc
|
119
122
|
Deploy result verification is disabled for this deploy.
|
120
123
|
This means the desired changes were communicated to Kubernetes, but the deploy did not make sure they actually succeeded.
|
121
124
|
MSG
|
122
125
|
@logger.summary.add_paragraph(ColorizedString.new(warning).yellow)
|
123
|
-
|
126
|
+
success = true
|
124
127
|
end
|
125
|
-
|
126
|
-
wait_for_completion(resources)
|
127
|
-
record_statuses(resources)
|
128
|
-
success = resources.all?(&:deploy_succeeded?)
|
129
128
|
rescue FatalDeploymentError => error
|
130
129
|
@logger.summary.add_action(error.message)
|
131
130
|
success = false
|
@@ -200,8 +199,7 @@ module KubernetesDeploy
|
|
200
199
|
PREDEPLOY_SEQUENCE.each do |resource_type|
|
201
200
|
matching_resources = resource_list.select { |r| r.type == resource_type }
|
202
201
|
next if matching_resources.empty?
|
203
|
-
deploy_resources(matching_resources)
|
204
|
-
wait_for_completion(matching_resources)
|
202
|
+
deploy_resources(matching_resources, verify: true)
|
205
203
|
|
206
204
|
failed_resources = matching_resources.reject(&:deploy_succeeded?)
|
207
205
|
fail_count = failed_resources.length
|
@@ -297,8 +295,8 @@ module KubernetesDeploy
|
|
297
295
|
@logger.summary.add_paragraph(debug_msg)
|
298
296
|
end
|
299
297
|
|
300
|
-
def wait_for_completion(watched_resources)
|
301
|
-
watcher = ResourceWatcher.new(watched_resources, logger: @logger)
|
298
|
+
def wait_for_completion(watched_resources, started_at)
|
299
|
+
watcher = ResourceWatcher.new(watched_resources, logger: @logger, deploy_started_at: started_at)
|
302
300
|
watcher.run
|
303
301
|
end
|
304
302
|
|
@@ -359,37 +357,46 @@ module KubernetesDeploy
|
|
359
357
|
@logger.info("All required parameters and files are present")
|
360
358
|
end
|
361
359
|
|
362
|
-
def deploy_resources(resources, prune: false)
|
363
|
-
|
360
|
+
def deploy_resources(resources, prune: false, verify:)
|
361
|
+
return if resources.empty?
|
362
|
+
deploy_started_at = Time.now.utc
|
363
|
+
|
364
|
+
if resources.length > 1
|
365
|
+
@logger.info("Deploying resources:")
|
366
|
+
else
|
367
|
+
resource = resources.first
|
368
|
+
@logger.info("Deploying #{resource.id} (timeout: #{resource.timeout}s)")
|
369
|
+
end
|
364
370
|
|
365
371
|
# Apply can be done in one large batch, the rest have to be done individually
|
366
372
|
applyables, individuals = resources.partition { |r| r.deploy_method == :apply }
|
367
373
|
|
368
374
|
individuals.each do |r|
|
369
|
-
@logger.info("- #{r.id}")
|
375
|
+
@logger.info("- #{r.id} (timeout: #{r.timeout}s)") if resources.length > 1
|
370
376
|
r.deploy_started = Time.now.utc
|
371
377
|
case r.deploy_method
|
372
378
|
when :replace
|
373
|
-
_, _,
|
379
|
+
_, _, replace_st = kubectl.run("replace", "-f", r.file.path, log_failure: false)
|
374
380
|
when :replace_force
|
375
|
-
_, _,
|
381
|
+
_, _, replace_st = kubectl.run("replace", "--force", "-f", r.file.path, log_failure: false)
|
376
382
|
else
|
377
383
|
# Fail Fast! This is a programmer mistake.
|
378
384
|
raise ArgumentError, "Unexpected deploy method! (#{r.deploy_method.inspect})"
|
379
385
|
end
|
380
386
|
|
381
|
-
next if
|
387
|
+
next if replace_st.success?
|
382
388
|
# it doesn't exist so we can't replace it
|
383
|
-
_, err,
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
389
|
+
_, err, create_st = kubectl.run("create", "-f", r.file.path, log_failure: false)
|
390
|
+
|
391
|
+
next if create_st.success?
|
392
|
+
raise FatalDeploymentError, <<-MSG.strip_heredoc
|
393
|
+
Failed to replace or create resource: #{r.id}
|
394
|
+
#{err}
|
395
|
+
MSG
|
390
396
|
end
|
391
397
|
|
392
398
|
apply_all(applyables, prune)
|
399
|
+
wait_for_completion(resources, deploy_started_at) if verify
|
393
400
|
end
|
394
401
|
|
395
402
|
def apply_all(resources, prune)
|
@@ -397,7 +404,7 @@ module KubernetesDeploy
|
|
397
404
|
|
398
405
|
command = ["apply"]
|
399
406
|
resources.each do |r|
|
400
|
-
@logger.info("- #{r.id} (timeout: #{r.timeout}s)")
|
407
|
+
@logger.info("- #{r.id} (timeout: #{r.timeout}s)") if resources.length > 1
|
401
408
|
command.push("-f", r.file.path)
|
402
409
|
r.deploy_started = Time.now.utc
|
403
410
|
end
|
@@ -68,11 +68,8 @@ module KubernetesDeploy
|
|
68
68
|
begin
|
69
69
|
@kubeclient.get_namespace(@namespace) if @namespace.present?
|
70
70
|
rescue KubeException => e
|
71
|
-
|
72
|
-
|
73
|
-
else
|
74
|
-
"Could not connect to kubernetes cluster"
|
75
|
-
end
|
71
|
+
msg = e.error_code == 404 ? "Namespace was not found" : "Could not connect to kubernetes cluster"
|
72
|
+
errors << msg
|
76
73
|
end
|
77
74
|
|
78
75
|
raise FatalTaskRunError, "Configuration invalid: #{errors.join(', ')}" unless errors.empty?
|
metadata
CHANGED
@@ -1,16 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kubernetes-deploy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
- Kir Shatrov
|
8
|
-
- Jean Boussier
|
9
7
|
- Katrina Verey
|
8
|
+
- Kir Shatrov
|
10
9
|
autorequire:
|
11
10
|
bindir: exe
|
12
11
|
cert_chain: []
|
13
|
-
date: 2017-06-
|
12
|
+
date: 2017-06-05 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: activesupport
|