kubernetes-deploy 0.3.3 → 0.3.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/lib/kubernetes-deploy.rb +6 -5
- data/lib/kubernetes-deploy/kubernetes_resource.rb +3 -3
- data/lib/kubernetes-deploy/kubernetes_resource/cloudsql.rb +6 -2
- data/lib/kubernetes-deploy/kubernetes_resource/config_map.rb +5 -1
- data/lib/kubernetes-deploy/kubernetes_resource/deployment.rb +7 -2
- data/lib/kubernetes-deploy/kubernetes_resource/ingress.rb +5 -1
- data/lib/kubernetes-deploy/kubernetes_resource/persistent_volume_claim.rb +5 -1
- data/lib/kubernetes-deploy/kubernetes_resource/pod.rb +10 -6
- data/lib/kubernetes-deploy/kubernetes_resource/redis.rb +7 -3
- data/lib/kubernetes-deploy/kubernetes_resource/service.rb +5 -1
- data/lib/kubernetes-deploy/runner.rb +14 -13
- data/lib/kubernetes-deploy/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 243574658a49fa135a24916b5ab9144d1350e3a5
|
4
|
+
data.tar.gz: 8ac19f9d603838a2791da5bfe1c58222a4d082c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 357d21eb05b6f7ae579db5ab5749ff5dc5eac8e3d6e682735e8dfbdef3ec9e5fa1c6324ac68f9fc0b50a7d125bf5d7297549ac001f70f204b92dc4560d1c5b12
|
7
|
+
data.tar.gz: 88e3506ab13ecbe080b155ecaf0bd825de3987235ab2fb62058b420ba722c299c5a12060d4ada535740cd6b40bcaf0cf969c927829a4e971a0eb30f4262d3143
|
data/lib/kubernetes-deploy.rb
CHANGED
@@ -17,12 +17,13 @@ module KubernetesDeploy
|
|
17
17
|
@logger ||= begin
|
18
18
|
l = Logger.new($stderr)
|
19
19
|
l.level = level_from_env
|
20
|
-
l.formatter = proc do |severity,
|
20
|
+
l.formatter = proc do |severity, datetime, _progname, msg|
|
21
|
+
log_text = "[#{severity}][#{datetime}]\t#{msg}"
|
21
22
|
case severity
|
22
|
-
when "FATAL"
|
23
|
-
when "WARN" then "\033[0;33m
|
24
|
-
when "INFO" then "\033[0;36m#{
|
25
|
-
else "
|
23
|
+
when "FATAL" then "\033[0;31m#{log_text}\x1b[0m\n" # red
|
24
|
+
when "ERROR", "WARN" then "\033[0;33m#{log_text}\x1b[0m\n" # yellow
|
25
|
+
when "INFO" then "\033[0;36m#{log_text}\x1b[0m\n" # blue
|
26
|
+
else "#{log_text}\n"
|
26
27
|
end
|
27
28
|
end
|
28
29
|
l
|
@@ -11,8 +11,8 @@ module KubernetesDeploy
|
|
11
11
|
def self.logger
|
12
12
|
@logger ||= begin
|
13
13
|
l = Logger.new($stderr)
|
14
|
-
l.formatter = proc do |_severity,
|
15
|
-
"#{msg}\n"
|
14
|
+
l.formatter = proc do |_severity, datetime, _progname, msg|
|
15
|
+
"[KUBESTATUS][#{datetime}]\t#{msg}\n"
|
16
16
|
end
|
17
17
|
l
|
18
18
|
end
|
@@ -125,7 +125,7 @@ module KubernetesDeploy
|
|
125
125
|
end
|
126
126
|
|
127
127
|
def log_status
|
128
|
-
KubernetesResource.logger.info("[
|
128
|
+
KubernetesResource.logger.info("[#{@context}][#{@namespace}] #{JSON.dump(status_data)}")
|
129
129
|
end
|
130
130
|
end
|
131
131
|
end
|
@@ -1,9 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module KubernetesDeploy
|
2
3
|
class Cloudsql < KubernetesResource
|
3
4
|
TIMEOUT = 5.minutes
|
4
5
|
|
5
6
|
def initialize(name, namespace, context, file)
|
6
|
-
@name
|
7
|
+
@name = name
|
8
|
+
@namespace = namespace
|
9
|
+
@context = context
|
10
|
+
@file = file
|
7
11
|
end
|
8
12
|
|
9
13
|
def sync
|
@@ -35,6 +39,7 @@ module KubernetesDeploy
|
|
35
39
|
end
|
36
40
|
|
37
41
|
private
|
42
|
+
|
38
43
|
def cloudsql_proxy_deployment_exists?
|
39
44
|
deployment, st = run_kubectl("get", "deployments", "cloudsql-proxy", "-o=json")
|
40
45
|
|
@@ -64,6 +69,5 @@ module KubernetesDeploy
|
|
64
69
|
|
65
70
|
false
|
66
71
|
end
|
67
|
-
|
68
72
|
end
|
69
73
|
end
|
@@ -1,9 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module KubernetesDeploy
|
2
3
|
class ConfigMap < KubernetesResource
|
3
4
|
TIMEOUT = 30.seconds
|
4
5
|
|
5
6
|
def initialize(name, namespace, context, file)
|
6
|
-
@name
|
7
|
+
@name = name
|
8
|
+
@namespace = namespace
|
9
|
+
@context = context
|
10
|
+
@file = file
|
7
11
|
end
|
8
12
|
|
9
13
|
def sync
|
@@ -1,9 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module KubernetesDeploy
|
2
3
|
class Deployment < KubernetesResource
|
3
4
|
TIMEOUT = 5.minutes
|
4
5
|
|
5
6
|
def initialize(name, namespace, context, file)
|
6
|
-
@name
|
7
|
+
@name = name
|
8
|
+
@namespace = namespace
|
9
|
+
@context = context
|
10
|
+
@file = file
|
7
11
|
end
|
8
12
|
|
9
13
|
def sync
|
@@ -14,7 +18,8 @@ module KubernetesDeploy
|
|
14
18
|
@pods = []
|
15
19
|
|
16
20
|
if @found
|
17
|
-
@rollout_data = JSON.parse(json_data)["status"]
|
21
|
+
@rollout_data = JSON.parse(json_data)["status"]
|
22
|
+
.slice("updatedReplicas", "replicas", "availableReplicas", "unavailableReplicas")
|
18
23
|
@status, _ = run_kubectl("rollout", "status", type, @name, "--watch=false") if @deploy_started
|
19
24
|
|
20
25
|
pod_list, st = run_kubectl("get", "pods", "-a", "-l", "name=#{name}", "--output=json")
|
@@ -1,9 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module KubernetesDeploy
|
2
3
|
class Ingress < KubernetesResource
|
3
4
|
TIMEOUT = 30.seconds
|
4
5
|
|
5
6
|
def initialize(name, namespace, context, file)
|
6
|
-
@name
|
7
|
+
@name = name
|
8
|
+
@namespace = namespace
|
9
|
+
@context = context
|
10
|
+
@file = file
|
7
11
|
end
|
8
12
|
|
9
13
|
def sync
|
@@ -1,9 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module KubernetesDeploy
|
2
3
|
class PersistentVolumeClaim < KubernetesResource
|
3
4
|
TIMEOUT = 5.minutes
|
4
5
|
|
5
6
|
def initialize(name, namespace, context, file)
|
6
|
-
@name
|
7
|
+
@name = name
|
8
|
+
@namespace = namespace
|
9
|
+
@context = context
|
10
|
+
@file = file
|
7
11
|
end
|
8
12
|
|
9
13
|
def sync
|
@@ -1,10 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module KubernetesDeploy
|
2
3
|
class Pod < KubernetesResource
|
3
4
|
TIMEOUT = 10.minutes
|
4
5
|
SUSPICIOUS_CONTAINER_STATES = %w(ImagePullBackOff RunContainerError).freeze
|
5
6
|
|
6
7
|
def initialize(name, namespace, context, file, parent: nil)
|
7
|
-
@name
|
8
|
+
@name = name
|
9
|
+
@namespace = namespace
|
10
|
+
@context = context
|
11
|
+
@file = file
|
12
|
+
@parent = parent
|
8
13
|
@bare = !@parent
|
9
14
|
end
|
10
15
|
|
@@ -18,8 +23,8 @@ module KubernetesDeploy
|
|
18
23
|
@ready = false
|
19
24
|
@containers = []
|
20
25
|
end
|
21
|
-
display_logs if @bare && deploy_finished?
|
22
26
|
log_status
|
27
|
+
display_logs if @bare && deploy_finished?
|
23
28
|
end
|
24
29
|
|
25
30
|
def interpret_json_data(pod_data)
|
@@ -31,12 +36,12 @@ module KubernetesDeploy
|
|
31
36
|
waiting_state = status["state"]["waiting"] if status["state"]
|
32
37
|
reason = waiting_state["reason"] if waiting_state
|
33
38
|
next unless SUSPICIOUS_CONTAINER_STATES.include?(reason)
|
34
|
-
KubernetesDeploy.logger.warn("#{id} has container in state #{reason} (#{waiting_state[
|
39
|
+
KubernetesDeploy.logger.warn("#{id} has container in state #{reason} (#{waiting_state['message']})")
|
35
40
|
end
|
36
41
|
end
|
37
42
|
|
38
43
|
if @phase == "Failed"
|
39
|
-
@status = "#{@phase} (Reason: #{pod_data[
|
44
|
+
@status = "#{@phase} (Reason: #{pod_data['status']['reason']})"
|
40
45
|
elsif @phase == "Terminating"
|
41
46
|
@status = @phase
|
42
47
|
else
|
@@ -75,8 +80,7 @@ module KubernetesDeploy
|
|
75
80
|
out, st = run_kubectl("logs", @name, "--timestamps=true", "--since-time=#{@deploy_started.to_datetime.rfc3339}")
|
76
81
|
next unless st.success? && out.present?
|
77
82
|
|
78
|
-
KubernetesDeploy.logger.info "Logs from #{id} container #{container_name}
|
79
|
-
KubernetesResource.logger.info(out)
|
83
|
+
KubernetesDeploy.logger.info "Logs from #{id} container #{container_name}:\x1b[0m \n#{out}\n"
|
80
84
|
@already_displayed = true
|
81
85
|
end
|
82
86
|
end
|
@@ -1,10 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module KubernetesDeploy
|
2
3
|
class Redis < KubernetesResource
|
3
4
|
TIMEOUT = 5.minutes
|
4
|
-
UUID_ANNOTATION = "redis.stable.shopify.io/owner_uid"
|
5
|
+
UUID_ANNOTATION = "redis.stable.shopify.io/owner_uid"
|
5
6
|
|
6
7
|
def initialize(name, namespace, context, file)
|
7
|
-
@name
|
8
|
+
@name = name
|
9
|
+
@namespace = namespace
|
10
|
+
@context = context
|
11
|
+
@file = file
|
8
12
|
end
|
9
13
|
|
10
14
|
def sync
|
@@ -36,6 +40,7 @@ module KubernetesDeploy
|
|
36
40
|
end
|
37
41
|
|
38
42
|
private
|
43
|
+
|
39
44
|
def redis_deployment_exists?
|
40
45
|
deployment, st = run_kubectl("get", "deployments", "redis-#{redis_resource_uuid}", "-o=json")
|
41
46
|
|
@@ -75,6 +80,5 @@ module KubernetesDeploy
|
|
75
80
|
@redis_resource_uuid = parsed.fetch("metadata", {}).fetch("uid", nil)
|
76
81
|
end
|
77
82
|
end
|
78
|
-
|
79
83
|
end
|
80
84
|
end
|
@@ -1,9 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module KubernetesDeploy
|
2
3
|
class Service < KubernetesResource
|
3
4
|
TIMEOUT = 5.minutes
|
4
5
|
|
5
6
|
def initialize(name, namespace, context, file)
|
6
|
-
@name
|
7
|
+
@name = name
|
8
|
+
@namespace = namespace
|
9
|
+
@context = context
|
10
|
+
@file = file
|
7
11
|
end
|
8
12
|
|
9
13
|
def sync
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'open3'
|
2
3
|
require 'securerandom'
|
3
4
|
require 'erb'
|
@@ -126,7 +127,8 @@ MSG
|
|
126
127
|
KubernetesDeploy.logger.warn("Inspecting the file mentioned in the error message (#{path})")
|
127
128
|
KubernetesDeploy.logger.warn(suspicious_file)
|
128
129
|
else
|
129
|
-
KubernetesDeploy.logger.warn("Detected a file (#{path.inspect}) referenced in the kubectl stderr
|
130
|
+
KubernetesDeploy.logger.warn("Detected a file (#{path.inspect}) referenced in the kubectl stderr " \
|
131
|
+
"but was unable to inspect it")
|
130
132
|
end
|
131
133
|
end
|
132
134
|
|
@@ -136,9 +138,9 @@ MSG
|
|
136
138
|
next if matching_resources.empty?
|
137
139
|
deploy_resources(matching_resources)
|
138
140
|
wait_for_completion(matching_resources)
|
139
|
-
|
140
|
-
|
141
|
-
raise FatalDeploymentError, "
|
141
|
+
fail_list = matching_resources.select { |r| r.deploy_failed? || r.deploy_timed_out? }.map(&:id)
|
142
|
+
unless fail_list.empty?
|
143
|
+
raise FatalDeploymentError, "The following priority resources failed to deploy: #{fail_list.join(', ')}"
|
142
144
|
end
|
143
145
|
end
|
144
146
|
end
|
@@ -159,7 +161,7 @@ MSG
|
|
159
161
|
end
|
160
162
|
|
161
163
|
def discover_resource_via_dry_run(tempfile)
|
162
|
-
resource_id,
|
164
|
+
resource_id, _err, st = run_kubectl("create", "-f", tempfile.path, "--dry-run", "--output=name")
|
163
165
|
raise FatalDeploymentError, "Dry run failed for template #{File.basename(tempfile.path)}." unless st.success?
|
164
166
|
resource_id
|
165
167
|
end
|
@@ -168,6 +170,8 @@ MSG
|
|
168
170
|
file_content = File.read(File.join(@template_dir, filename))
|
169
171
|
rendered_content = render_template(filename, file_content)
|
170
172
|
YAML.load_stream(rendered_content) do |doc|
|
173
|
+
next if doc.blank?
|
174
|
+
|
171
175
|
f = Tempfile.new(filename)
|
172
176
|
f.write(YAML.dump(doc))
|
173
177
|
f.close
|
@@ -183,8 +187,7 @@ MSG
|
|
183
187
|
log_green("Deploy succeeded!")
|
184
188
|
else
|
185
189
|
fail_list = resources.select { |r| r.deploy_failed? || r.deploy_timed_out? }.map(&:id)
|
186
|
-
|
187
|
-
raise FatalDeploymentError, "#{fail_list.length} resources failed to deploy"
|
190
|
+
raise FatalDeploymentError, "The following resources failed to deploy: #{fail_list.join(', ')}"
|
188
191
|
end
|
189
192
|
end
|
190
193
|
|
@@ -196,7 +199,7 @@ MSG
|
|
196
199
|
KubernetesDeploy.logger.info("Waiting for #{human_resources} with #{max_wait_time}s timeout")
|
197
200
|
while watched_resources.present?
|
198
201
|
if Time.now.utc < delay_sync_until
|
199
|
-
sleep
|
202
|
+
sleep(delay_sync_until - Time.now.utc)
|
200
203
|
end
|
201
204
|
delay_sync_until = Time.now.utc + 3 # don't pummel the API if the sync is fast
|
202
205
|
watched_resources.each(&:sync)
|
@@ -204,8 +207,6 @@ MSG
|
|
204
207
|
newly_finished_resources.each do |resource|
|
205
208
|
next unless resource.deploy_failed? || resource.deploy_timed_out?
|
206
209
|
KubernetesDeploy.logger.error("#{resource.id} failed to deploy with status '#{resource.status}'.")
|
207
|
-
KubernetesDeploy.logger.error("This script will continue to poll until the status of all resources deployed in this phase is resolved, but the deploy is now doomed and you may wish abort it.")
|
208
|
-
KubernetesDeploy.logger.error(resource.status_data)
|
209
210
|
end
|
210
211
|
end
|
211
212
|
|
@@ -227,7 +228,7 @@ MSG
|
|
227
228
|
def validate_configuration
|
228
229
|
errors = []
|
229
230
|
if ENV["KUBECONFIG"].blank? || !File.file?(ENV["KUBECONFIG"])
|
230
|
-
errors << "Kube config not found at #{ENV[
|
231
|
+
errors << "Kube config not found at #{ENV['KUBECONFIG']}"
|
231
232
|
end
|
232
233
|
|
233
234
|
if @current_sha.blank?
|
@@ -250,7 +251,7 @@ MSG
|
|
250
251
|
errors << "Context must be specified"
|
251
252
|
end
|
252
253
|
|
253
|
-
raise FatalDeploymentError, "Configuration invalid: #{errors.join(
|
254
|
+
raise FatalDeploymentError, "Configuration invalid: #{errors.join(', ')}" unless errors.empty?
|
254
255
|
KubernetesDeploy.logger.info("All required parameters and files are present")
|
255
256
|
end
|
256
257
|
|
@@ -338,7 +339,7 @@ MSG
|
|
338
339
|
def phase_heading(phase_name)
|
339
340
|
@current_phase += 1
|
340
341
|
heading = "Phase #{@current_phase}: #{phase_name}"
|
341
|
-
padding = (100.0 - heading.length)/2
|
342
|
+
padding = (100.0 - heading.length) / 2
|
342
343
|
KubernetesDeploy.logger.info("")
|
343
344
|
KubernetesDeploy.logger.info("#{'-' * padding.floor}#{heading}#{'-' * padding.ceil}")
|
344
345
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kubernetes-deploy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kir Shatrov
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date: 2017-03-
|
13
|
+
date: 2017-03-22 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -118,7 +118,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
118
118
|
version: '0'
|
119
119
|
requirements: []
|
120
120
|
rubyforge_project:
|
121
|
-
rubygems_version: 2.
|
121
|
+
rubygems_version: 2.5.1
|
122
122
|
signing_key:
|
123
123
|
specification_version: 4
|
124
124
|
summary: Kubernetes deploy scripts
|