krane 3.2.0 → 3.4.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/.github/CODEOWNERS +1 -1
- data/.github/workflows/add-to-project.yml +18 -0
- data/.github/workflows/ci.yml +3 -0
- data/1.0-Upgrade.md +1 -1
- data/CHANGELOG.md +11 -1
- data/CONTRIBUTING.md +4 -4
- data/README.md +14 -14
- 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 +4 -4
- data/lib/krane/ejson_secret_provisioner.rb +4 -4
- data/lib/krane/global_deploy_task.rb +2 -2
- data/lib/krane/kubectl.rb +10 -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 +7 -6
- data/lib/krane/rollout_conditions.rb +2 -2
- data/lib/krane/version.rb +1 -1
- metadata +15 -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: 0a400c15e247a60bf8596665ddf2737abb44c2418358212e689890eb2178956f
|
|
4
|
+
data.tar.gz: '0386e1417ba00c97add6aa7184176785f82d05de5453140a8806540833c85f46'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a8b4c706a3918d6d3b66f098ae03c1e02680d59bef3f8eab34248997bfc11e512206f1b1d1794f50f12965e7a0cffbb2df2293b4639dd28b4b8526db881cf315
|
|
7
|
+
data.tar.gz: 7d113bfa20d8dec893fa3494ea7f55a9bf89c3a59ca7a461e1076c5fed37c2725b495a96efa5034c18b857819c96f5803045dec444a3c205e70f647b162f8106
|
data/.github/CODEOWNERS
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
* @Shopify/
|
|
1
|
+
* @Shopify/infrastructure-tooling
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
name: Project automations
|
|
2
|
+
on:
|
|
3
|
+
issues:
|
|
4
|
+
types:
|
|
5
|
+
- opened
|
|
6
|
+
- reopened
|
|
7
|
+
env:
|
|
8
|
+
PROJECT_URL: https://github.com/orgs/Shopify/projects/2279
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
add-to-project:
|
|
12
|
+
name: Issue or PR opened
|
|
13
|
+
runs-on: shopify-ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/add-to-project@v0.4.0 # https://github.com/actions/add-to-project/tree/v0.4.0
|
|
16
|
+
with:
|
|
17
|
+
project-url: ${{ env.PROJECT_URL }}
|
|
18
|
+
github-token: ${{ secrets.SHOPIFY_GH_ACCESS_TOKEN }}
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -16,10 +16,13 @@ jobs:
|
|
|
16
16
|
- "3.0.4"
|
|
17
17
|
- "2.7.6"
|
|
18
18
|
kubernetes_version:
|
|
19
|
+
- "1.27.3"
|
|
19
20
|
- "1.26.4"
|
|
20
21
|
- "1.24.13"
|
|
21
22
|
- "1.23.17"
|
|
22
23
|
include:
|
|
24
|
+
- kubernetes_version: "1.27.3"
|
|
25
|
+
kind_image: "kindest/node:v1.27.3@sha256:9dd3392d79af1b084671b05bcf65b21de476256ad1dcc853d9f3b10b4ac52dde"
|
|
23
26
|
- kubernetes_version: "1.26.4"
|
|
24
27
|
kind_image: "kindest/node:v1.26.4@sha256:a539833d26264444ab3b8f5e56e23fa3361436445fa23c864e6dec622458858f"
|
|
25
28
|
- kubernetes_version: "1.24.13"
|
data/1.0-Upgrade.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* There are breaking changes in the public API (such as the renaming of the `KubernetesDeploy` namespace to `Krane`, and the change in default values for different arguments of the public interface).
|
|
8
8
|
* StatsD metrics will now be generated with the `krane` prefix.
|
|
9
9
|
* `krane deploy` now considers all namespaced resources eligible for pruning, including
|
|
10
|
-
custom resources. See [blacklist](https://github.com/Shopify/krane/blob/
|
|
10
|
+
custom resources. See [blacklist](https://github.com/Shopify/krane/blob/main/lib/krane/cluster_resource_discovery.rb#L20) for exceptions.
|
|
11
11
|
* `kubernetes-deploy` (now `krane deploy`) / `DeployTask` can no longer deploy global (non-namespaced) resources. A new command called `krane global-deploy` and a related class called `GlobalDeployTask` were added to replace that feature.
|
|
12
12
|
* `krane deploy` will not render erb templates. Use `krane render | krane deploy --stdin` to reproduce this functionality.
|
|
13
13
|
* If you attempt to install two gems that have conflicting executables, `gem install` will warn you but the most recently installed one will win.
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
## next
|
|
2
2
|
|
|
3
|
+
# 3.4.0
|
|
4
|
+
|
|
5
|
+
- Use `prune-allowlist` instead of `prune-whitelist` for 1.26+ clusters. Clusters running 1.25 or less will continue to use `--prune-whitelist`. [#940](https://github.com/Shopify/krane/pull/940)
|
|
6
|
+
|
|
7
|
+
## 3.3.0
|
|
8
|
+
|
|
9
|
+
*Enhancements*
|
|
10
|
+
|
|
11
|
+
- Enable detection of successful StatefulSet deploys when the `updateStrategy` is `onDelete`, behind an annotation. [#926](https://github.com/Shopify/krane/pull/926)
|
|
12
|
+
|
|
3
13
|
## 3.2.0
|
|
4
14
|
|
|
5
15
|
*Enhancements*
|
|
@@ -282,7 +292,7 @@ It seems an issue when too many pods are referencing the same secret/configmap h
|
|
|
282
292
|
# 1.0.0
|
|
283
293
|
|
|
284
294
|
We've renamed the gem and cli to Krane.
|
|
285
|
-
See our [migration guide](https://github.com/Shopify/krane/blob/
|
|
295
|
+
See our [migration guide](https://github.com/Shopify/krane/blob/main/1.0-Upgrade.md) to help navigate the breaking changes.
|
|
286
296
|
|
|
287
297
|
## 1.0.0.pre.2
|
|
288
298
|
|
data/CONTRIBUTING.md
CHANGED
|
@@ -22,7 +22,7 @@ The following is a set of guidelines for contributing to krane. Please take a mo
|
|
|
22
22
|
* [CI (External contributors)](#ci-external-contributors)
|
|
23
23
|
## Code of Conduct
|
|
24
24
|
|
|
25
|
-
This project and everyone participating in it are governed by the [Code of Conduct](https://github.com/Shopify/krane/blob/
|
|
25
|
+
This project and everyone participating in it are governed by the [Code of Conduct](https://github.com/Shopify/krane/blob/main/CODE_OF_CONDUCT.md).
|
|
26
26
|
By participating, you are expected to uphold this code. Please report unacceptable
|
|
27
27
|
behavior to [krane@shopify.com](mailto:krane@shopify.com).
|
|
28
28
|
|
|
@@ -95,9 +95,9 @@ This gem uses subclasses of `KubernetesResource` to implement custom success/fai
|
|
|
95
95
|
* `deploy_failed?`
|
|
96
96
|
3. Adjust the `TIMEOUT` constant to an appropriate value for this type.
|
|
97
97
|
4. Add the new class to list of resources in
|
|
98
|
-
[`deploy_task.rb`](https://github.com/Shopify/krane/blob/
|
|
99
|
-
5. Add the new resource to the [prune whitelist](https://github.com/Shopify/krane/blob/
|
|
100
|
-
6. Add a basic example of the type to the hello-cloud [fixture set](https://github.com/Shopify/krane/tree/
|
|
98
|
+
[`deploy_task.rb`](https://github.com/Shopify/krane/blob/main/lib/krane/deploy_task.rb#L8)
|
|
99
|
+
5. Add the new resource to the [prune whitelist](https://github.com/Shopify/krane/blob/main/lib/krane/deploy_task.rb#L81)
|
|
100
|
+
6. Add a basic example of the type to the hello-cloud [fixture set](https://github.com/Shopify/krane/tree/main/test/fixtures/hello-cloud) and appropriate assertions to `#assert_all_up` in [`hello_cloud.rb`](https://github.com/Shopify/krane/blob/main/test/helpers/fixture_sets/hello_cloud.rb). This will get you coverage in several existing tests, such as `test_full_hello_cloud_set_deploy_succeeds`.
|
|
101
101
|
7. Add tests for any edge cases you foresee.
|
|
102
102
|
|
|
103
103
|
### Contributor License Agreement
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# krane [](https://buildkite.com/shopify/krane)
|
|
2
2
|
|
|
3
|
-
> This project used to be called `kubernetes-deploy`. Check out our [migration guide](https://github.com/Shopify/krane/blob/
|
|
3
|
+
> This project used to be called `kubernetes-deploy`. Check out our [migration guide](https://github.com/Shopify/krane/blob/main/1.0-Upgrade.md) for more information including details about breaking changes.
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
`krane` is a command line tool that helps you ship changes to a Kubernetes namespace and understand the result. At Shopify, we use it within our much-beloved, open-source [Shipit](https://github.com/Shopify/shipit-engine#kubernetes) deployment app.
|
|
@@ -93,6 +93,7 @@ Krane provides support for official upstream supported versions [Kubernetes](htt
|
|
|
93
93
|
| 1.24 | Yes | -- |
|
|
94
94
|
| 1.25 | No | -- |
|
|
95
95
|
| 1.26 | Yes | -- |
|
|
96
|
+
| 1.27 | Yes | -- |
|
|
96
97
|
|
|
97
98
|
## Installation
|
|
98
99
|
|
|
@@ -155,14 +156,13 @@ If you want dynamic templates, you may render ERB with `krane render` and then p
|
|
|
155
156
|
- `krane.shopify.io/required-rollout`: Modifies how much of the rollout needs to finish
|
|
156
157
|
before the deployment is considered successful.
|
|
157
158
|
- _Compatibility_: Deployment
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
`spec.replicas` * Percent.
|
|
159
|
+
- `full`: The deployment is successful when all pods in the new `replicaSet` are ready.
|
|
160
|
+
- `none`: The deployment is successful as soon as the new `replicaSet` is created for the deployment.
|
|
161
|
+
- `maxUnavailable`: The deploy is successful when minimum availability is reached in the new `replicaSet`.
|
|
162
|
+
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.
|
|
163
|
+
- Percent (e.g. 90%): The deploy is successful when the number of new pods that are ready is equal to `spec.replicas` * Percent.
|
|
164
|
+
- _Compatibility_: StatefulSet
|
|
165
|
+
- `full`: The deployment is successful when all pods are ready.
|
|
166
166
|
- `krane.shopify.io/predeployed`: Causes a Custom Resource to be deployed in the pre-deploy phase.
|
|
167
167
|
- _Compatibility_: Custom Resource Definition
|
|
168
168
|
- _Default_: `true`
|
|
@@ -337,7 +337,7 @@ status:
|
|
|
337
337
|
|
|
338
338
|
### Deploy walkthrough
|
|
339
339
|
|
|
340
|
-
Let's walk through what happens when you run the `deploy` task with [this directory of templates](https://github.com/Shopify/krane/tree/
|
|
340
|
+
Let's walk through what happens when you run the `deploy` task with [this directory of templates](https://github.com/Shopify/krane/tree/main/test/fixtures/hello-cloud). This particular example uses ERB templates as well, so we'll use the [krane render](#krane-render) task to achieve that.
|
|
341
341
|
|
|
342
342
|
You can test this out for yourself by running the following command:
|
|
343
343
|
|
|
@@ -404,7 +404,7 @@ In this phase, we:
|
|
|
404
404
|
|
|
405
405
|
Just like in the previous phase, we essentially run `kubectl apply` on those templates and periodically check the cluster for the current status of each resource so we can display error or success information.
|
|
406
406
|
|
|
407
|
-
If pruning is enabled (which, again, is the default), any [kind not listed in the blacklist](https://github.com/Shopify/krane/blob/
|
|
407
|
+
If pruning is enabled (which, again, is the default), any [kind not listed in the blacklist](https://github.com/Shopify/krane/blob/main/lib/krane/cluster_resource_discovery.rb#L20) that we can find in the namespace but not in the templates will be removed. A particular message about pruning will be printed in the next phase if any resource matches this criteria.
|
|
408
408
|
|
|
409
409
|
#### Result
|
|
410
410
|
|
|
@@ -654,13 +654,13 @@ This is a limitation of the current implementation.
|
|
|
654
654
|
# Contributing
|
|
655
655
|
|
|
656
656
|
We :heart: contributors! To make it easier for you and us we've written a
|
|
657
|
-
[Contributing Guide](https://github.com/Shopify/krane/blob/
|
|
657
|
+
[Contributing Guide](https://github.com/Shopify/krane/blob/main/CONTRIBUTING.md)
|
|
658
658
|
|
|
659
659
|
|
|
660
660
|
You can also reach out to us on our slack channel, #krane, at https://kubernetes.slack.com. All are welcome!
|
|
661
661
|
|
|
662
662
|
## Code of Conduct
|
|
663
|
-
Everyone is expected to follow our [Code of Conduct](https://github.com/Shopify/krane/blob/
|
|
663
|
+
Everyone is expected to follow our [Code of Conduct](https://github.com/Shopify/krane/blob/main/CODE_OF_CONDUCT.md).
|
|
664
664
|
|
|
665
665
|
|
|
666
666
|
# License
|
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
|
@@ -77,7 +77,7 @@ module Krane
|
|
|
77
77
|
Hash[before_crs + crs + after_crs]
|
|
78
78
|
end
|
|
79
79
|
|
|
80
|
-
def
|
|
80
|
+
def prune_allowlist
|
|
81
81
|
cluster_resource_discoverer.prunable_resources(namespaced: true)
|
|
82
82
|
end
|
|
83
83
|
|
|
@@ -192,7 +192,7 @@ module Krane
|
|
|
192
192
|
|
|
193
193
|
def resource_deployer
|
|
194
194
|
@resource_deployer ||= Krane::ResourceDeployer.new(task_config: @task_config,
|
|
195
|
-
|
|
195
|
+
prune_allowlist: prune_allowlist, global_timeout: @global_timeout,
|
|
196
196
|
selector: @selector, statsd_tags: statsd_tags, current_sha: @current_sha)
|
|
197
197
|
end
|
|
198
198
|
|
|
@@ -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
|
|
|
@@ -108,7 +108,7 @@ module Krane
|
|
|
108
108
|
|
|
109
109
|
def deploy!(resources, verify_result, prune)
|
|
110
110
|
resource_deployer = ResourceDeployer.new(task_config: @task_config,
|
|
111
|
-
|
|
111
|
+
prune_allowlist: prune_allowlist, global_timeout: @global_timeout,
|
|
112
112
|
selector: @selector, statsd_tags: statsd_tags)
|
|
113
113
|
resource_deployer.deploy!(resources, verify_result, prune)
|
|
114
114
|
end
|
|
@@ -194,7 +194,7 @@ module Krane
|
|
|
194
194
|
@kubectl ||= Kubectl.new(task_config: @task_config, log_failure_by_default: true)
|
|
195
195
|
end
|
|
196
196
|
|
|
197
|
-
def
|
|
197
|
+
def prune_allowlist
|
|
198
198
|
cluster_resource_discoverer.prunable_resources(namespaced: false)
|
|
199
199
|
end
|
|
200
200
|
|
data/lib/krane/kubectl.rb
CHANGED
|
@@ -12,6 +12,7 @@ module Krane
|
|
|
12
12
|
DEFAULT_TIMEOUT = 15
|
|
13
13
|
MAX_RETRY_DELAY = 16
|
|
14
14
|
SERVER_DRY_RUN_MIN_VERSION = "1.13"
|
|
15
|
+
ALLOW_LIST_MIN_VERSION = "1.26"
|
|
15
16
|
|
|
16
17
|
class ResourceNotFoundError < StandardError; end
|
|
17
18
|
|
|
@@ -85,7 +86,7 @@ module Krane
|
|
|
85
86
|
response, _, status = run("version", output: "json", use_namespace: false, log_failure: true, attempts: 2)
|
|
86
87
|
raise KubectlError, "Could not retrieve kubectl version info" unless status.success?
|
|
87
88
|
|
|
88
|
-
version_data =
|
|
89
|
+
version_data = MultiJson.load(response)
|
|
89
90
|
client_version = platform_agnostic_version(version_data.dig("clientVersion", "gitVersion").to_s)
|
|
90
91
|
server_version = platform_agnostic_version(version_data.dig("serverVersion", "gitVersion").to_s)
|
|
91
92
|
unless client_version && server_version
|
|
@@ -112,6 +113,14 @@ module Krane
|
|
|
112
113
|
"--dry-run=server"
|
|
113
114
|
end
|
|
114
115
|
|
|
116
|
+
def allowlist_flag
|
|
117
|
+
if client_version >= Gem::Version.new(ALLOW_LIST_MIN_VERSION)
|
|
118
|
+
"--prune-allowlist"
|
|
119
|
+
else
|
|
120
|
+
"--prune-whitelist"
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
115
124
|
private
|
|
116
125
|
|
|
117
126
|
def build_command_from_options(args, use_namespace, use_context, output)
|
|
@@ -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
|
|
@@ -11,9 +11,9 @@ module Krane
|
|
|
11
11
|
delegate :logger, to: :@task_config
|
|
12
12
|
attr_reader :statsd_tags
|
|
13
13
|
|
|
14
|
-
def initialize(task_config:,
|
|
14
|
+
def initialize(task_config:, prune_allowlist:, global_timeout:, current_sha: nil, selector:, statsd_tags:)
|
|
15
15
|
@task_config = task_config
|
|
16
|
-
@
|
|
16
|
+
@prune_allowlist = prune_allowlist
|
|
17
17
|
@global_timeout = global_timeout
|
|
18
18
|
@current_sha = current_sha
|
|
19
19
|
@selector = selector
|
|
@@ -102,7 +102,7 @@ module Krane
|
|
|
102
102
|
# Apply can be done in one large batch, the rest have to be done individually
|
|
103
103
|
applyables, individuals = resources.partition { |r| r.deploy_method == :apply }
|
|
104
104
|
# Prunable resources should also applied so that they can be pruned
|
|
105
|
-
pruneable_types = @
|
|
105
|
+
pruneable_types = @prune_allowlist.map { |t| t.split("/").last }
|
|
106
106
|
applyables += individuals.select { |r| pruneable_types.include?(r.type) && !r.deploy_method_override }
|
|
107
107
|
|
|
108
108
|
individuals.each do |individual_resource|
|
|
@@ -147,14 +147,15 @@ module Krane
|
|
|
147
147
|
r.deploy_started_at = Time.now.utc unless dry_run
|
|
148
148
|
end
|
|
149
149
|
command.push("-f", tmp_dir)
|
|
150
|
-
if prune && @
|
|
150
|
+
if prune && @prune_allowlist.present?
|
|
151
151
|
command.push("--prune")
|
|
152
152
|
if @selector
|
|
153
153
|
command.push("--selector", @selector.to_s)
|
|
154
154
|
else
|
|
155
155
|
command.push("--all")
|
|
156
156
|
end
|
|
157
|
-
|
|
157
|
+
allow_list_flag = kubectl.allowlist_flag
|
|
158
|
+
@prune_allowlist.each { |type| command.push("#{allow_list_flag}=#{type}") }
|
|
158
159
|
end
|
|
159
160
|
|
|
160
161
|
command.push(kubectl.dry_run_flag) if dry_run
|
|
@@ -252,7 +253,7 @@ module Krane
|
|
|
252
253
|
# For resources that rely on a generateName attribute, we get the `name` from the result of the call to `create`
|
|
253
254
|
# We must explicitly set this name value so that the `apply` step for pruning can run successfully
|
|
254
255
|
if status.success? && resource.uses_generate_name?
|
|
255
|
-
resource.use_generated_name(
|
|
256
|
+
resource.use_generated_name(MultiJson.load(out))
|
|
256
257
|
end
|
|
257
258
|
|
|
258
259
|
[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.4.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-12-13 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
|
|
@@ -414,6 +414,7 @@ files:
|
|
|
414
414
|
- ".github/CODEOWNERS"
|
|
415
415
|
- ".github/ISSUE_TEMPLATE.md"
|
|
416
416
|
- ".github/pull_request_template.md"
|
|
417
|
+
- ".github/workflows/add-to-project.yml"
|
|
417
418
|
- ".github/workflows/ci.yml"
|
|
418
419
|
- ".github/workflows/cla.yml"
|
|
419
420
|
- ".gitignore"
|
|
@@ -487,7 +488,6 @@ files:
|
|
|
487
488
|
- lib/krane/kubernetes_resource/service_account.rb
|
|
488
489
|
- lib/krane/kubernetes_resource/stateful_set.rb
|
|
489
490
|
- lib/krane/label_selector.rb
|
|
490
|
-
- lib/krane/oj.rb
|
|
491
491
|
- lib/krane/options_helper.rb
|
|
492
492
|
- lib/krane/psych_k8s_compatibility.rb
|
|
493
493
|
- lib/krane/remote_logs.rb
|
|
@@ -525,7 +525,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
525
525
|
- !ruby/object:Gem::Version
|
|
526
526
|
version: '0'
|
|
527
527
|
requirements: []
|
|
528
|
-
rubygems_version: 3.4.
|
|
528
|
+
rubygems_version: 3.4.22
|
|
529
529
|
signing_key:
|
|
530
530
|
specification_version: 4
|
|
531
531
|
summary: A command line tool that helps you ship changes to a Kubernetes namespace
|
data/lib/krane/oj.rb
DELETED