krane 2.1.5 → 2.1.10

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