krane 3.2.0 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +7 -8
- data/krane.gemspec +4 -4
- data/lib/krane/bindings_parser.rb +2 -2
- data/lib/krane/cli/krane.rb +6 -6
- data/lib/krane/cluster_resource_discovery.rb +3 -3
- data/lib/krane/deploy_task.rb +2 -2
- data/lib/krane/ejson_secret_provisioner.rb +4 -4
- data/lib/krane/kubectl.rb +1 -1
- data/lib/krane/kubernetes_resource/pod.rb +1 -0
- data/lib/krane/kubernetes_resource/stateful_set.rb +25 -10
- data/lib/krane/resource_cache.rb +1 -1
- data/lib/krane/resource_deployer.rb +1 -1
- data/lib/krane/rollout_conditions.rb +2 -2
- data/lib/krane/version.rb +1 -1
- metadata +14 -15
- data/lib/krane/oj.rb +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ea6e5f5541819d9404729a0c1f05aae53c4d909817c73349aab761987ea0b368
|
4
|
+
data.tar.gz: '049f3b4cd88f914580475b84e33f3bd216f363f6b5474dd76810ce53f051d4e0'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b860d42eb86ff04e44faf2709ff98c31cc60a2c0c1418088dff894cadcda8b9c85400a17e3db1946211996bd5389bde75d0efc5bb75d12231b6977b89ff23753
|
7
|
+
data.tar.gz: 4345f565b49788844df7ac55978237192990de8689a55cc76b1d48e54aa69fb1ae3f93869d1760a606a9d6d3a3c0c3521d0eef77da414122c6b3b594204f0379
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -155,14 +155,13 @@ If you want dynamic templates, you may render ERB with `krane render` and then p
|
|
155
155
|
- `krane.shopify.io/required-rollout`: Modifies how much of the rollout needs to finish
|
156
156
|
before the deployment is considered successful.
|
157
157
|
- _Compatibility_: Deployment
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
`spec.replicas` * Percent.
|
158
|
+
- `full`: The deployment is successful when all pods in the new `replicaSet` are ready.
|
159
|
+
- `none`: The deployment is successful as soon as the new `replicaSet` is created for the deployment.
|
160
|
+
- `maxUnavailable`: The deploy is successful when minimum availability is reached in the new `replicaSet`.
|
161
|
+
In other words, the number of new pods that must be ready is equal to `spec.replicas` - `strategy.RollingUpdate.maxUnavailable` (converted from percentages by rounding up, if applicable). This option is only valid for deployments that use the `RollingUpdate` strategy.
|
162
|
+
- Percent (e.g. 90%): The deploy is successful when the number of new pods that are ready is equal to `spec.replicas` * Percent.
|
163
|
+
- _Compatibility_: StatefulSet
|
164
|
+
- `full`: The deployment is successful when all pods are ready.
|
166
165
|
- `krane.shopify.io/predeployed`: Causes a Custom Resource to be deployed in the pre-deploy phase.
|
167
166
|
- _Compatibility_: Custom Resource Definition
|
168
167
|
- _Default_: `true`
|
data/krane.gemspec
CHANGED
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
|
|
32
32
|
spec.add_dependency("ejson", "~> 1.0")
|
33
33
|
spec.add_dependency("colorize", "~> 0.8")
|
34
34
|
spec.add_dependency("statsd-instrument", ['>= 2.8', "< 4"])
|
35
|
-
spec.add_dependency("
|
35
|
+
spec.add_dependency("multi_json")
|
36
36
|
spec.add_dependency("concurrent-ruby", "~> 1.1")
|
37
37
|
spec.add_dependency("jsonpath", "~> 1.0")
|
38
38
|
spec.add_dependency("thor", ">= 1.0", "< 2.0")
|
@@ -43,11 +43,11 @@ Gem::Specification.new do |spec|
|
|
43
43
|
spec.add_development_dependency("yard")
|
44
44
|
|
45
45
|
# Test framework
|
46
|
-
spec.add_development_dependency("minitest", "~> 5.
|
46
|
+
spec.add_development_dependency("minitest", "~> 5.19")
|
47
47
|
spec.add_development_dependency("minitest-stub-const", "~> 0.6")
|
48
48
|
spec.add_development_dependency("minitest-reporters")
|
49
|
-
spec.add_development_dependency("mocha", "~> 1
|
50
|
-
spec.add_development_dependency("webmock", "~> 3.
|
49
|
+
spec.add_development_dependency("mocha", "~> 2.1")
|
50
|
+
spec.add_development_dependency("webmock", "~> 3.18")
|
51
51
|
spec.add_development_dependency("timecop")
|
52
52
|
|
53
53
|
# Debugging and analysis
|
@@ -54,14 +54,14 @@ module Krane
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def parse_json(string)
|
57
|
-
bindings =
|
57
|
+
bindings = MultiJson.load(string)
|
58
58
|
|
59
59
|
unless bindings.is_a?(Hash)
|
60
60
|
raise ArgumentError, "Expected JSON data to be a hash."
|
61
61
|
end
|
62
62
|
|
63
63
|
bindings
|
64
|
-
rescue
|
64
|
+
rescue MultiJson::ParseError
|
65
65
|
nil
|
66
66
|
end
|
67
67
|
|
data/lib/krane/cli/krane.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require 'krane'
|
3
|
-
require 'krane/oj'
|
4
|
-
require 'thor'
|
5
|
-
require 'krane/cli/version_command'
|
6
|
-
require 'krane/cli/restart_command'
|
7
|
-
require 'krane/cli/run_command'
|
8
|
-
require 'krane/cli/render_command'
|
9
3
|
require 'krane/cli/deploy_command'
|
10
4
|
require 'krane/cli/global_deploy_command'
|
5
|
+
require 'krane/cli/render_command'
|
6
|
+
require 'krane/cli/restart_command'
|
7
|
+
require 'krane/cli/run_command'
|
8
|
+
require 'krane/cli/version_command'
|
9
|
+
require 'multi_json'
|
10
|
+
require 'thor'
|
11
11
|
|
12
12
|
module Krane
|
13
13
|
module CLI
|
@@ -54,7 +54,7 @@ module Krane
|
|
54
54
|
@api_path_cache["/"] ||= begin
|
55
55
|
raw_json, err, st = kubectl.run("get", "--raw", base_api_path, attempts: 5, use_namespace: false)
|
56
56
|
paths = if st.success?
|
57
|
-
|
57
|
+
MultiJson.load(raw_json)["paths"]
|
58
58
|
else
|
59
59
|
raise FatalKubeAPIError, "Error retrieving raw path /: #{err}"
|
60
60
|
end
|
@@ -66,7 +66,7 @@ module Krane
|
|
66
66
|
@api_path_cache[path] ||= begin
|
67
67
|
raw_json, err, st = kubectl.run("get", "--raw", path, attempts: 2, use_namespace: false)
|
68
68
|
if st.success?
|
69
|
-
|
69
|
+
MultiJson.load(raw_json)
|
70
70
|
else
|
71
71
|
logger.warn("Error retrieving api path: #{err}")
|
72
72
|
{}
|
@@ -92,7 +92,7 @@ module Krane
|
|
92
92
|
raw_json, err, st = kubectl.run("get", "CustomResourceDefinition", output: "json", attempts: 5,
|
93
93
|
use_namespace: false)
|
94
94
|
if st.success?
|
95
|
-
|
95
|
+
MultiJson.load(raw_json)["items"]
|
96
96
|
else
|
97
97
|
raise FatalKubeAPIError, "Error retrieving CustomResourceDefinition: #{err}"
|
98
98
|
end
|
data/lib/krane/deploy_task.rb
CHANGED
@@ -328,7 +328,7 @@ module Krane
|
|
328
328
|
@namespace_definition ||= begin
|
329
329
|
definition, _err, st = kubectl.run("get", "namespace", @namespace, use_namespace: false,
|
330
330
|
log_failure: true, raise_if_not_found: true, attempts: 3, output: 'json')
|
331
|
-
st.success? ?
|
331
|
+
st.success? ? MultiJson.load(definition, symbolize_names: true) : nil
|
332
332
|
end
|
333
333
|
rescue Kubectl::ResourceNotFoundError
|
334
334
|
nil
|
@@ -362,7 +362,7 @@ module Krane
|
|
362
362
|
unless st.success?
|
363
363
|
raise EjsonSecretError, "Error retrieving Secret/#{EjsonSecretProvisioner::EJSON_KEYS_SECRET}: #{err}"
|
364
364
|
end
|
365
|
-
|
365
|
+
MultiJson.load(out)
|
366
366
|
end
|
367
367
|
end
|
368
368
|
|
@@ -117,8 +117,8 @@ module Krane
|
|
117
117
|
|
118
118
|
def load_ejson_from_file
|
119
119
|
return {} unless File.exist?(@ejson_file)
|
120
|
-
|
121
|
-
rescue
|
120
|
+
MultiJson.load(File.read(@ejson_file))
|
121
|
+
rescue MultiJson::ParseError => e
|
122
122
|
raise EjsonSecretError, "Failed to parse encrypted ejson:\n #{e}"
|
123
123
|
end
|
124
124
|
|
@@ -139,8 +139,8 @@ module Krane
|
|
139
139
|
msg = err.presence || out
|
140
140
|
raise EjsonSecretError, msg
|
141
141
|
end
|
142
|
-
|
143
|
-
rescue
|
142
|
+
MultiJson.load(out)
|
143
|
+
rescue MultiJson::ParseError
|
144
144
|
raise EjsonSecretError, "Failed to parse decrypted ejson"
|
145
145
|
end
|
146
146
|
|
data/lib/krane/kubectl.rb
CHANGED
@@ -85,7 +85,7 @@ module Krane
|
|
85
85
|
response, _, status = run("version", output: "json", use_namespace: false, log_failure: true, attempts: 2)
|
86
86
|
raise KubectlError, "Could not retrieve kubectl version info" unless status.success?
|
87
87
|
|
88
|
-
version_data =
|
88
|
+
version_data = MultiJson.load(response)
|
89
89
|
client_version = platform_agnostic_version(version_data.dig("clientVersion", "gitVersion").to_s)
|
90
90
|
server_version = platform_agnostic_version(version_data.dig("serverVersion", "gitVersion").to_s)
|
91
91
|
unless client_version && server_version
|
@@ -5,6 +5,7 @@ module Krane
|
|
5
5
|
TIMEOUT = 10.minutes
|
6
6
|
ONDELETE = 'OnDelete'
|
7
7
|
SYNC_DEPENDENCIES = %w(Pod)
|
8
|
+
REQUIRED_ROLLOUT_TYPES = %w(full).freeze
|
8
9
|
attr_reader :pods
|
9
10
|
|
10
11
|
def sync(cache)
|
@@ -19,25 +20,35 @@ module Krane
|
|
19
20
|
end
|
20
21
|
|
21
22
|
def deploy_succeeded?
|
22
|
-
success = observed_generation == current_generation
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
success = observed_generation == current_generation
|
24
|
+
|
25
|
+
@pods.each do |pod|
|
26
|
+
success &= pod.definition["metadata"]["labels"]["controller-revision-hash"] == status_data['updateRevision']
|
27
|
+
end
|
28
|
+
|
29
|
+
if update_strategy == 'RollingUpdate'
|
30
|
+
success &= status_data['currentRevision'] == status_data['updateRevision']
|
31
|
+
success &= desired_replicas == status_data['readyReplicas'].to_i
|
32
|
+
success &= desired_replicas == status_data['currentReplicas'].to_i
|
33
|
+
|
34
|
+
elsif update_strategy == ONDELETE
|
27
35
|
unless @success_assumption_warning_shown
|
28
36
|
@logger.warn("WARNING: Your StatefulSet's updateStrategy is set to OnDelete, "\
|
29
|
-
"which means
|
30
|
-
"Consider switching to rollingUpdate.")
|
37
|
+
"which means the deployment won't succeed until all pods are updated by deletion.")
|
31
38
|
@success_assumption_warning_shown = true
|
32
39
|
end
|
33
|
-
|
34
|
-
|
40
|
+
|
41
|
+
if required_rollout == 'full'
|
42
|
+
success &= desired_replicas == status_data['readyReplicas'].to_i
|
43
|
+
success &= desired_replicas == status_data['updatedReplicas'].to_i
|
44
|
+
end
|
35
45
|
end
|
46
|
+
|
36
47
|
success
|
37
48
|
end
|
38
49
|
|
39
50
|
def deploy_failed?
|
40
|
-
return false if update_strategy == ONDELETE
|
51
|
+
return false if update_strategy == ONDELETE && required_rollout != 'full'
|
41
52
|
pods.present? && pods.any?(&:deploy_failed?) &&
|
42
53
|
observed_generation == current_generation
|
43
54
|
end
|
@@ -67,5 +78,9 @@ module Krane
|
|
67
78
|
pod_data["metadata"]["ownerReferences"].any? { |ref| ref["uid"] == @instance_data["metadata"]["uid"] } &&
|
68
79
|
@instance_data["status"]["currentRevision"] == pod_data["metadata"]["labels"]["controller-revision-hash"]
|
69
80
|
end
|
81
|
+
|
82
|
+
def required_rollout
|
83
|
+
krane_annotation_value("required-rollout") || nil
|
84
|
+
end
|
70
85
|
end
|
71
86
|
end
|
data/lib/krane/resource_cache.rb
CHANGED
@@ -64,7 +64,7 @@ module Krane
|
|
64
64
|
raise KubectlError unless st.success?
|
65
65
|
|
66
66
|
instances = {}
|
67
|
-
|
67
|
+
MultiJson.load(raw_json)["items"].each do |resource|
|
68
68
|
resource_name = resource.dig("metadata", "name")
|
69
69
|
instances[resource_name] = resource
|
70
70
|
end
|
@@ -252,7 +252,7 @@ module Krane
|
|
252
252
|
# For resources that rely on a generateName attribute, we get the `name` from the result of the call to `create`
|
253
253
|
# We must explicitly set this name value so that the `apply` step for pruning can run successfully
|
254
254
|
if status.success? && resource.uses_generate_name?
|
255
|
-
resource.use_generated_name(
|
255
|
+
resource.use_generated_name(MultiJson.load(out))
|
256
256
|
end
|
257
257
|
|
258
258
|
[err, status]
|
@@ -11,7 +11,7 @@ module Krane
|
|
11
11
|
def from_annotation(conditions_string)
|
12
12
|
return new(default_conditions) if conditions_string.downcase.strip == "true"
|
13
13
|
|
14
|
-
conditions =
|
14
|
+
conditions = MultiJson.load(conditions_string).slice('success_conditions', 'failure_conditions')
|
15
15
|
conditions.deep_symbolize_keys!
|
16
16
|
|
17
17
|
# Create JsonPath objects
|
@@ -26,7 +26,7 @@ module Krane
|
|
26
26
|
end
|
27
27
|
|
28
28
|
new(conditions)
|
29
|
-
rescue
|
29
|
+
rescue MultiJson::ParseError => e
|
30
30
|
raise RolloutConditionsError, "Rollout conditions are not valid JSON: #{e}"
|
31
31
|
rescue StandardError => e
|
32
32
|
raise RolloutConditionsError,
|
data/lib/krane/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: krane
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Katrina Verey
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date: 2023-
|
13
|
+
date: 2023-08-08 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -103,19 +103,19 @@ dependencies:
|
|
103
103
|
- !ruby/object:Gem::Version
|
104
104
|
version: '4'
|
105
105
|
- !ruby/object:Gem::Dependency
|
106
|
-
name:
|
106
|
+
name: multi_json
|
107
107
|
requirement: !ruby/object:Gem::Requirement
|
108
108
|
requirements:
|
109
|
-
- - "
|
109
|
+
- - ">="
|
110
110
|
- !ruby/object:Gem::Version
|
111
|
-
version: '
|
111
|
+
version: '0'
|
112
112
|
type: :runtime
|
113
113
|
prerelease: false
|
114
114
|
version_requirements: !ruby/object:Gem::Requirement
|
115
115
|
requirements:
|
116
|
-
- - "
|
116
|
+
- - ">="
|
117
117
|
- !ruby/object:Gem::Version
|
118
|
-
version: '
|
118
|
+
version: '0'
|
119
119
|
- !ruby/object:Gem::Dependency
|
120
120
|
name: concurrent-ruby
|
121
121
|
requirement: !ruby/object:Gem::Requirement
|
@@ -212,14 +212,14 @@ dependencies:
|
|
212
212
|
requirements:
|
213
213
|
- - "~>"
|
214
214
|
- !ruby/object:Gem::Version
|
215
|
-
version: '5.
|
215
|
+
version: '5.19'
|
216
216
|
type: :development
|
217
217
|
prerelease: false
|
218
218
|
version_requirements: !ruby/object:Gem::Requirement
|
219
219
|
requirements:
|
220
220
|
- - "~>"
|
221
221
|
- !ruby/object:Gem::Version
|
222
|
-
version: '5.
|
222
|
+
version: '5.19'
|
223
223
|
- !ruby/object:Gem::Dependency
|
224
224
|
name: minitest-stub-const
|
225
225
|
requirement: !ruby/object:Gem::Requirement
|
@@ -254,28 +254,28 @@ dependencies:
|
|
254
254
|
requirements:
|
255
255
|
- - "~>"
|
256
256
|
- !ruby/object:Gem::Version
|
257
|
-
version: '1
|
257
|
+
version: '2.1'
|
258
258
|
type: :development
|
259
259
|
prerelease: false
|
260
260
|
version_requirements: !ruby/object:Gem::Requirement
|
261
261
|
requirements:
|
262
262
|
- - "~>"
|
263
263
|
- !ruby/object:Gem::Version
|
264
|
-
version: '1
|
264
|
+
version: '2.1'
|
265
265
|
- !ruby/object:Gem::Dependency
|
266
266
|
name: webmock
|
267
267
|
requirement: !ruby/object:Gem::Requirement
|
268
268
|
requirements:
|
269
269
|
- - "~>"
|
270
270
|
- !ruby/object:Gem::Version
|
271
|
-
version: '3.
|
271
|
+
version: '3.18'
|
272
272
|
type: :development
|
273
273
|
prerelease: false
|
274
274
|
version_requirements: !ruby/object:Gem::Requirement
|
275
275
|
requirements:
|
276
276
|
- - "~>"
|
277
277
|
- !ruby/object:Gem::Version
|
278
|
-
version: '3.
|
278
|
+
version: '3.18'
|
279
279
|
- !ruby/object:Gem::Dependency
|
280
280
|
name: timecop
|
281
281
|
requirement: !ruby/object:Gem::Requirement
|
@@ -487,7 +487,6 @@ files:
|
|
487
487
|
- lib/krane/kubernetes_resource/service_account.rb
|
488
488
|
- lib/krane/kubernetes_resource/stateful_set.rb
|
489
489
|
- lib/krane/label_selector.rb
|
490
|
-
- lib/krane/oj.rb
|
491
490
|
- lib/krane/options_helper.rb
|
492
491
|
- lib/krane/psych_k8s_compatibility.rb
|
493
492
|
- lib/krane/remote_logs.rb
|
@@ -525,7 +524,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
525
524
|
- !ruby/object:Gem::Version
|
526
525
|
version: '0'
|
527
526
|
requirements: []
|
528
|
-
rubygems_version: 3.4.
|
527
|
+
rubygems_version: 3.4.17
|
529
528
|
signing_key:
|
530
529
|
specification_version: 4
|
531
530
|
summary: A command line tool that helps you ship changes to a Kubernetes namespace
|
data/lib/krane/oj.rb
DELETED