krane 2.1.3 → 2.1.4

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: 5a6ce0892fb00b50930df4316057572b08245e946d7eb9e60d938c76e4ba826e
4
- data.tar.gz: 903999c3121acbd58162ebfffedb10fbfa22a347262c7108bc3c499527654a22
3
+ metadata.gz: 7ae8bb4b0c7f920136990847601e19c7767075a89ead99781213feaf309d623d
4
+ data.tar.gz: 90ad58122ca788ebd4010e62e624c0d73a0c153e48c942673e244e7fbb4ccb32
5
5
  SHA512:
6
- metadata.gz: ca770038ea36996205013d9baae03f4acb6da0b37e57aa7f261d1c95a5846999135bb147392c1016a9c0c04377258e07e155f5f3a994e4a3e1fd8bffb69f296d
7
- data.tar.gz: b1c3fc517252cd4be20cf11a7dbf2381591890aeb6074859a6058f2dfd0becd060039800704106451dff116494a4725af93c2d0175550437df1a9c94428453b1
6
+ metadata.gz: 7e09bdb58b4bca4380b77bb10589a2e5b57aa31e9d8838c4b6efc68ccbf58b5af84c360a1a2710564164e4d6f19419cd38d7b3952559c56d5f7dc026d432a194
7
+ data.tar.gz: 659649bf0d0cfbe04d3fad0f32f3a05cc6ed9e117ca0755bf808d898b60dbf0d5be88cad609de1589cd93eb2b808e6cc9994a73f7b21267920b679b71afd138e
@@ -195,6 +195,7 @@ Style/FrozenStringLiteralComment:
195
195
  SupportedStyles:
196
196
  - always
197
197
  - never
198
+ SafeAutoCorrect: true
198
199
 
199
200
  Style/GlobalVars:
200
201
  AllowedVariables: []
@@ -1,6 +1,6 @@
1
1
  containers:
2
2
  default:
3
- docker: circleci/ruby:2.5.7
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.18-latest :ruby: 2.7)'
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.18-latest
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.12)'
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
- # Flip this back to v1.16-latest when 1.16.14 comes out (see #733)
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:
@@ -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 [![Build status](https://badge.buildkite.com/35c56e797c3bbd6ba50053aefdded0715898cd8e8c86f7e462.svg?branch=master)](https://buildkite.com/shopify/krane) [![codecov](https://codecov.io/gh/Shopify/kubernetes-deploy/branch/master/graph/badge.svg)](https://codecov.io/gh/Shopify/kubernetes-deploy)
1
+ # krane [![Build status](https://badge.buildkite.com/35c56e797c3bbd6ba50053aefdded0715898cd8e8c86f7e462.svg?branch=master)](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.5+
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.5}" \
19
+ ruby:"${RUBY_VERSION:-2.6.6}" \
21
20
  bin/test
data/dev.yml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: krane
3
3
  up:
4
- - ruby: 2.5.7 # Matches gemspec
4
+ - ruby: 2.6.6 # Matches gemspec
5
5
  - bundler
6
6
  - homebrew:
7
7
  - homebrew/cask/minikube
@@ -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.5.0'
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("codecov")
60
+ spec.add_development_dependency("simplecov")
61
61
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
-
3
2
  require 'krane'
3
+ require 'krane/oj'
4
4
  require 'thor'
5
5
  require 'krane/cli/version_command'
6
6
  require 'krane/cli/restart_command'
@@ -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
- group_versions = api_versions[resource['apigroup'].to_s]
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)
@@ -11,7 +11,6 @@ require 'active_support/core_ext/array/conversions'
11
11
  require 'colorized_string'
12
12
 
13
13
  require 'krane/version'
14
- require 'krane/oj'
15
14
  require 'krane/errors'
16
15
  require 'krane/formatted_logger'
17
16
  require 'krane/statsd'
@@ -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
- r.validate_definition(kubectl, selector: @selector)
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?)
@@ -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, selector: nil)
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 = ["apply", "-f", file_path, "--server-dry-run", "--output=name"]
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
- command = %w(apply)
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$/)
@@ -118,7 +118,7 @@ module Krane
118
118
  end
119
119
 
120
120
  def validate_pod(pod)
121
- pod.validate_definition(kubectl)
121
+ pod.validate_definition(kubectl: kubectl)
122
122
  end
123
123
 
124
124
  def watch_pod(pod)
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Krane
3
- VERSION = "2.1.3"
3
+ VERSION = "2.1.4"
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: 2.1.3
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: 2020-12-14 00:00:00.000000000 Z
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: codecov
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.5.0
514
+ version: 2.6.0
515
515
  required_rubygems_version: !ruby/object:Gem::Requirement
516
516
  requirements:
517
517
  - - ">="