krane 2.1.5 → 2.1.10

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: ae99732594c24143e48be0c4c44fdfec9f3f81e7d604362f8d000df837758aaa
4
- data.tar.gz: 11684058ac036a9846e5101944c0f26e33216da3d87bde0f20fe13246e52bbb5
3
+ metadata.gz: 41b26bfb1a0aee84de5462ef6f2e9421e208ead40437e1175c5fffcbbee10a65
4
+ data.tar.gz: bd21cd0c3ac2c5eeebb75883bb671da5847561e85173a0ffbf40f0b420ff0b57
5
5
  SHA512:
6
- metadata.gz: 36fec016df1d46e0bec3b7889913bbaa20bdb411795bb58b9995a87dde2bd0ed94203b21d229673fa8fe3d663d60981ce0e4d666acc173e7262b67a3671209ac
7
- data.tar.gz: df91b23d97e65489476c5ddb9f404e07c7a314003d84debd6cb5d59c27328f9a48394876af32a7ccb3976d3bfb296f60cd54af4c4fbdca6c31527ce86c2ad19a
6
+ metadata.gz: 8d53a59534ce296455aaf8b964aec3c0af378da315e7f1d45d56d8f9cb141f9992a72a594146e048487945e17551c6fddb62a46bc52244c8f7af49b5d83c0f88
7
+ data.tar.gz: 9a2764c120e71f0b429ea2c764ac56bbbedf91d42da5b94a97686809d33025fe81049692b3290970a12768402d2a69891443128b882aa10aafe0d179b6a250ae
data/.rubocop.yml CHANGED
@@ -1,5 +1,5 @@
1
- inherit_from:
2
- - http://shopify.github.io/ruby-style-guide/rubocop.yml
1
+ inherit_gem:
2
+ rubocop-shopify: rubocop.yml
3
3
 
4
4
  AllCops:
5
5
  TargetRubyVersion: 2.4
@@ -8,6 +8,14 @@ steps:
8
8
  run:
9
9
  - bundle: ~
10
10
  - bundle exec rubocop
11
+ - label: 'Run Test Suite (:kubernetes: 1.21-latest :ruby: 3.0)'
12
+ command: bin/ci
13
+ agents:
14
+ queue: k8s-ci
15
+ env:
16
+ LOGGING_LEVEL: "4"
17
+ KUBERNETES_VERSION: v1.21-latest
18
+ RUBY_VERSION: "3.0"
11
19
  - label: 'Run Test Suite (:kubernetes: 1.20-latest :ruby: 3.0)'
12
20
  command: bin/ci
13
21
  agents:
@@ -38,17 +46,3 @@ steps:
38
46
  env:
39
47
  LOGGING_LEVEL: "4"
40
48
  KUBERNETES_VERSION: v1.17-latest
41
- - label: 'Run Test Suite (:kubernetes: 1.16-latest)'
42
- command: bin/ci
43
- agents:
44
- queue: k8s-ci
45
- env:
46
- LOGGING_LEVEL: "4"
47
- KUBERNETES_VERSION: v1.16-latest
48
- - label: 'Run Test Suite (:kubernetes: 1.15-latest)'
49
- command: bin/ci
50
- agents:
51
- queue: k8s-ci
52
- env:
53
- LOGGING_LEVEL: "4"
54
- KUBERNETES_VERSION: v1.15-latest
data/CHANGELOG.md CHANGED
@@ -1,5 +1,44 @@
1
1
  ## next
2
2
 
