krane 2.1.3 → 2.1.4
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/.rubocop-http---shopify-github-io-ruby-style-guide-rubocop-yml +1 -0
- data/.shopify-build/krane.yml +20 -6
- data/CHANGELOG.md +10 -0
- data/README.md +2 -2
- data/bin/ci +1 -2
- data/dev.yml +1 -1
- data/krane.gemspec +2 -2
- data/lib/krane/cli/krane.rb +1 -1
- data/lib/krane/cluster_resource_discovery.rb +21 -4
- data/lib/krane/common.rb +0 -1
- data/lib/krane/deploy_task.rb +11 -3
- data/lib/krane/ejson_secret_provisioner.rb +1 -1
- data/lib/krane/global_deploy_task.rb +1 -1
- data/lib/krane/kubectl.rb +8 -0
- data/lib/krane/kubernetes_resource.rb +8 -3
- data/lib/krane/kubernetes_resource/deployment.rb +2 -0
- data/lib/krane/resource_deployer.rb +15 -6
- data/lib/krane/runner_task.rb +1 -1
- data/lib/krane/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ae8bb4b0c7f920136990847601e19c7767075a89ead99781213feaf309d623d
|
4
|
+
data.tar.gz: 90ad58122ca788ebd4010e62e624c0d73a0c153e48c942673e244e7fbb4ccb32
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7e09bdb58b4bca4380b77bb10589a2e5b57aa31e9d8838c4b6efc68ccbf58b5af84c360a1a2710564164e4d6f19419cd38d7b3952559c56d5f7dc026d432a194
|
7
|
+
data.tar.gz: 659649bf0d0cfbe04d3fad0f32f3a05cc6ed9e117ca0755bf808d898b60dbf0d5be88cad609de1589cd93eb2b808e6cc9994a73f7b21267920b679b71afd138e
|
data/.shopify-build/krane.yml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
containers:
|
2
2
|
default:
|
3
|
-
docker: circleci/ruby:2.
|
3
|
+
docker: circleci/ruby:2.6.6
|
4
4
|
|
5
5
|
steps:
|
6
6
|
- label: Lint
|
@@ -8,14 +8,29 @@ steps:
|
|
8
8
|
run:
|
9
9
|
- bundle: ~
|
10
10
|
- bundle exec rubocop
|
11
|
-
- label: 'Run Test Suite (:kubernetes: 1.
|
11
|
+
- label: 'Run Test Suite (:kubernetes: 1.20-latest :ruby: 3.0)'
|
12
12
|
command: bin/ci
|
13
13
|
agents:
|
14
14
|
queue: k8s-ci
|
15
15
|
env:
|
16
16
|
LOGGING_LEVEL: "4"
|
17
|
-
KUBERNETES_VERSION: v1.
|
17
|
+
KUBERNETES_VERSION: v1.20-latest
|
18
|
+
RUBY_VERSION: "3.0"
|
19
|
+
- label: 'Run Test Suite (:kubernetes: 1.19-latest :ruby: 2.7)'
|
20
|
+
command: bin/ci
|
21
|
+
agents:
|
22
|
+
queue: k8s-ci
|
23
|
+
env:
|
24
|
+
LOGGING_LEVEL: "4"
|
25
|
+
KUBERNETES_VERSION: v1.19-latest
|
18
26
|
RUBY_VERSION: "2.7"
|
27
|
+
- label: 'Run Test Suite (:kubernetes: 1.18-latest)'
|
28
|
+
command: bin/ci
|
29
|
+
agents:
|
30
|
+
queue: k8s-ci
|
31
|
+
env:
|
32
|
+
LOGGING_LEVEL: "4"
|
33
|
+
KUBERNETES_VERSION: v1.18-latest
|
19
34
|
- label: 'Run Test Suite (:kubernetes: 1.17-latest)'
|
20
35
|
command: bin/ci
|
21
36
|
agents:
|
@@ -23,14 +38,13 @@ steps:
|
|
23
38
|
env:
|
24
39
|
LOGGING_LEVEL: "4"
|
25
40
|
KUBERNETES_VERSION: v1.17-latest
|
26
|
-
- label: 'Run Test Suite (:kubernetes: 1.16
|
41
|
+
- label: 'Run Test Suite (:kubernetes: 1.16-latest)'
|
27
42
|
command: bin/ci
|
28
43
|
agents:
|
29
44
|
queue: k8s-ci
|
30
45
|
env:
|
31
46
|
LOGGING_LEVEL: "4"
|
32
|
-
|
33
|
-
KUBERNETES_VERSION: v1.16.12
|
47
|
+
KUBERNETES_VERSION: v1.16-latest
|
34
48
|
- label: 'Run Test Suite (:kubernetes: 1.15-latest)'
|
35
49
|
command: bin/ci
|
36
50
|
agents:
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
## next
|
2
2
|
|
3
|
+
## 2.1.4
|
4
|
+
|
5
|
+
*Enhancements*
|
6
|
+
- Attempt to batch run server-side apply in validation phase instead of dry-running each resource individually [#781](https://github.com/Shopify/krane/pull/781).
|
7
|
+
- Evaluate progress condition only after progress deadline seconds have passed since deploy invocation [#765](https://github.com/Shopify/krane/pull/765).
|
8
|
+
|
9
|
+
*Other*
|
10
|
+
- Dropped support for Ruby 2.5 due to EoL. [#782](https://github.com/Shopify/krane/pull/782).
|
11
|
+
- Only patch JSON when run as CLI, not as library [#779](https://github.com/Shopify/krane/pull/779).
|
12
|
+
|
3
13
|
## 2.1.3
|
4
14
|
|
5
15
|
- Add version exception for ServiceNetworkEndpointGroup (GKE resource) [#768](https://github.com/Shopify/krane/pull/768)
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# krane [](https://buildkite.com/shopify/krane)
|
1
|
+
# krane [](https://buildkite.com/shopify/krane)
|
2
2
|
|
3
3
|
> This project used to be called `kubernetes-deploy`. Check out our [migration guide](https://github.com/Shopify/krane/blob/master/1.0-Upgrade.md) for more information including details about breaking changes.
|
4
4
|
|
@@ -73,7 +73,7 @@ If you need the ability to render dynamic values in templates before deploying,
|
|
73
73
|
|
74
74
|
## Prerequisites
|
75
75
|
|
76
|
-
* Ruby 2.
|
76
|
+
* Ruby 2.6+
|
77
77
|
* Your cluster must be running Kubernetes v1.15.0 or higher<sup>1</sup>
|
78
78
|
|
79
79
|
<sup>1</sup> We run integration tests against these Kubernetes versions. You can find our
|
data/bin/ci
CHANGED
@@ -12,10 +12,9 @@ docker run --rm \
|
|
12
12
|
-v "$PWD":/usr/src/app \
|
13
13
|
-v "/usr/bin/kubectl":"/usr/bin/kubectl" \
|
14
14
|
-e CI=1 \
|
15
|
-
-e CODECOV_TOKEN=$CODECOV_TOKEN \
|
16
15
|
-e COVERAGE=1 \
|
17
16
|
-e VERBOSE=1 \
|
18
17
|
-e PARALLELISM=$PARALLELISM \
|
19
18
|
-w /usr/src/app \
|
20
|
-
ruby:"${RUBY_VERSION:-2.
|
19
|
+
ruby:"${RUBY_VERSION:-2.6.6}" \
|
21
20
|
bin/test
|
data/dev.yml
CHANGED
data/krane.gemspec
CHANGED
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
|
|
25
25
|
|
26
26
|
spec.metadata['allowed_push_host'] = "https://rubygems.org"
|
27
27
|
|
28
|
-
spec.required_ruby_version = '>= 2.
|
28
|
+
spec.required_ruby_version = '>= 2.6.0'
|
29
29
|
spec.add_dependency("activesupport", ">= 5.0")
|
30
30
|
spec.add_dependency("kubeclient", "~> 4.3")
|
31
31
|
spec.add_dependency("googleauth", "~> 0.8")
|
@@ -57,5 +57,5 @@ Gem::Specification.new do |spec|
|
|
57
57
|
spec.add_development_dependency("ruby-prof")
|
58
58
|
spec.add_development_dependency("ruby-prof-flamegraph")
|
59
59
|
spec.add_development_dependency("rubocop", "~> 0.89.1")
|
60
|
-
spec.add_development_dependency("
|
60
|
+
spec.add_development_dependency("simplecov")
|
61
61
|
end
|
data/lib/krane/cli/krane.rb
CHANGED
@@ -23,9 +23,7 @@ module Krane
|
|
23
23
|
fetch_resources(namespaced: namespaced).uniq { |r| r['kind'] }.map do |resource|
|
24
24
|
next unless resource['verbs'].one? { |v| v == "delete" }
|
25
25
|
next if black_list.include?(resource['kind'])
|
26
|
-
|
27
|
-
version = version_for_kind(group_versions, resource['kind'])
|
28
|
-
[resource['apigroup'], version, resource['kind']].compact.join("/")
|
26
|
+
gvk_string(api_versions, resource)
|
29
27
|
end.compact
|
30
28
|
end
|
31
29
|
|
@@ -90,7 +88,9 @@ module Krane
|
|
90
88
|
"CSIDriver" => "v1beta1", "Ingress" => "v1beta1",
|
91
89
|
"CSINode" => "v1beta1", "Job" => "v1",
|
92
90
|
"IngressClass" => "v1beta1", "FrontendConfig" => "v1beta1",
|
93
|
-
"ServiceNetworkEndpointGroup" => "v1beta1"
|
91
|
+
"ServiceNetworkEndpointGroup" => "v1beta1",
|
92
|
+
"EnvoyFilter" => "v1alpha3",
|
93
|
+
"TCPIngress" => "v1beta1" }
|
94
94
|
|
95
95
|
pattern = /v(?<major>\d+)(?<pre>alpha|beta)?(?<minor>\d+)?/
|
96
96
|
latest = versions.sort_by do |version|
|
@@ -101,6 +101,23 @@ module Krane
|
|
101
101
|
version_override.fetch(kind, latest)
|
102
102
|
end
|
103
103
|
|
104
|
+
def gvk_string(api_versions, resource)
|
105
|
+
apiversion = resource['apiversion'].to_s
|
106
|
+
|
107
|
+
## In kubectl 1.20 APIGroups was replaced by APIVersions
|
108
|
+
if apiversion.empty?
|
109
|
+
apigroup = resource['apigroup'].to_s
|
110
|
+
group_versions = api_versions[apigroup]
|
111
|
+
|
112
|
+
version = version_for_kind(group_versions, resource['kind'])
|
113
|
+
apigroup = 'core' if apigroup.empty?
|
114
|
+
apiversion = "#{apigroup}/#{version}"
|
115
|
+
end
|
116
|
+
|
117
|
+
apiversion = "core/#{apiversion}" unless apiversion.include?("/")
|
118
|
+
[apiversion, resource['kind']].compact.join("/")
|
119
|
+
end
|
120
|
+
|
104
121
|
def fetch_crds
|
105
122
|
raw_json, err, st = kubectl.run("get", "CustomResourceDefinition", output: "json", attempts: 5,
|
106
123
|
use_namespace: false)
|
data/lib/krane/common.rb
CHANGED
data/lib/krane/deploy_task.rb
CHANGED
@@ -279,13 +279,17 @@ module Krane
|
|
279
279
|
|
280
280
|
def validate_resources(resources)
|
281
281
|
validate_globals(resources)
|
282
|
+
batch_dry_run_success = validate_dry_run(resources)
|
282
283
|
Krane::Concurrency.split_across_threads(resources) do |r|
|
283
|
-
|
284
|
+
# No need to pass in kubectl (and do per-resource dry run apply) if batch dry run succeeded
|
285
|
+
if batch_dry_run_success
|
286
|
+
r.validate_definition(kubectl: nil, selector: @selector, dry_run: false)
|
287
|
+
else
|
288
|
+
r.validate_definition(kubectl: kubectl, selector: @selector, dry_run: true)
|
289
|
+
end
|
284
290
|
end
|
285
|
-
|
286
291
|
failed_resources = resources.select(&:validation_failed?)
|
287
292
|
if failed_resources.present?
|
288
|
-
|
289
293
|
failed_resources.each do |r|
|
290
294
|
content = File.read(r.file_path) if File.file?(r.file_path) && !r.sensitive_template_content?
|
291
295
|
record_invalid_template(logger: @logger, err: r.validation_error_msg,
|
@@ -308,6 +312,10 @@ module Krane
|
|
308
312
|
"Use GlobalDeployTask instead."
|
309
313
|
end
|
310
314
|
|
315
|
+
def validate_dry_run(resources)
|
316
|
+
resource_deployer.dry_run(resources)
|
317
|
+
end
|
318
|
+
|
311
319
|
def namespace_definition
|
312
320
|
@namespace_definition ||= begin
|
313
321
|
definition, _err, st = kubectl.run("get", "namespace", @namespace, use_namespace: false,
|
@@ -53,7 +53,7 @@ module Krane
|
|
53
53
|
secrets.map do |secret_name, secret_spec|
|
54
54
|
validate_secret_spec(secret_name, secret_spec)
|
55
55
|
resource = generate_secret_resource(secret_name, secret_spec["_type"], secret_spec["data"])
|
56
|
-
resource.validate_definition(@kubectl)
|
56
|
+
resource.validate_definition(kubectl: @kubectl)
|
57
57
|
if resource.validation_failed?
|
58
58
|
raise EjsonSecretError, "Resulting resource Secret/#{secret_name} failed validation"
|
59
59
|
end
|
@@ -131,7 +131,7 @@ module Krane
|
|
131
131
|
validate_globals(resources)
|
132
132
|
|
133
133
|
Concurrency.split_across_threads(resources) do |r|
|
134
|
-
r.validate_definition(@kubectl, selector: @selector)
|
134
|
+
r.validate_definition(kubectl: @kubectl, selector: @selector)
|
135
135
|
end
|
136
136
|
|
137
137
|
failed_resources = resources.select(&:validation_failed?)
|
data/lib/krane/kubectl.rb
CHANGED
@@ -100,6 +100,14 @@ module Krane
|
|
100
100
|
server_version >= Gem::Version.new(SERVER_DRY_RUN_MIN_VERSION)
|
101
101
|
end
|
102
102
|
|
103
|
+
def dry_run_flag
|
104
|
+
if server_version >= Gem::Version.new("1.18")
|
105
|
+
"--dry-run=server"
|
106
|
+
else
|
107
|
+
"--server-dry-run"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
103
111
|
private
|
104
112
|
|
105
113
|
def build_command_from_options(args, use_namespace, use_context, output)
|
@@ -134,12 +134,12 @@ module Krane
|
|
134
134
|
Kubeclient::Resource.new(@definition)
|
135
135
|
end
|
136
136
|
|
137
|
-
def validate_definition(kubectl
|
137
|
+
def validate_definition(kubectl:, selector: nil, dry_run: true)
|
138
138
|
@validation_errors = []
|
139
139
|
validate_selector(selector) if selector
|
140
140
|
validate_timeout_annotation
|
141
141
|
validate_deploy_method_override_annotation
|
142
|
-
validate_spec_with_kubectl(kubectl)
|
142
|
+
validate_spec_with_kubectl(kubectl) if dry_run
|
143
143
|
@validation_errors.present?
|
144
144
|
end
|
145
145
|
|
@@ -560,7 +560,12 @@ module Krane
|
|
560
560
|
|
561
561
|
# Server side dry run is only supported on apply
|
562
562
|
def validate_with_server_side_dry_run(kubectl)
|
563
|
-
command =
|
563
|
+
command = if kubectl.server_version >= Gem::Version.new('1.18')
|
564
|
+
["apply", "-f", file_path, "--dry-run=server", "--output=name"]
|
565
|
+
else
|
566
|
+
["apply", "-f", file_path, "--server-dry-run", "--output=name"]
|
567
|
+
end
|
568
|
+
|
564
569
|
kubectl.run(*command, log_failure: false, output_is_sensitive: sensitive_template_content?,
|
565
570
|
retry_whitelist: [:client_timeout, :empty, :context_deadline], attempts: 3)
|
566
571
|
end
|
@@ -155,6 +155,8 @@ module Krane
|
|
155
155
|
|
156
156
|
def deploy_failing_to_progress?
|
157
157
|
return false unless progress_condition.present?
|
158
|
+
# Ensure at least progress_deadline wall clock time has passed before before examining progress_condition
|
159
|
+
return false if deploy_started? && Time.now.utc - @deploy_started_at < progress_deadline
|
158
160
|
|
159
161
|
# This assumes that when the controller bumps the observed generation, it also updates/clears all the status
|
160
162
|
# conditions. Specifically, it assumes the progress condition is immediately set to True if a rollout is starting.
|
@@ -20,6 +20,13 @@ module Krane
|
|
20
20
|
@statsd_tags = statsd_tags
|
21
21
|
end
|
22
22
|
|
23
|
+
def dry_run(resources)
|
24
|
+
apply_all(resources, true, dry_run: true)
|
25
|
+
true
|
26
|
+
rescue FatalDeploymentError
|
27
|
+
false
|
28
|
+
end
|
29
|
+
|
23
30
|
def deploy!(resources, verify_result, prune)
|
24
31
|
if verify_result
|
25
32
|
deploy_all_resources(resources, prune: prune, verify: true)
|
@@ -128,17 +135,17 @@ module Krane
|
|
128
135
|
end
|
129
136
|
end
|
130
137
|
|
131
|
-
def apply_all(resources, prune)
|
138
|
+
def apply_all(resources, prune, dry_run: false)
|
132
139
|
return unless resources.present?
|
133
|
-
|
140
|
+
start = Time.now.utc
|
134
141
|
|
142
|
+
command = %w(apply)
|
135
143
|
Dir.mktmpdir do |tmp_dir|
|
136
144
|
resources.each do |r|
|
137
145
|
FileUtils.symlink(r.file_path, tmp_dir)
|
138
|
-
r.deploy_started_at = Time.now.utc
|
146
|
+
r.deploy_started_at = Time.now.utc unless dry_run
|
139
147
|
end
|
140
148
|
command.push("-f", tmp_dir)
|
141
|
-
|
142
149
|
if prune && @prune_whitelist.present?
|
143
150
|
command.push("--prune")
|
144
151
|
if @selector
|
@@ -149,20 +156,22 @@ module Krane
|
|
149
156
|
@prune_whitelist.each { |type| command.push("--prune-whitelist=#{type}") }
|
150
157
|
end
|
151
158
|
|
159
|
+
command.push(kubectl.dry_run_flag) if dry_run
|
152
160
|
output_is_sensitive = resources.any?(&:sensitive_template_content?)
|
153
161
|
global_mode = resources.all?(&:global?)
|
154
162
|
out, err, st = kubectl.run(*command, log_failure: false, output_is_sensitive: output_is_sensitive,
|
155
163
|
attempts: 2, use_namespace: !global_mode)
|
156
164
|
|
165
|
+
tags = statsd_tags + (dry_run ? ['dry_run:true'] : ['dry_run:false'])
|
166
|
+
Krane::StatsD.client.distribution('apply_all.duration', Krane::StatsD.duration(start), tags: tags)
|
157
167
|
if st.success?
|
158
168
|
log_pruning(out) if prune
|
159
169
|
else
|
160
|
-
record_apply_failure(err, resources: resources)
|
170
|
+
record_apply_failure(err, resources: resources) unless dry_run
|
161
171
|
raise FatalDeploymentError, "Command failed: #{Shellwords.join(command)}"
|
162
172
|
end
|
163
173
|
end
|
164
174
|
end
|
165
|
-
measure_method(:apply_all)
|
166
175
|
|
167
176
|
def log_pruning(kubectl_output)
|
168
177
|
pruned = kubectl_output.scan(/^(.*) pruned$/)
|
data/lib/krane/runner_task.rb
CHANGED
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: 2.1.
|
4
|
+
version: 2.1.4
|
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:
|
13
|
+
date: 2021-01-20 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -375,7 +375,7 @@ dependencies:
|
|
375
375
|
- !ruby/object:Gem::Version
|
376
376
|
version: 0.89.1
|
377
377
|
- !ruby/object:Gem::Dependency
|
378
|
-
name:
|
378
|
+
name: simplecov
|
379
379
|
requirement: !ruby/object:Gem::Requirement
|
380
380
|
requirements:
|
381
381
|
- - ">="
|
@@ -511,7 +511,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
511
511
|
requirements:
|
512
512
|
- - ">="
|
513
513
|
- !ruby/object:Gem::Version
|
514
|
-
version: 2.
|
514
|
+
version: 2.6.0
|
515
515
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
516
516
|
requirements:
|
517
517
|
- - ">="
|