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 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