3
+ ## 2.1.10
4
+
5
+ *Bug Fixes*
6
+
7
+ - Don't gather prunable resources by calling uniq only on `kind`: use `group` as well. Otherwise certain resources may not be added to the prune whitelist if the same kind exists across multiple groups [#825](https://github.com/Shopify/krane/pull/825)
8
+ - Fix resource discovery failures when API paths are not located at the root of the API server (this occurs, for example, when using Rancher proxy) [#827](https://github.com/Shopify/krane/pull/827)
9
+
10
+ *Other*
11
+
12
+ - Fix ERB deprecation of positional arguments [#828](https://github.com/Shopify/krane/pull/828)
13
+
14
+ ## 2.1.9
15
+
16
+ *Other*
17
+
18
+ - Don't package screenshots in the built gem to reduce size [#817](https://github.com/Shopify/krane/pull/817)
19
+
20
+ ## 2.1.8
21
+
22
+ *Other*
23
+
24
+ - Change `statsd-instrument` dependency constraint to `< 4` [#815](https://github.com/Shopify/krane/pull/815)
25
+
26
+ ## 2.1.7
27
+
28
+ *Enhancements*
29
+ - ENV["KRANE_LOG_LINE_LIMIT"] allows the number of container logs printed for failures to be configurable from the 25 line default [#803](https://github.com/Shopify/krane/pull/803).
30
+
31
+ *Other*
32
+ - Remove the overly tight timeout on cluster resource discovery, which was causing too many timeouts in high latency environments [#813](https://github.com/Shopify/krane/pull/813)
33
+
34
+ ## 2.1.6
35
+
36
+ *Enhancements*
37
+ - Remove the need for a hard coded GVK overide list via improvements to cluster discovery [#778](https://github.com/Shopify/krane/pull/778)
38
+
39
+ *Bug Fixes*
40
+ - Remove resources that are targeted by side-effect-inducing mutating admission webhooks from the serverside dry run batch [#798](https://github.com/Shopify/krane/pull/798)
41
+
3
42
  ## 2.1.5
4
43
 
5
44
  - Fix bug where the wrong dry-run flag is used for kubectl if client version is below 1.18 AND server version is 1.18+ [#793](https://github.com/Shopify/krane/pull/793).
data/dev.yml CHANGED
@@ -4,7 +4,7 @@ up:
4
4
  - ruby: 2.6.6 # Matches gemspec
5
5
  - bundler
6
6
  - homebrew:
7
- - homebrew/cask/minikube
7
+ - minikube
8
8
  - hyperkit
9
9
  - custom:
10
10
  name: Install the minikube fork of driver-hyperkit
data/krane.gemspec CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
17
17
  spec.license = "MIT"
18
18
 
19
19
  spec.files = %x(git ls-files -z).split("\x0").reject do |f|
20
- f.match(%r{^(test|spec|features)/})
20
+ f.match(%r{^(test|spec|features|screenshots)/})
21
21
  end
22
22
  spec.bindir = "exe"
23
23
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
@@ -31,7 +31,7 @@ Gem::Specification.new do |spec|
31
31
  spec.add_dependency("googleauth", "~> 0.8")
32
32
  spec.add_dependency("ejson", "~> 1.0")
33
33
  spec.add_dependency("colorize", "~> 0.8")
34
- spec.add_dependency("statsd-instrument", ['>= 2.8', "< 3.1"])
34
+ spec.add_dependency("statsd-instrument", ['>= 2.8', "< 4"])
35
35
  spec.add_dependency("oj", "~> 3.0")
36
36
  spec.add_dependency("concurrent-ruby", "~> 1.1")
37
37
  spec.add_dependency("jsonpath", "~> 0.9.6")
@@ -57,5 +57,6 @@ 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("rubocop-shopify", "~> 1.0.5")
60
61
  spec.add_development_dependency("simplecov")
61
62
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require 'concurrent'
2
3
 
3
4
  module Krane
4
5
  class ClusterResourceDiscovery
@@ -7,6 +8,7 @@ module Krane
7
8
  def initialize(task_config:, namespace_tags: [])
8
9
  @task_config = task_config
9
10
  @namespace_tags = namespace_tags
11
+ @api_path_cache = {}
10
12
  end
11
13
 
12
14
  def crds
@@ -18,104 +20,85 @@ module Krane
18
20
 
19
21
  def prunable_resources(namespaced:)
20
22
  black_list = %w(Namespace Node ControllerRevision)
21
- api_versions = fetch_api_versions
22
-
23
- fetch_resources(namespaced: namespaced).uniq { |r| r['kind'] }.map do |resource|
24
- next unless resource['verbs'].one? { |v| v == "delete" }
25
- next if black_list.include?(resource['kind'])
26
- gvk_string(api_versions, resource)
23
+ fetch_resources(namespaced: namespaced).map do |resource|
24
+ next unless resource["verbs"].one? { |v| v == "delete" }
25
+ next if black_list.include?(resource["kind"])
26
+ [resource["apigroup"], resource["version"], resource["kind"]].compact.join("/")
27
27
  end.compact
28
28
  end
29
29
 
30
- # kubectl api-resources -o wide returns 5 columns
31
- # NAME SHORTNAMES APIGROUP NAMESPACED KIND VERBS
32
- # SHORTNAMES and APIGROUP may be blank
33
- # VERBS is an array
34
- # serviceaccounts sa <blank> true ServiceAccount [create delete deletecollection get list patch update watch]
35
30
  def fetch_resources(namespaced: false)
36
- command = %w(api-resources)
37
- command << "--namespaced=#{namespaced}"
38
- raw, err, st = kubectl.run(*command, output: "wide", attempts: 5,
39
- use_namespace: false)
40
- if st.success?
41
- rows = raw.split("\n")
42
- header = rows[0]
43
- resources = rows[1..-1]
44
- full_width_field_names = header.downcase.scan(/[a-z]+[\W]*/)
45
- cursor = 0
46
- fields = full_width_field_names.each_with_object({}) do |name, hash|
47
- start = cursor
48
- cursor = start + name.length
49
- # Last field should consume the remainder of the line
50
- cursor = 0 if full_width_field_names.last == name.strip
51
- hash[name.strip] = [start, cursor - 1]
52
- end
53
- resources.map do |resource|
54
- resource = fields.map { |k, (s, e)| [k.strip, resource[s..e].strip] }.to_h
55
- # Manually parse verbs: "[get list]" into %w(get list)
56
- resource["verbs"] = resource["verbs"][1..-2].split
57
- resource
58
- end
59
- else
60
- raise FatalKubeAPIError, "Error retrieving api-resources: #{err}"
31
+ responses = Concurrent::Hash.new
32
+ Krane::Concurrency.split_across_threads(api_paths) do |path|
33
+ responses[path] = fetch_api_path(path)["resources"] || []
61
34
  end
35
+ responses.flat_map do |path, resources|
36
+ resources.map { |r| resource_hash(path, namespaced, r) }
37
+ end.compact.uniq { |r| "#{r['apigroup']}/#{r['kind']}" }
62
38
  end
63
39
 
64
- private
65
-
66
- # kubectl api-versions returns a list of group/version strings e.g. autoscaling/v2beta2
67
- # A kind may not exist in all versions of the group.
68
- def fetch_api_versions
69
- raw, err, st = kubectl.run("api-versions", attempts: 5, use_namespace: false)
70
- # The "core" group is represented by an empty string
71
- versions = { "" => %w(v1) }
40
+ def fetch_mutating_webhook_configurations
41
+ command = %w(get mutatingwebhookconfigurations)
42
+ raw_json, err, st = kubectl.run(*command, output: "json", attempts: 5, use_namespace: false)
72
43
  if st.success?
73
- rows = raw.split("\n")
74
- rows.each do |group_version|
75
- group, version = group_version.split("/")
76
- versions[group] ||= []
77
- versions[group] << version
44
+ JSON.parse(raw_json)["items"].map do |definition|
45
+ Krane::MutatingWebhookConfiguration.new(namespace: namespace, context: context, logger: logger,
46
+ definition: definition, statsd_tags: @namespace_tags)
78
47
  end
79
48
  else
80
- raise FatalKubeAPIError, "Error retrieving api-versions: #{err}"
49
+ raise FatalKubeAPIError, "Error retrieving mutatingwebhookconfigurations: #{err}"
81
50
  end
82
- versions
83
51
  end
84
52
 
85
- def version_for_kind(versions, kind)
86
- # Override list for kinds that don't appear in the lastest version of a group
87
- version_override = { "CronJob" => "v1beta1", "VolumeAttachment" => "v1beta1",
88
- "CSIDriver" => "v1beta1", "Ingress" => "v1beta1",
89
- "CSINode" => "v1beta1", "Job" => "v1",
90
- "IngressClass" => "v1beta1", "FrontendConfig" => "v1beta1",
91
- "ServiceNetworkEndpointGroup" => "v1beta1",
92
- "EnvoyFilter" => "v1alpha3",
93
- "TCPIngress" => "v1beta1" }
53
+ private
94
54
 
95
- pattern = /v(?<major>\d+)(?<pre>alpha|beta)?(?<minor>\d+)?/
96
- latest = versions.sort_by do |version|
97
- match = version.match(pattern)
98
- pre = { "alpha" => 0, "beta" => 1, nil => 2 }.fetch(match[:pre])
99
- [match[:major].to_i, pre, match[:minor].to_i]
100
- end.last
101
- version_override.fetch(kind, latest)
102
- end
55
+ # During discovery, the api paths may not actually be at the root, so we must programatically find it.
56
+ def base_api_path
57
+ @base_api_path ||= begin
58
+ raw_response, err, st = kubectl.run("config", "view", "--minify", "--output",
59
+ "jsonpath={.clusters[*].cluster.server}", attempts: 5, use_namespace: false)
60
+ raise FatalKubeAPIError, "Error retrieving cluster url: #{err}" unless st.success?
103
61
 
104
- def gvk_string(api_versions, resource)
105
- apiversion = resource['apiversion'].to_s
62
+ URI(raw_response).path.blank? ? "/" : URI(raw_response).path
63
+ end
64
+ end
106
65
 
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]
66
+ def api_paths
67
+ @api_path_cache["/"] ||= begin
68
+ raw_json, err, st = kubectl.run("get", "--raw", base_api_path, attempts: 5, use_namespace: false)
69
+ paths = if st.success?
70
+ JSON.parse(raw_json)["paths"]
71
+ else
72
+ raise FatalKubeAPIError, "Error retrieving raw path /: #{err}"
73
+ end
74
+ paths.select { |path| %r{^\/api.*\/v.*$}.match(path) }
75
+ end
76
+ end
111
77
 
112
- version = version_for_kind(group_versions, resource['kind'])
113
- apigroup = 'core' if apigroup.empty?
114
- apiversion = "#{apigroup}/#{version}"
78
+ def fetch_api_path(path)
79
+ @api_path_cache[path] ||= begin
80
+ raw_json, err, st = kubectl.run("get", "--raw", path, attempts: 2, use_namespace: false)
81
+ if st.success?
82
+ JSON.parse(raw_json)
83
+ else
84
+ logger.warn("Error retrieving api path: #{err}")
85
+ {}
86
+ end
115
87
  end
88
+ end
116
89
 
117
- apiversion = "core/#{apiversion}" unless apiversion.include?("/")
118
- [apiversion, resource['kind']].compact.join("/")
90
+ def resource_hash(path, namespaced, blob)
91
+ return unless blob["namespaced"] == namespaced
92
+ # skip sub-resources
93
+ return if blob["name"].include?("/")
94
+ path_regex = %r{(/apis?/)(?<group>[^/]*)/?(?<version>v.+)}
95
+ match = path.match(path_regex)
96
+ {
97
+ "verbs" => blob["verbs"],
98
+ "kind" => blob["kind"],
99
+ "apigroup" => match[:group],
100
+ "version" => match[:version],
101
+ }
119
102
  end
120
103
 
121
104
  def fetch_crds
@@ -3,7 +3,7 @@ module Krane
3
3
  class ContainerLogs
4
4
  attr_reader :lines, :container_name
5
5
 
6
- DEFAULT_LINE_LIMIT = 25
6
+ DEFAULT_LINE_LIMIT = Integer(ENV.fetch('KRANE_LOG_LINE_LIMIT', 25))
7
7
 
8
8
  def initialize(parent_id:, container_name:, namespace:, context:, logger:)
9
9
  @parent_id = parent_id
@@ -30,6 +30,7 @@ require 'krane/kubernetes_resource'
30
30
  custom_resource_definition
31
31
  horizontal_pod_autoscaler
32
32
  secret
33
+ mutating_webhook_configuration
33
34
  ).each do |subresource|
34
35
  require "krane/kubernetes_resource/#{subresource}"
35
36
  end
@@ -277,16 +278,25 @@ module Krane
277
278
  end
278
279
  measure_method(:validate_configuration)
279
280
 
281
+ def partition_dry_run_resources(resources)
282
+ individuals = []
283
+ mutating_webhook_configurations = cluster_resource_discoverer.fetch_mutating_webhook_configurations
284
+ mutating_webhook_configurations.each do |mutating_webhook_configuration|
285
+ mutating_webhook_configuration.webhooks.each do |webhook|
286
+ individuals = (individuals + resources.select { |resource| webhook.matches_resource?(resource) }).uniq
287
+ resources -= individuals
288
+ end
289
+ end
290
+ [resources, individuals]
291
+ end
292
+
280
293
  def validate_resources(resources)
281
294
  validate_globals(resources)
282
- batch_dry_run_success = kubectl.server_dry_run_enabled? && validate_dry_run(resources)
295
+ batchable_resources, individuals = partition_dry_run_resources(resources.dup)
296
+ batch_dry_run_success = kubectl.server_dry_run_enabled? && validate_dry_run(batchable_resources)
297
+ individuals += batchable_resources unless batch_dry_run_success
283
298
  Krane::Concurrency.split_across_threads(resources) do |r|
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
299
+ r.validate_definition(kubectl: kubectl, selector: @selector, dry_run: individuals.include?(r))
290
300
  end
291
301
  failed_resources = resources.select(&:validation_failed?)
292
302
  if failed_resources.present?
@@ -226,6 +226,11 @@ module Krane
226
226
  version ? grouping : "core"
227
227
  end
228
228
 
229
+ def version
230
+ prefix, version = @definition.dig("apiVersion").split("/")
231
+ version || prefix
232
+ end
233
+
229
234
  def kubectl_resource_type
230
235
  type
231
236
  end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Krane
4
+ class MutatingWebhookConfiguration < KubernetesResource
5
+ GLOBAL = true
6
+
7
+ class Webhook
8
+ EQUIVALENT = 'Equivalent'
9
+ EXACT = 'Exact'
10
+
11
+ class Rule
12
+ def initialize(definition)
13
+ @definition = definition
14
+ end
15
+
16
+ def matches_resource?(resource, accept_equivalent:)
17
+ groups.each do |group|
18
+ versions.each do |version|
19
+ resources.each do |kind|
20
+ return true if (resource.group == group || group == '*' || accept_equivalent) &&
21
+ (resource.version == version || version == '*' || accept_equivalent) &&
22
+ (resource.type.downcase == kind.downcase.singularize || kind == "*")
23
+ end
24
+ end
25
+ end
26
+ false
27
+ end
28
+
29
+ def groups
30
+ @definition.dig('apiGroups')
31
+ end
32
+
33
+ def versions
34
+ @definition.dig('apiVersions')
35
+ end
36
+
37
+ def resources
38
+ @definition.dig('resources')
39
+ end
40
+ end
41
+
42
+ def initialize(definition)
43
+ @definition = definition
44
+ end
45
+
46
+ def side_effects
47
+ @definition.dig('sideEffects')
48
+ end
49
+
50
+ def has_side_effects?
51
+ !%w(None NoneOnDryRun).include?(side_effects)
52
+ end
53
+
54
+ def match_policy
55
+ @definition.dig('matchPolicy')
56
+ end
57
+
58
+ def matches_resource?(resource, skip_rule_if_side_effect_none: true)
59
+ return false if skip_rule_if_side_effect_none && !has_side_effects?
60
+ rules.any? do |rule|
61
+ rule.matches_resource?(resource, accept_equivalent: match_policy == EQUIVALENT)
62
+ end
63
+ end
64
+
65
+ def rules
66
+ @definition.fetch('rules', []).map { |rule| Rule.new(rule) }
67
+ end
68
+ end
69
+
70
+ def initialize(namespace:, context:, definition:, logger:, statsd_tags:)
71
+ @webhooks = (definition.dig('webhooks') || []).map { |hook| Webhook.new(hook) }
72
+ super(namespace: namespace, context: context, definition: definition,
73
+ logger: logger, statsd_tags: statsd_tags)
74
+ end
75
+
76
+ TIMEOUT = 30.seconds
77
+
78
+ def deploy_succeeded?
79
+ exists?
80
+ end
81
+
82
+ def webhooks
83
+ @definition.fetch('webhooks', []).map { |webhook| Webhook.new(webhook) }
84
+ end
85
+ end
86
+ end
@@ -39,7 +39,7 @@ module Krane
39
39
  erb_binding = TemplateContext.new(self).template_binding
40
40
  bind_template_variables(erb_binding, template_variables)
41
41
 
42
- ERB.new(raw_template, nil, '-').result(erb_binding)
42
+ ERB.new(raw_template, trim_mode: '-').result(erb_binding)
43
43
  rescue InvalidPartialError => err
44
44
  err.parents = err.parents.dup.unshift(filename)
45
45
  err.filename = "#{err.filename} (partial included from: #{err.parents.join(' -> ')})"
@@ -56,7 +56,7 @@ module Krane
56
56
 
57
57
  partial_path = find_partial(partial)
58
58
  template = File.read(partial_path)
59
- expanded_template = ERB.new(template, nil, '-').result(erb_binding)
59
+ expanded_template = ERB.new(template, trim_mode: '-').result(erb_binding)
60
60
 
61
61
  docs = Psych.parse_stream(expanded_template, partial_path)
62
62
  # If the partial contains multiple documents or has an explicit document header,
data/lib/krane/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Krane
3
- VERSION = "2.1.5"
3
+ VERSION = "2.1.10"
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.5
4
+ version: 2.1.10
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: 2021-01-27 00:00:00.000000000 Z
13
+ date: 2021-06-04 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
@@ -91,7 +91,7 @@ dependencies:
91
91
  version: '2.8'
92
92
  - - "<"
93
93
  - !ruby/object:Gem::Version
94
- version: '3.1'
94
+ version: '4'
95
95
  type: :runtime
96
96
  prerelease: false
97
97
  version_requirements: !ruby/object:Gem::Requirement
@@ -101,7 +101,7 @@ dependencies:
101
101
  version: '2.8'
102
102
  - - "<"
103
103
  - !ruby/object:Gem::Version
104
- version: '3.1'
104
+ version: '4'
105
105
  - !ruby/object:Gem::Dependency
106
106
  name: oj
107
107
  requirement: !ruby/object:Gem::Requirement
@@ -374,6 +374,20 @@ dependencies:
374
374
  - - "~>"
375
375
  - !ruby/object:Gem::Version
376
376
  version: 0.89.1
377
+ - !ruby/object:Gem::Dependency
378
+ name: rubocop-shopify
379
+ requirement: !ruby/object:Gem::Requirement
380
+ requirements:
381
+ - - "~>"
382
+ - !ruby/object:Gem::Version
383
+ version: 1.0.5
384
+ type: :development
385
+ prerelease: false
386
+ version_requirements: !ruby/object:Gem::Requirement
387
+ requirements:
388
+ - - "~>"
389
+ - !ruby/object:Gem::Version
390
+ version: 1.0.5
377
391
  - !ruby/object:Gem::Dependency
378
392
  name: simplecov
379
393
  requirement: !ruby/object:Gem::Requirement
@@ -460,6 +474,7 @@ files:
460
474
  - lib/krane/kubernetes_resource/horizontal_pod_autoscaler.rb
461
475
  - lib/krane/kubernetes_resource/ingress.rb
462
476
  - lib/krane/kubernetes_resource/job.rb
477
+ - lib/krane/kubernetes_resource/mutating_webhook_configuration.rb
463
478
  - lib/krane/kubernetes_resource/network_policy.rb
464
479
  - lib/krane/kubernetes_resource/persistent_volume_claim.rb
465
480
  - lib/krane/kubernetes_resource/pod.rb
@@ -493,11 +508,6 @@ files:
493
508
  - lib/krane/task_config_validator.rb
494
509
  - lib/krane/template_sets.rb
495
510
  - lib/krane/version.rb
496
- - screenshots/deploy-demo.gif
497
- - screenshots/migrate-logs.png
498
- - screenshots/missing-secret-fail.png
499
- - screenshots/success.png
500
- - screenshots/test-output.png
501
511
  homepage: https://github.com/Shopify/krane
502
512
  licenses:
503
513
  - MIT
@@ -518,7 +528,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
518
528
  - !ruby/object:Gem::Version
519
529
  version: '0'
520
530
  requirements: []
521
- rubygems_version: 3.0.3
531
+ rubygems_version: 3.2.17
522
532
  signing_key:
523
533
  specification_version: 4
524
534
  summary: A command line tool that helps you ship changes to a Kubernetes namespace
Binary file
Binary file
Binary file
Binary file
Binary file