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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c1c5ae5aab30f6f9065bdf415b4fe94b7b82c8c0a05aecc582a5363349221be8
4
- data.tar.gz: 79d0aefc5abb7671c5c366a02648e183589d1cb90991912f381ac0b6a46c5af6
3
+ metadata.gz: ea6e5f5541819d9404729a0c1f05aae53c4d909817c73349aab761987ea0b368
4
+ data.tar.gz: '049f3b4cd88f914580475b84e33f3bd216f363f6b5474dd76810ce53f051d4e0'
5
5
  SHA512:
6
- metadata.gz: 33c08fdcb4e09e571667872ea761f046977516e1d882d29638faf54f9f58b00ae0534de616a5f304a7231f2820c2a6938ae7a3eaea761987c619b4f6ffc13693
7
- data.tar.gz: 96d52d7e49b0d50bd12e6c28f8ec65e3db86e3b66704149a6ef7756119a168ca4326d0e7aeb897489a2a04a8a4d0e56e7ca0b6254d88e48e682b134ee7b921a9
6
+ metadata.gz: b860d42eb86ff04e44faf2709ff98c31cc60a2c0c1418088dff894cadcda8b9c85400a17e3db1946211996bd5389bde75d0efc5bb75d12231b6977b89ff23753
7
+ data.tar.gz: 4345f565b49788844df7ac55978237192990de8689a55cc76b1d48e54aa69fb1ae3f93869d1760a606a9d6d3a3c0c3521d0eef77da414122c6b3b594204f0379
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  ## next
2
2
 
3
+ ## 3.3.0
4
+
5
+ *Enhancements*
6
+
7
+ - Enable detection of successful StatefulSet deploys when the `updateStrategy` is `onDelete`, behind an annotation. [#926](https://github.com/Shopify/krane/pull/926)
8
+
3
9
  ## 3.2.0
4
10
 
5
11
  *Enhancements*
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
- - `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`
162
- (converted from percentages by rounding up, if applicable). This option is only valid for deployments
163
- that use the `RollingUpdate` strategy.
164
- - Percent (e.g. 90%): The deploy is successful when the number of new pods that are ready is equal to
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("oj", "~> 3.0")
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.12")
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.5")
50
- spec.add_development_dependency("webmock", "~> 3.0")
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 = JSON.parse(string)
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 JSON::ParserError
64
+ rescue MultiJson::ParseError
65
65
  nil
66
66
  end
67
67
 
@@ -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
- JSON.parse(raw_json)["paths"]
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
- JSON.parse(raw_json)
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
- JSON.parse(raw_json)["items"]
95
+ MultiJson.load(raw_json)["items"]
96
96
  else
97
97
  raise FatalKubeAPIError, "Error retrieving CustomResourceDefinition: #{err}"
98
98
  end
@@ -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? ? JSON.parse(definition, symbolize_names: true) : nil
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
- JSON.parse(out)
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
- JSON.parse(File.read(@ejson_file))
121
- rescue JSON::ParserError => e
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
- JSON.parse(out)
143
- rescue JSON::ParserError
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 = JSON.parse(response)
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
@@ -10,6 +10,7 @@ module Krane
10
10
  )
11
11
 
12
12
  attr_accessor :stream_logs
13
+ attr_reader :definition
13
14
 
14
15
  def initialize(namespace:, context:, definition:, logger:,
15
16
  statsd_tags: nil, parent: nil, deploy_started_at: nil, stream_logs: false)
@@ -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
- desired_replicas == status_data['readyReplicas'].to_i &&
24
- status_data['currentRevision'] == status_data['updateRevision']
25
- if update_strategy == ONDELETE
26
- # Gem cannot monitor update since it doesn't occur until delete
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 updates will not be applied until its pods are deleted. "\
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
- else
34
- success &= desired_replicas == status_data['currentReplicas'].to_i
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
@@ -64,7 +64,7 @@ module Krane
64
64
  raise KubectlError unless st.success?
65
65
 
66
66
  instances = {}
67
- JSON.parse(raw_json)["items"].each do |resource|
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(JSON.parse(out))
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 = JSON.parse(conditions_string).slice('success_conditions', 'failure_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 JSON::ParserError => e
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
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Krane
3
- VERSION = "3.2.0"
3
+ VERSION = "3.3.0"
4
4
  end
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.2.0
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-06-14 00:00:00.000000000 Z
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: oj
106
+ name: multi_json
107
107
  requirement: !ruby/object:Gem::Requirement
108
108
  requirements:
109
- - - "~>"
109
+ - - ">="
110
110
  - !ruby/object:Gem::Version
111
- version: '3.0'
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: '3.0'
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.12'
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.12'
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.5'
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.5'
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.0'
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.0'
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.13
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
@@ -1,4 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'oj'
3
-
4
- Oj.mimic_JSON