krane 1.0.0 → 1.1.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/.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(
|