krane 1.0.0 → 1.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/CODEOWNERS +1 -0
- data/{ISSUE_TEMPLATE.md → .github/ISSUE_TEMPLATE.md} +0 -0
- data/{pull_request_template.md → .github/pull_request_template.md} +0 -0
- data/.gitignore +0 -3
- data/.rubocop-http---shopify-github-io-ruby-style-guide-rubocop-yml +1020 -0
- data/.rubocop.yml +0 -12
- data/.shopify-build/{kubernetes-deploy.yml → krane.yml} +16 -1
- data/1.0-Upgrade.md +4 -5
- data/CHANGELOG.md +55 -1
- data/CONTRIBUTING.md +5 -5
- data/Gemfile +0 -11
- data/README.md +22 -24
- data/bin/ci +1 -1
- data/bin/test +2 -2
- data/dev.yml +4 -4
- data/krane.gemspec +22 -5
- data/lib/krane/cli/deploy_command.rb +3 -4
- data/lib/krane/cli/global_deploy_command.rb +3 -3
- data/lib/krane/cli/render_command.rb +3 -3
- data/lib/krane/cluster_resource_discovery.rb +9 -6
- data/lib/krane/concurrency.rb +2 -2
- data/lib/krane/container_logs.rb +1 -1
- data/lib/krane/container_overrides.rb +33 -0
- data/lib/krane/deploy_task.rb +5 -5
- data/lib/krane/ejson_secret_provisioner.rb +7 -4
- data/lib/krane/global_deploy_task.rb +3 -2
- data/lib/krane/kubectl.rb +11 -1
- data/lib/krane/kubernetes_resource.rb +7 -6
- data/lib/krane/kubernetes_resource/custom_resource.rb +1 -1
- data/lib/krane/kubernetes_resource/custom_resource_definition.rb +1 -1
- data/lib/krane/kubernetes_resource/daemon_set.rb +1 -0
- data/lib/krane/kubernetes_resource/deployment.rb +3 -2
- data/lib/krane/kubernetes_resource/pod.rb +12 -8
- data/lib/krane/kubernetes_resource/replica_set.rb +2 -16
- data/lib/krane/kubernetes_resource/service.rb +3 -7
- data/lib/krane/kubernetes_resource/stateful_set.rb +1 -0
- data/lib/krane/render_task.rb +2 -2
- data/lib/krane/resource_cache.rb +6 -0
- data/lib/krane/resource_watcher.rb +2 -1
- data/lib/krane/restart_task.rb +2 -2
- data/lib/krane/runner_task.rb +16 -17
- data/lib/krane/statsd.rb +2 -2
- data/lib/krane/template_sets.rb +1 -1
- data/lib/krane/version.rb +1 -1
- metadata +168 -20
- data/lib/krane/kubernetes_resource/cloudsql.rb +0 -43
- data/shipit.yml +0 -4
@@ -8,7 +8,8 @@ module Krane
|
|
8
8
|
"filenames" => { type: :array, banner: 'config/deploy/production config/deploy/my-extra-resource.yml',
|
9
9
|
aliases: :f, required: false, default: [],
|
10
10
|
desc: "Directories and files that contains the configuration to apply" },
|
11
|
-
"stdin" => { type: :boolean, default: false,
|
11
|
+
"stdin" => { type: :boolean, default: false,
|
12
|
+
desc: "[DEPRECATED] Read resources from stdin" },
|
12
13
|
"global-timeout" => { type: :string, banner: "duration", default: DEFAULT_DEPLOY_TIMEOUT,
|
13
14
|
desc: "Max duration to monitor workloads correctly deployed" },
|
14
15
|
"verify-result" => { type: :boolean, default: true,
|
@@ -28,11 +29,10 @@ module Krane
|
|
28
29
|
|
29
30
|
selector = ::Krane::LabelSelector.parse(options[:selector])
|
30
31
|
|
31
|
-
# never mutate options directly
|
32
32
|
filenames = options[:filenames].dup
|
33
33
|
filenames << "-" if options[:stdin]
|
34
34
|
if filenames.empty?
|
35
|
-
raise
|
35
|
+
raise(Thor::RequiredArgumentMissingError, '--filenames must be set and not empty')
|
36
36
|
end
|
37
37
|
|
38
38
|
::Krane::OptionsHelper.with_processed_template_paths(filenames) do |paths|
|
@@ -7,7 +7,8 @@ module Krane
|
|
7
7
|
"bindings" => { type: :array, banner: "foo=bar abc=def", desc: 'Bindings for erb' },
|
8
8
|
"filenames" => { type: :array, banner: 'config/deploy/production config/deploy/my-extra-resource.yml',
|
9
9
|
required: false, default: [], aliases: 'f', desc: 'Directories and files to render' },
|
10
|
-
"stdin" => { type: :boolean,
|
10
|
+
"stdin" => { type: :boolean, default: false,
|
11
|
+
desc: "[DEPRECATED] Read resources from stdin" },
|
11
12
|
"current-sha" => { type: :string, banner: "SHA", desc: "Expose SHA `current_sha` in ERB bindings",
|
12
13
|
lazy_default: '' },
|
13
14
|
}
|
@@ -20,11 +21,10 @@ module Krane
|
|
20
21
|
bindings_parser = ::Krane::BindingsParser.new
|
21
22
|
options[:bindings]&.each { |b| bindings_parser.add(b) }
|
22
23
|
|
23
|
-
# never mutate options directly
|
24
24
|
filenames = options[:filenames].dup
|
25
25
|
filenames << "-" if options[:stdin]
|
26
26
|
if filenames.empty?
|
27
|
-
raise
|
27
|
+
raise(Thor::RequiredArgumentMissingError, '--filenames must be set and not empty')
|
28
28
|
end
|
29
29
|
|
30
30
|
::Krane::OptionsHelper.with_processed_template_paths(filenames, render_erb: true) do |paths|
|
@@ -37,7 +37,7 @@ module Krane
|
|
37
37
|
def fetch_resources(namespaced: false)
|
38
38
|
command = %w(api-resources)
|
39
39
|
command << "--namespaced=#{namespaced}"
|
40
|
-
raw,
|
40
|
+
raw, err, st = kubectl.run(*command, output: "wide", attempts: 5,
|
41
41
|
use_namespace: false)
|
42
42
|
if st.success?
|
43
43
|
rows = raw.split("\n")
|
@@ -59,7 +59,7 @@ module Krane
|
|
59
59
|
resource
|
60
60
|
end
|
61
61
|
else
|
62
|
-
|
62
|
+
raise FatalKubeAPIError, "Error retrieving api-resources: #{err}"
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
@@ -68,7 +68,7 @@ module Krane
|
|
68
68
|
# kubectl api-versions returns a list of group/version strings e.g. autoscaling/v2beta2
|
69
69
|
# A kind may not exist in all versions of the group.
|
70
70
|
def fetch_api_versions
|
71
|
-
raw,
|
71
|
+
raw, err, st = kubectl.run("api-versions", attempts: 5, use_namespace: false)
|
72
72
|
# The "core" group is represented by an empty string
|
73
73
|
versions = { "" => %w(v1) }
|
74
74
|
if st.success?
|
@@ -78,6 +78,8 @@ module Krane
|
|
78
78
|
versions[group] ||= []
|
79
79
|
versions[group] << version
|
80
80
|
end
|
81
|
+
else
|
82
|
+
raise FatalKubeAPIError, "Error retrieving api-versions: #{err}"
|
81
83
|
end
|
82
84
|
versions
|
83
85
|
end
|
@@ -85,7 +87,8 @@ module Krane
|
|
85
87
|
def version_for_kind(versions, kind)
|
86
88
|
# Override list for kinds that don't appear in the lastest version of a group
|
87
89
|
version_override = { "CronJob" => "v1beta1", "VolumeAttachment" => "v1beta1",
|
88
|
-
"CSIDriver" => "v1beta1", "Ingress" => "v1beta1",
|
90
|
+
"CSIDriver" => "v1beta1", "Ingress" => "v1beta1",
|
91
|
+
"CSINode" => "v1beta1", "Job" => "v1" }
|
89
92
|
|
90
93
|
pattern = /v(?<major>\d+)(?<pre>alpha|beta)?(?<minor>\d+)?/
|
91
94
|
latest = versions.sort_by do |version|
|
@@ -97,12 +100,12 @@ module Krane
|
|
97
100
|
end
|
98
101
|
|
99
102
|
def fetch_crds
|
100
|
-
raw_json,
|
103
|
+
raw_json, err, st = kubectl.run("get", "CustomResourceDefinition", output: "json", attempts: 5,
|
101
104
|
use_namespace: false)
|
102
105
|
if st.success?
|
103
106
|
JSON.parse(raw_json)["items"]
|
104
107
|
else
|
105
|
-
|
108
|
+
raise FatalKubeAPIError, "Error retrieving CustomResourceDefinition: #{err}"
|
106
109
|
end
|
107
110
|
end
|
108
111
|
|
data/lib/krane/concurrency.rb
CHANGED
@@ -3,11 +3,11 @@ module Krane
|
|
3
3
|
module Concurrency
|
4
4
|
MAX_THREADS = 8
|
5
5
|
|
6
|
-
def self.split_across_threads(all_work, &block)
|
6
|
+
def self.split_across_threads(all_work, max_threads: MAX_THREADS, &block)
|
7
7
|
return if all_work.empty?
|
8
8
|
raise ArgumentError, "Block of work is required" unless block_given?
|
9
9
|
|
10
|
-
slice_size = ((all_work.length +
|
10
|
+
slice_size = ((all_work.length + max_threads - 1) / max_threads)
|
11
11
|
threads = []
|
12
12
|
all_work.each_slice(slice_size) do |work_group|
|
13
13
|
threads << Thread.new { work_group.each(&block) }
|
data/lib/krane/container_logs.rb
CHANGED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Krane
|
3
|
+
class ContainerOverrides
|
4
|
+
attr_reader :command, :arguments, :env_vars, :image_tag
|
5
|
+
|
6
|
+
def initialize(command: nil, arguments: nil, env_vars: [], image_tag: nil)
|
7
|
+
@command = command
|
8
|
+
@arguments = arguments
|
9
|
+
@env_vars = env_vars
|
10
|
+
@image_tag = image_tag
|
11
|
+
end
|
12
|
+
|
13
|
+
def apply!(container)
|
14
|
+
container.command = command if command
|
15
|
+
container.args = arguments if arguments
|
16
|
+
|
17
|
+
if image_tag
|
18
|
+
image = container.image
|
19
|
+
base_image, _old_tag = image.split(':')
|
20
|
+
new_image = "#{base_image}:#{image_tag}"
|
21
|
+
|
22
|
+
container.image = new_image
|
23
|
+
end
|
24
|
+
|
25
|
+
env_args = env_vars.map do |env|
|
26
|
+
key, value = env.split('=', 2)
|
27
|
+
{ name: key, value: value }
|
28
|
+
end
|
29
|
+
container.env ||= []
|
30
|
+
container.env = container.env.map(&:to_h) + env_args
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/krane/deploy_task.rb
CHANGED
@@ -10,7 +10,6 @@ require 'krane/resource_cache'
|
|
10
10
|
require 'krane/kubernetes_resource'
|
11
11
|
%w(
|
12
12
|
custom_resource
|
13
|
-
cloudsql
|
14
13
|
config_map
|
15
14
|
deployment
|
16
15
|
ingress
|
@@ -60,14 +59,14 @@ module Krane
|
|
60
59
|
before_crs = %w(
|
61
60
|
ResourceQuota
|
62
61
|
NetworkPolicy
|
63
|
-
)
|
64
|
-
after_crs = %w(
|
65
62
|
ConfigMap
|
66
63
|
PersistentVolumeClaim
|
67
64
|
ServiceAccount
|
68
65
|
Role
|
69
66
|
RoleBinding
|
70
67
|
Secret
|
68
|
+
)
|
69
|
+
after_crs = %w(
|
71
70
|
Pod
|
72
71
|
)
|
73
72
|
|
@@ -117,8 +116,8 @@ module Krane
|
|
117
116
|
# Runs the task, returning a boolean representing success or failure
|
118
117
|
#
|
119
118
|
# @return [Boolean]
|
120
|
-
def run(
|
121
|
-
run!(
|
119
|
+
def run(**args)
|
120
|
+
run!(**args)
|
122
121
|
true
|
123
122
|
rescue FatalDeploymentError
|
124
123
|
false
|
@@ -216,6 +215,7 @@ module Krane
|
|
216
215
|
|
217
216
|
def check_initial_status(resources)
|
218
217
|
cache = ResourceCache.new(@task_config)
|
218
|
+
cache.prewarm(resources)
|
219
219
|
Krane::Concurrency.split_across_threads(resources) { |r| r.sync(cache) }
|
220
220
|
resources.each { |r| @logger.info(r.pretty_status) }
|
221
221
|
end
|
@@ -134,10 +134,13 @@ module Krane
|
|
134
134
|
end
|
135
135
|
|
136
136
|
def decrypt_ejson(key_dir)
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
137
|
+
out, err, st = Open3.capture3("EJSON_KEYDIR=#{key_dir} ejson decrypt #{@ejson_file}")
|
138
|
+
unless st.success?
|
139
|
+
# older ejson versions dump some errors to STDOUT
|
140
|
+
msg = err.presence || out
|
141
|
+
raise EjsonSecretError, msg
|
142
|
+
end
|
143
|
+
JSON.parse(out)
|
141
144
|
rescue JSON::ParserError
|
142
145
|
raise EjsonSecretError, "Failed to parse decrypted ejson"
|
143
146
|
end
|
@@ -46,8 +46,8 @@ module Krane
|
|
46
46
|
# Runs the task, returning a boolean representing success or failure
|
47
47
|
#
|
48
48
|
# @return [Boolean]
|
49
|
-
def run(
|
50
|
-
run!(
|
49
|
+
def run(**args)
|
50
|
+
run!(**args)
|
51
51
|
true
|
52
52
|
rescue FatalDeploymentError
|
53
53
|
false
|
@@ -202,6 +202,7 @@ module Krane
|
|
202
202
|
|
203
203
|
def check_initial_status(resources)
|
204
204
|
cache = ResourceCache.new(@task_config)
|
205
|
+
cache.prewarm(resources)
|
205
206
|
Concurrency.split_across_threads(resources) { |r| r.sync(cache) }
|
206
207
|
resources.each { |r| logger.info(r.pretty_status) }
|
207
208
|
end
|
data/lib/krane/kubectl.rb
CHANGED
@@ -6,6 +6,7 @@ module Krane
|
|
6
6
|
ERROR_MATCHERS = {
|
7
7
|
not_found: /NotFound/,
|
8
8
|
client_timeout: /Client\.Timeout exceeded while awaiting headers/,
|
9
|
+
empty: /\A\z/,
|
9
10
|
}
|
10
11
|
DEFAULT_TIMEOUT = 15
|
11
12
|
MAX_RETRY_DELAY = 16
|
@@ -34,7 +35,16 @@ module Krane
|
|
34
35
|
(1..attempts).to_a.each do |current_attempt|
|
35
36
|
logger.debug("Running command (attempt #{current_attempt}): #{cmd.join(' ')}")
|
36
37
|
out, err, st = Open3.capture3(*cmd)
|
37
|
-
|
38
|
+
|
39
|
+
# https://github.com/Shopify/krane/issues/395
|
40
|
+
unless out.valid_encoding?
|
41
|
+
out = out.dup.force_encoding(Encoding::UTF_8)
|
42
|
+
end
|
43
|
+
|
44
|
+
if logger.debug? && !output_is_sensitive
|
45
|
+
# don't do the gsub unless we're going to print this
|
46
|
+
logger.debug("Kubectl out: " + out.gsub(/\s+/, ' '))
|
47
|
+
end
|
38
48
|
|
39
49
|
break if st.success?
|
40
50
|
raise(ResourceNotFoundError, err) if err.match(ERROR_MATCHERS[:not_found]) && raise_if_not_found
|
@@ -16,7 +16,7 @@ module Krane
|
|
16
16
|
TIMEOUT = 5.minutes
|
17
17
|
LOG_LINE_COUNT = 250
|
18
18
|
SERVER_DRY_RUN_DISABLED_ERROR =
|
19
|
-
/(unknown flag: --server-dry-run)|(
|
19
|
+
/(unknown flag: --server-dry-run)|(does[\s\']n[o|']t support dry[-\s]run)|(dryRun alpha feature is disabled)/
|
20
20
|
|
21
21
|
DISABLE_FETCHING_LOG_INFO = 'DISABLE_FETCHING_LOG_INFO'
|
22
22
|
DISABLE_FETCHING_EVENT_INFO = 'DISABLE_FETCHING_EVENT_INFO'
|
@@ -38,6 +38,7 @@ module Krane
|
|
38
38
|
LAST_APPLIED_ANNOTATION = "kubectl.kubernetes.io/last-applied-configuration"
|
39
39
|
SENSITIVE_TEMPLATE_CONTENT = false
|
40
40
|
SERVER_DRY_RUNNABLE = false
|
41
|
+
SYNC_DEPENDENCIES = []
|
41
42
|
|
42
43
|
class << self
|
43
44
|
def build(namespace: nil, context:, definition:, logger:, statsd_tags:, crd: nil, global_names: [])
|
@@ -59,8 +60,8 @@ module Krane
|
|
59
60
|
end
|
60
61
|
|
61
62
|
def class_for_kind(kind)
|
62
|
-
if Krane.const_defined?(kind)
|
63
|
-
Krane.const_get(kind)
|
63
|
+
if Krane.const_defined?(kind, false)
|
64
|
+
Krane.const_get(kind, false)
|
64
65
|
end
|
65
66
|
rescue NameError
|
66
67
|
nil
|
@@ -255,7 +256,7 @@ module Krane
|
|
255
256
|
if cause == :gave_up
|
256
257
|
debug_heading = ColorizedString.new("#{id}: GLOBAL WATCH TIMEOUT (#{info_hash[:timeout]} seconds)").yellow
|
257
258
|
helpful_info << "If you expected it to take longer than #{info_hash[:timeout]} seconds for your deploy"\
|
258
|
-
" to roll out, increase --
|
259
|
+
" to roll out, increase --global-timeout."
|
259
260
|
elsif deploy_failed?
|
260
261
|
debug_heading = ColorizedString.new("#{id}: FAILED").red
|
261
262
|
helpful_info << failure_message if failure_message.present?
|
@@ -571,7 +572,7 @@ module Krane
|
|
571
572
|
def validate_with_server_side_dry_run(kubectl)
|
572
573
|
command = ["apply", "-f", file_path, "--server-dry-run", "--output=name"]
|
573
574
|
kubectl.run(*command, log_failure: false, output_is_sensitive: sensitive_template_content?,
|
574
|
-
retry_whitelist: [:client_timeout], attempts: 3)
|
575
|
+
retry_whitelist: [:client_timeout, :empty], attempts: 3)
|
575
576
|
end
|
576
577
|
|
577
578
|
# Local dry run is supported on only create and apply
|
@@ -581,7 +582,7 @@ module Krane
|
|
581
582
|
verb = deploy_method == :apply ? "apply" : "create"
|
582
583
|
command = [verb, "-f", file_path, "--dry-run", "--output=name"]
|
583
584
|
kubectl.run(*command, log_failure: false, output_is_sensitive: sensitive_template_content?,
|
584
|
-
retry_whitelist: [:client_timeout], attempts: 3, use_namespace: !global?)
|
585
|
+
retry_whitelist: [:client_timeout, :empty], attempts: 3, use_namespace: !global?)
|
585
586
|
end
|
586
587
|
|
587
588
|
def labels
|
@@ -4,6 +4,7 @@ require 'krane/kubernetes_resource/replica_set'
|
|
4
4
|
module Krane
|
5
5
|
class Deployment < KubernetesResource
|
6
6
|
TIMEOUT = 7.minutes
|
7
|
+
SYNC_DEPENDENCIES = %w(Pod ReplicaSet)
|
7
8
|
REQUIRED_ROLLOUT_ANNOTATION_SUFFIX = "required-rollout"
|
8
9
|
REQUIRED_ROLLOUT_ANNOTATION_DEPRECATED = "kubernetes-deploy.shopify.io/#{REQUIRED_ROLLOUT_ANNOTATION_SUFFIX}"
|
9
10
|
REQUIRED_ROLLOUT_ANNOTATION = "krane.shopify.io/#{REQUIRED_ROLLOUT_ANNOTATION_SUFFIX}"
|
@@ -96,7 +97,7 @@ module Krane
|
|
96
97
|
progress_condition.present? ? deploy_failing_to_progress? : super
|
97
98
|
end
|
98
99
|
|
99
|
-
def validate_definition(
|
100
|
+
def validate_definition(*, **)
|
100
101
|
super
|
101
102
|
|
102
103
|
unless REQUIRED_ROLLOUT_TYPES.include?(required_rollout) || percent?(required_rollout)
|
@@ -190,7 +191,7 @@ module Krane
|
|
190
191
|
def min_available_replicas
|
191
192
|
if percent?(required_rollout)
|
192
193
|
(desired_replicas * required_rollout.to_i / 100.0).ceil
|
193
|
-
elsif max_unavailable =~ /%/
|
194
|
+
elsif max_unavailable.is_a?(String) && max_unavailable =~ /%/
|
194
195
|
(desired_replicas * (100 - max_unavailable.to_i) / 100.0).ceil
|
195
196
|
else
|
196
197
|
desired_replicas - max_unavailable.to_i
|
@@ -219,14 +219,7 @@ module Krane
|
|
219
219
|
limbo_reason = @status.dig("state", "waiting", "reason")
|
220
220
|
limbo_message = @status.dig("state", "waiting", "message")
|
221
221
|
|
222
|
-
if
|
223
|
-
# ref: https://github.com/kubernetes/kubernetes/blob/562e721ece8a16e05c7e7d6bdd6334c910733ab2/pkg/kubelet/dockershim/docker_container.go#L353
|
224
|
-
exit_code = @status.dig('lastState', 'terminated', 'exitCode')
|
225
|
-
"Failed to start (exit #{exit_code}): #{@status.dig('lastState', 'terminated', 'message')}"
|
226
|
-
elsif @status.dig("state", "terminated", "reason") == "ContainerCannotRun"
|
227
|
-
exit_code = @status.dig('state', 'terminated', 'exitCode')
|
228
|
-
"Failed to start (exit #{exit_code}): #{@status.dig('state', 'terminated', 'message')}"
|
229
|
-
elsif limbo_reason == "CrashLoopBackOff"
|
222
|
+
if limbo_reason == "CrashLoopBackOff"
|
230
223
|
exit_code = @status.dig('lastState', 'terminated', 'exitCode')
|
231
224
|
"Crashing repeatedly (exit #{exit_code}). See logs for more information."
|
232
225
|
elsif limbo_reason == "ErrImagePull" && limbo_message.match(/not found/i)
|
@@ -234,6 +227,17 @@ module Krane
|
|
234
227
|
"Did you wait for it to be built and pushed to the registry before deploying?"
|
235
228
|
elsif limbo_reason == "CreateContainerConfigError"
|
236
229
|
"Failed to generate container configuration: #{limbo_message}"
|
230
|
+
elsif @status.dig("lastState", "terminated", "reason") == "ContainerCannotRun"
|
231
|
+
# ref: https://github.com/kubernetes/kubernetes/blob/562e721ece8a16e05c7e7d6bdd6334c910733ab2/pkg/kubelet/dockershim/docker_container.go#L353
|
232
|
+
exit_code = @status.dig('lastState', 'terminated', 'exitCode')
|
233
|
+
# We've observed failures here that are actually issues with the node or kube infra, and not with the
|
234
|
+
# container. These issues have been transient and result in a 128 exit code, so do not treat these as fatal.
|
235
|
+
return if exit_code == 128
|
236
|
+
"Failed to start (exit #{exit_code}): #{@status.dig('lastState', 'terminated', 'message')}"
|
237
|
+
elsif @status.dig("state", "terminated", "reason") == "ContainerCannotRun"
|
238
|
+
exit_code = @status.dig('state', 'terminated', 'exitCode')
|
239
|
+
return if exit_code == 128
|
240
|
+
"Failed to start (exit #{exit_code}): #{@status.dig('state', 'terminated', 'message')}"
|
237
241
|
end
|
238
242
|
end
|
239
243
|
|
@@ -4,6 +4,7 @@ require 'krane/kubernetes_resource/pod_set_base'
|
|
4
4
|
module Krane
|
5
5
|
class ReplicaSet < PodSetBase
|
6
6
|
TIMEOUT = 5.minutes
|
7
|
+
SYNC_DEPENDENCIES = %w(Pod)
|
7
8
|
attr_reader :pods
|
8
9
|
|
9
10
|
def initialize(namespace:, context:, definition:, logger:, statsd_tags: nil,
|
@@ -17,7 +18,7 @@ module Krane
|
|
17
18
|
|
18
19
|
def sync(cache)
|
19
20
|
super
|
20
|
-
@pods =
|
21
|
+
@pods = exists? ? find_pods(cache) : []
|
21
22
|
end
|
22
23
|
|
23
24
|
def status
|
@@ -58,21 +59,6 @@ module Krane
|
|
58
59
|
observed_generation != current_generation
|
59
60
|
end
|
60
61
|
|
61
|
-
def fetch_pods_if_needed(cache)
|
62
|
-
# If the ReplicaSet doesn't exist, its pods won't either
|
63
|
-
return unless exists?
|
64
|
-
# If the status hasn't been updated yet, we're not going to make a determination anyway
|
65
|
-
return if stale_status?
|
66
|
-
# If we don't want any pods at all, we don't need to look for them
|
67
|
-
return if desired_replicas == 0
|
68
|
-
# We only need to fetch pods so that deploy_failed? can check that they aren't ALL bad.
|
69
|
-
# If we can already tell some pods are ok from the RS data, don't bother fetching them (which can be expensive)
|
70
|
-
# Lower numbers here make us more susceptible to being fooled by replicas without probes briefly appearing ready
|
71
|
-
return if ready_replicas > 1
|
72
|
-
|
73
|
-
find_pods(cache)
|
74
|
-
end
|
75
|
-
|
76
62
|
def rollout_data
|
77
63
|
return { "replicas" => 0 } unless exists?
|
78
64
|
{ "replicas" => 0 }.merge(
|