kubernetes-deploy 0.18.0 → 0.18.1
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/CHANGELOG.md +5 -1
- data/ISSUE_TEMPLATE.md +25 -0
- data/README.md +2 -3
- data/lib/kubernetes-deploy.rb +1 -0
- data/lib/kubernetes-deploy/deploy_task.rb +8 -5
- data/lib/kubernetes-deploy/kubernetes_resource.rb +34 -32
- data/lib/kubernetes-deploy/kubernetes_resource/bucket.rb +2 -7
- data/lib/kubernetes-deploy/kubernetes_resource/cloudsql.rb +20 -49
- data/lib/kubernetes-deploy/kubernetes_resource/config_map.rb +4 -10
- data/lib/kubernetes-deploy/kubernetes_resource/cron_job.rb +0 -10
- data/lib/kubernetes-deploy/kubernetes_resource/daemon_set.rb +36 -32
- data/lib/kubernetes-deploy/kubernetes_resource/deployment.rb +69 -66
- data/lib/kubernetes-deploy/kubernetes_resource/elasticsearch.rb +1 -16
- data/lib/kubernetes-deploy/kubernetes_resource/ingress.rb +2 -8
- data/lib/kubernetes-deploy/kubernetes_resource/memcached.rb +18 -31
- data/lib/kubernetes-deploy/kubernetes_resource/persistent_volume_claim.rb +4 -10
- data/lib/kubernetes-deploy/kubernetes_resource/pod.rb +28 -31
- data/lib/kubernetes-deploy/kubernetes_resource/pod_disruption_budget.rb +2 -8
- data/lib/kubernetes-deploy/kubernetes_resource/pod_set_base.rb +10 -12
- data/lib/kubernetes-deploy/kubernetes_resource/pod_template.rb +2 -8
- data/lib/kubernetes-deploy/kubernetes_resource/redis.rb +19 -48
- data/lib/kubernetes-deploy/kubernetes_resource/replica_set.rb +33 -35
- data/lib/kubernetes-deploy/kubernetes_resource/resource_quota.rb +3 -14
- data/lib/kubernetes-deploy/kubernetes_resource/service.rb +20 -34
- data/lib/kubernetes-deploy/kubernetes_resource/service_account.rb +2 -8
- data/lib/kubernetes-deploy/kubernetes_resource/stateful_set.rb +37 -31
- data/lib/kubernetes-deploy/kubernetes_resource/statefulservice.rb +1 -16
- data/lib/kubernetes-deploy/kubernetes_resource/topic.rb +1 -16
- data/lib/kubernetes-deploy/resource_watcher.rb +6 -3
- data/lib/kubernetes-deploy/restart_task.rb +3 -1
- data/lib/kubernetes-deploy/sync_mediator.rb +66 -0
- data/lib/kubernetes-deploy/version.rb +1 -1
- metadata +4 -3
- data/lib/kubernetes-deploy/kubernetes_resource/bugsnag.rb +0 -33
@@ -17,33 +17,29 @@ module KubernetesDeploy
|
|
17
17
|
super(namespace: namespace, context: context, definition: definition, logger: logger)
|
18
18
|
end
|
19
19
|
|
20
|
-
def sync(
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
if pod_data.present?
|
28
|
-
@found = true
|
29
|
-
@phase = @status = pod_data["status"]["phase"]
|
30
|
-
@status += " (Reason: #{pod_data['status']['reason']})" if pod_data['status']['reason'].present?
|
31
|
-
@ready = ready?(pod_data["status"])
|
32
|
-
update_container_statuses(pod_data["status"])
|
20
|
+
def sync(mediator)
|
21
|
+
super
|
22
|
+
raise_predates_deploy_error if exists? && unmanaged? && !deploy_started?
|
23
|
+
|
24
|
+
if exists?
|
25
|
+
update_container_statuses(@instance_data["status"])
|
33
26
|
else # reset
|
34
|
-
@found = @ready = false
|
35
|
-
@status = @phase = 'Unknown'
|
36
27
|
@containers.each(&:reset_status)
|
37
28
|
end
|
38
29
|
|
39
|
-
display_logs if unmanaged? && deploy_succeeded?
|
30
|
+
display_logs(mediator) if unmanaged? && deploy_succeeded?
|
31
|
+
end
|
32
|
+
|
33
|
+
def status
|
34
|
+
return phase if @instance_data.dig('status', 'reason').blank?
|
35
|
+
"#{phase} (Reason: #{@instance_data['status']['reason']})"
|
40
36
|
end
|
41
37
|
|
42
38
|
def deploy_succeeded?
|
43
39
|
if unmanaged?
|
44
|
-
|
40
|
+
phase == "Succeeded"
|
45
41
|
else
|
46
|
-
|
42
|
+
phase == "Running" && ready?
|
47
43
|
end
|
48
44
|
end
|
49
45
|
|
@@ -51,10 +47,6 @@ module KubernetesDeploy
|
|
51
47
|
failure_message.present?
|
52
48
|
end
|
53
49
|
|
54
|
-
def exists?
|
55
|
-
@found
|
56
|
-
end
|
57
|
-
|
58
50
|
def timeout_message
|
59
51
|
return STANDARD_TIMEOUT_MESSAGE unless readiness_probe_failure?
|
60
52
|
probe_failure_msgs = @containers.map(&:readiness_fail_reason).compact
|
@@ -63,8 +55,8 @@ module KubernetesDeploy
|
|
63
55
|
end
|
64
56
|
|
65
57
|
def failure_message
|
66
|
-
if
|
67
|
-
phase_problem = "Pod status: #{
|
58
|
+
if phase == FAILED_PHASE_NAME
|
59
|
+
phase_problem = "Pod status: #{status}. "
|
68
60
|
end
|
69
61
|
|
70
62
|
doomed_containers = @containers.select(&:doomed?)
|
@@ -87,7 +79,7 @@ module KubernetesDeploy
|
|
87
79
|
# "app" => ["array of log lines", "received from app container"],
|
88
80
|
# "nginx" => ["array of log lines", "received from nginx container"]
|
89
81
|
# }
|
90
|
-
def fetch_logs
|
82
|
+
def fetch_logs(kubectl)
|
91
83
|
return {} unless exists? && @containers.present?
|
92
84
|
@containers.each_with_object({}) do |container, container_logs|
|
93
85
|
cmd = [
|
@@ -97,20 +89,25 @@ module KubernetesDeploy
|
|
97
89
|
"--since-time=#{@deploy_started_at.to_datetime.rfc3339}",
|
98
90
|
]
|
99
91
|
cmd << "--tail=#{LOG_LINE_COUNT}" unless unmanaged?
|
100
|
-
out, _err, _st = kubectl.run(*cmd)
|
92
|
+
out, _err, _st = kubectl.run(*cmd, log_failure: false)
|
101
93
|
container_logs[container.name] = out.split("\n")
|
102
94
|
end
|
103
95
|
end
|
104
96
|
|
105
97
|
private
|
106
98
|
|
99
|
+
def phase
|
100
|
+
@instance_data.dig("status", "phase") || "Unknown"
|
101
|
+
end
|
102
|
+
|
107
103
|
def readiness_probe_failure?
|
108
|
-
return false if
|
109
|
-
return false if
|
104
|
+
return false if ready? || unmanaged?
|
105
|
+
return false if phase != "Running"
|
110
106
|
@containers.any?(&:readiness_fail_reason)
|
111
107
|
end
|
112
108
|
|
113
|
-
def ready?
|
109
|
+
def ready?
|
110
|
+
return false unless status_data = @instance_data["status"]
|
114
111
|
ready_condition = status_data.fetch("conditions", []).find { |condition| condition["type"] == "Ready" }
|
115
112
|
ready_condition.present? && (ready_condition["status"] == "True")
|
116
113
|
end
|
@@ -131,9 +128,9 @@ module KubernetesDeploy
|
|
131
128
|
@parent.blank?
|
132
129
|
end
|
133
130
|
|
134
|
-
def display_logs
|
131
|
+
def display_logs(mediator)
|
135
132
|
return if @already_displayed
|
136
|
-
container_logs = fetch_logs
|
133
|
+
container_logs = fetch_logs(mediator.kubectl)
|
137
134
|
|
138
135
|
if container_logs.empty?
|
139
136
|
@logger.warn("No logs found for pod #{id}")
|
@@ -3,10 +3,8 @@ module KubernetesDeploy
|
|
3
3
|
class PodDisruptionBudget < KubernetesResource
|
4
4
|
TIMEOUT = 10.seconds
|
5
5
|
|
6
|
-
def
|
7
|
-
|
8
|
-
@found = st.success?
|
9
|
-
@status = @found ? "Available" : "Unknown"
|
6
|
+
def status
|
7
|
+
exists? ? "Available" : "Unknown"
|
10
8
|
end
|
11
9
|
|
12
10
|
def deploy_succeeded?
|
@@ -21,9 +19,5 @@ module KubernetesDeploy
|
|
21
19
|
def timeout_message
|
22
20
|
UNUSUAL_FAILURE_MESSAGE
|
23
21
|
end
|
24
|
-
|
25
|
-
def exists?
|
26
|
-
@found
|
27
|
-
end
|
28
22
|
end
|
29
23
|
end
|
@@ -9,14 +9,14 @@ module KubernetesDeploy
|
|
9
9
|
pods.map(&:timeout_message).compact.uniq.join("\n")
|
10
10
|
end
|
11
11
|
|
12
|
-
def fetch_events
|
12
|
+
def fetch_events(kubectl)
|
13
13
|
own_events = super
|
14
14
|
return own_events unless pods.present?
|
15
15
|
most_useful_pod = pods.find(&:deploy_failed?) || pods.find(&:deploy_timed_out?) || pods.first
|
16
|
-
own_events.merge(most_useful_pod.fetch_events)
|
16
|
+
own_events.merge(most_useful_pod.fetch_events(kubectl))
|
17
17
|
end
|
18
18
|
|
19
|
-
def fetch_logs
|
19
|
+
def fetch_logs(kubectl)
|
20
20
|
return {} unless pods.present? # the kubectl command times out if no pods exist
|
21
21
|
container_names.each_with_object({}) do |container_name, container_logs|
|
22
22
|
out, _err, _st = kubectl.run(
|
@@ -24,7 +24,8 @@ module KubernetesDeploy
|
|
24
24
|
id,
|
25
25
|
"--container=#{container_name}",
|
26
26
|
"--since-time=#{@deploy_started_at.to_datetime.rfc3339}",
|
27
|
-
"--tail=#{LOG_LINE_COUNT}"
|
27
|
+
"--tail=#{LOG_LINE_COUNT}",
|
28
|
+
log_failure: false
|
28
29
|
)
|
29
30
|
container_logs[container_name] = out.split("\n")
|
30
31
|
end
|
@@ -36,7 +37,7 @@ module KubernetesDeploy
|
|
36
37
|
raise NotImplementedError, "Subclasses must define a `pods` accessor"
|
37
38
|
end
|
38
39
|
|
39
|
-
def parent_of_pod?(_
|
40
|
+
def parent_of_pod?(_)
|
40
41
|
raise NotImplementedError, "Subclasses must define a `parent_of_pod?` method"
|
41
42
|
end
|
42
43
|
|
@@ -46,14 +47,11 @@ module KubernetesDeploy
|
|
46
47
|
regular_containers + init_containers
|
47
48
|
end
|
48
49
|
|
49
|
-
def find_pods(
|
50
|
-
|
51
|
-
raw_json, _err, st = kubectl.run("get", "pods", "-a", "--output=json", "--selector=#{label_string}")
|
52
|
-
return [] unless st.success?
|
50
|
+
def find_pods(mediator)
|
51
|
+
all_pods = mediator.get_all(Pod.kind, @instance_data["spec"]["selector"]["matchLabels"])
|
53
52
|
|
54
|
-
all_pods = JSON.parse(raw_json)["items"]
|
55
53
|
all_pods.each_with_object([]) do |pod_data, relevant_pods|
|
56
|
-
next unless parent_of_pod?(
|
54
|
+
next unless parent_of_pod?(pod_data)
|
57
55
|
pod = Pod.new(
|
58
56
|
namespace: namespace,
|
59
57
|
context: context,
|
@@ -62,7 +60,7 @@ module KubernetesDeploy
|
|
62
60
|
parent: "#{name.capitalize} #{type}",
|
63
61
|
deploy_started_at: @deploy_started_at
|
64
62
|
)
|
65
|
-
pod.sync(
|
63
|
+
pod.sync(mediator)
|
66
64
|
relevant_pods << pod
|
67
65
|
end
|
68
66
|
end
|
@@ -1,10 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module KubernetesDeploy
|
3
3
|
class PodTemplate < KubernetesResource
|
4
|
-
def
|
5
|
-
|
6
|
-
@status = st.success? ? "Available" : "Unknown"
|
7
|
-
@found = st.success?
|
4
|
+
def status
|
5
|
+
exists? ? "Available" : "Unknown"
|
8
6
|
end
|
9
7
|
|
10
8
|
def deploy_succeeded?
|
@@ -18,9 +16,5 @@ module KubernetesDeploy
|
|
18
16
|
def timeout_message
|
19
17
|
UNUSUAL_FAILURE_MESSAGE
|
20
18
|
end
|
21
|
-
|
22
|
-
def exists?
|
23
|
-
@found
|
24
|
-
end
|
25
19
|
end
|
26
20
|
end
|
@@ -4,75 +4,46 @@ module KubernetesDeploy
|
|
4
4
|
TIMEOUT = 5.minutes
|
5
5
|
UUID_ANNOTATION = "redis.stable.shopify.io/owner_uid"
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
@
|
11
|
-
@
|
7
|
+
SYNC_DEPENDENCIES = %w(Deployment Service)
|
8
|
+
def sync(mediator)
|
9
|
+
super
|
10
|
+
@deployment = mediator.get_instance(Deployment.kind, "redis-#{redis_resource_uuid}")
|
11
|
+
@service = mediator.get_instance(Service.kind, "redis-#{redis_resource_uuid}")
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
else
|
16
|
-
"Unknown"
|
17
|
-
end
|
14
|
+
def status
|
15
|
+
deploy_succeeded? ? "Provisioned" : "Unknown"
|
18
16
|
end
|
19
17
|
|
20
18
|
def deploy_succeeded?
|
21
|
-
|
19
|
+
deployment_ready? && service_ready?
|
22
20
|
end
|
23
21
|
|
24
22
|
def deploy_failed?
|
25
23
|
false
|
26
24
|
end
|
27
25
|
|
28
|
-
def exists?
|
29
|
-
@found
|
30
|
-
end
|
31
|
-
|
32
26
|
def deploy_method
|
33
27
|
:replace
|
34
28
|
end
|
35
29
|
|
36
30
|
private
|
37
31
|
|
38
|
-
def
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
parsed = JSON.parse(deployment)
|
43
|
-
|
44
|
-
if parsed.fetch("status", {}).fetch("availableReplicas", -1) == parsed.fetch("status", {}).fetch("replicas", 0)
|
45
|
-
# all redis pods are running
|
46
|
-
return true
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
false
|
32
|
+
def deployment_ready?
|
33
|
+
return false unless status = @deployment["status"]
|
34
|
+
# all redis pods are running
|
35
|
+
status.fetch("availableReplicas", -1) == status.fetch("replicas", 0)
|
51
36
|
end
|
52
37
|
|
53
|
-
def
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
parsed = JSON.parse(service)
|
58
|
-
|
59
|
-
if parsed.dig("spec", "clusterIP").present?
|
60
|
-
return true
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
false
|
38
|
+
def service_ready?
|
39
|
+
return false unless @service.present?
|
40
|
+
# the service has an assigned cluster IP and is therefore functioning
|
41
|
+
@service.dig("spec", "clusterIP").present?
|
65
42
|
end
|
66
43
|
|
67
44
|
def redis_resource_uuid
|
68
|
-
return @
|
69
|
-
|
70
|
-
redis, _err, st = kubectl.run("get", "redises", @name, "-o=json")
|
71
|
-
if st.success?
|
72
|
-
parsed = JSON.parse(redis)
|
73
|
-
|
74
|
-
@redis_resource_uuid = parsed.dig("metadata", "uid")
|
75
|
-
end
|
45
|
+
return unless @instance_data.present?
|
46
|
+
@instance_data.dig("metadata", "uid")
|
76
47
|
end
|
77
48
|
end
|
78
49
|
end
|
@@ -3,64 +3,62 @@ require 'kubernetes-deploy/kubernetes_resource/pod_set_base'
|
|
3
3
|
module KubernetesDeploy
|
4
4
|
class ReplicaSet < PodSetBase
|
5
5
|
TIMEOUT = 5.minutes
|
6
|
-
attr_reader :
|
6
|
+
attr_reader :pods
|
7
7
|
|
8
8
|
def initialize(namespace:, context:, definition:, logger:, parent: nil, deploy_started_at: nil)
|
9
9
|
@parent = parent
|
10
10
|
@deploy_started_at = deploy_started_at
|
11
|
-
@rollout_data = { "replicas" => 0 }
|
12
|
-
@desired_replicas = -1
|
13
|
-
@ready_replicas = -1
|
14
|
-
@available_replicas = -1
|
15
11
|
@pods = []
|
16
12
|
super(namespace: namespace, context: context, definition: definition, logger: logger)
|
17
13
|
end
|
18
14
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
15
|
+
SYNC_DEPENDENCIES = %w(Pod)
|
16
|
+
def sync(mediator)
|
17
|
+
super
|
18
|
+
@pods = exists? ? find_pods(mediator) : []
|
19
|
+
end
|
24
20
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
@rollout_data = { "replicas" => 0 }.merge(
|
29
|
-
rs_data["status"].slice("replicas", "availableReplicas", "readyReplicas")
|
30
|
-
)
|
31
|
-
@ready_replicas = @rollout_data['readyReplicas'].to_i
|
32
|
-
@available_replicas = @rollout_data["availableReplicas"].to_i
|
33
|
-
@status = @rollout_data.map { |state_replicas, num| "#{num} #{state_replicas.chop.pluralize(num)}" }.join(", ")
|
34
|
-
@pods = find_pods(rs_data)
|
35
|
-
else # reset
|
36
|
-
@found = false
|
37
|
-
@rollout_data = { "replicas" => 0 }
|
38
|
-
@status = nil
|
39
|
-
@pods = []
|
40
|
-
@desired_replicas = -1
|
41
|
-
@ready_replicas = -1
|
42
|
-
@available_replicas = -1
|
43
|
-
end
|
21
|
+
def status
|
22
|
+
return super unless rollout_data.present?
|
23
|
+
rollout_data.map { |state_replicas, num| "#{num} #{state_replicas.chop.pluralize(num)}" }.join(", ")
|
44
24
|
end
|
45
25
|
|
46
26
|
def deploy_succeeded?
|
47
|
-
|
48
|
-
|
27
|
+
desired_replicas == rollout_data["availableReplicas"].to_i &&
|
28
|
+
desired_replicas == rollout_data["readyReplicas"].to_i
|
49
29
|
end
|
50
30
|
|
51
31
|
def deploy_failed?
|
52
32
|
pods.present? && pods.all?(&:deploy_failed?)
|
53
33
|
end
|
54
34
|
|
55
|
-
def
|
56
|
-
|
35
|
+
def desired_replicas
|
36
|
+
return -1 unless exists?
|
37
|
+
@instance_data["spec"]["replicas"].to_i
|
38
|
+
end
|
39
|
+
|
40
|
+
def ready_replicas
|
41
|
+
return -1 unless exists?
|
42
|
+
rollout_data['readyReplicas'].to_i
|
43
|
+
end
|
44
|
+
|
45
|
+
def available_replicas
|
46
|
+
return -1 unless exists?
|
47
|
+
rollout_data["availableReplicas"].to_i
|
57
48
|
end
|
58
49
|
|
59
50
|
private
|
60
51
|
|
61
|
-
def
|
52
|
+
def rollout_data
|
53
|
+
return { "replicas" => 0 } unless exists?
|
54
|
+
{ "replicas" => 0 }.merge(
|
55
|
+
@instance_data["status"].slice("replicas", "availableReplicas", "readyReplicas")
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
def parent_of_pod?(pod_data)
|
62
60
|
return false unless pod_data.dig("metadata", "ownerReferences")
|
63
|
-
pod_data["metadata"]["ownerReferences"].any? { |ref| ref["uid"] ==
|
61
|
+
pod_data["metadata"]["ownerReferences"].any? { |ref| ref["uid"] == @instance_data["metadata"]["uid"] }
|
64
62
|
end
|
65
63
|
|
66
64
|
def unmanaged?
|
@@ -3,19 +3,12 @@ module KubernetesDeploy
|
|
3
3
|
class ResourceQuota < KubernetesResource
|
4
4
|
TIMEOUT = 30.seconds
|
5
5
|
|
6
|
-
def
|
7
|
-
|
8
|
-
@status = st.success? ? "Available" : "Unknown"
|
9
|
-
@found = st.success?
|
10
|
-
@rollout_data = if @found
|
11
|
-
JSON.parse(raw_json)
|
12
|
-
else
|
13
|
-
{}
|
14
|
-
end
|
6
|
+
def status
|
7
|
+
exists? ? "In effect" : "Unknown"
|
15
8
|
end
|
16
9
|
|
17
10
|
def deploy_succeeded?
|
18
|
-
@
|
11
|
+
@instance_data.dig("spec", "hard") == @instance_data.dig("status", "hard")
|
19
12
|
end
|
20
13
|
|
21
14
|
def deploy_failed?
|
@@ -25,9 +18,5 @@ module KubernetesDeploy
|
|
25
18
|
def timeout_message
|
26
19
|
UNUSUAL_FAILURE_MESSAGE
|
27
20
|
end
|
28
|
-
|
29
|
-
def exists?
|
30
|
-
@found
|
31
|
-
end
|
32
21
|
end
|
33
22
|
end
|