krane 3.2.0 → 3.3.0
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 +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