krane 1.1.1 → 2.1.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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +1 -0
  3. data/{ISSUE_TEMPLATE.md → .github/ISSUE_TEMPLATE.md} +0 -0
  4. data/{pull_request_template.md → .github/pull_request_template.md} +0 -0
  5. data/.rubocop-http---shopify-github-io-ruby-style-guide-rubocop-yml +27 -33
  6. data/.rubocop.yml +0 -12
  7. data/.shopify-build/krane.yml +20 -6
  8. data/1.0-Upgrade.md +1 -1
  9. data/CHANGELOG.md +57 -0
  10. data/CONTRIBUTING.md +2 -2
  11. data/README.md +17 -14
  12. data/bin/ci +1 -1
  13. data/bin/test +2 -2
  14. data/dev.yml +3 -2
  15. data/krane.gemspec +6 -4
  16. data/lib/krane/annotation.rb +11 -0
  17. data/lib/krane/cli/deploy_command.rb +2 -3
  18. data/lib/krane/cli/global_deploy_command.rb +3 -3
  19. data/lib/krane/cli/render_command.rb +3 -3
  20. data/lib/krane/cluster_resource_discovery.rb +10 -6
  21. data/lib/krane/concerns/template_reporting.rb +0 -6
  22. data/lib/krane/container_logs.rb +1 -1
  23. data/lib/krane/container_overrides.rb +33 -0
  24. data/lib/krane/deploy_task.rb +21 -18
  25. data/lib/krane/ejson_secret_provisioner.rb +1 -2
  26. data/lib/krane/global_deploy_task.rb +8 -14
  27. data/lib/krane/kubeclient_builder.rb +4 -2
  28. data/lib/krane/kubectl.rb +18 -5
  29. data/lib/krane/kubernetes_resource.rb +32 -42
  30. data/lib/krane/kubernetes_resource/custom_resource.rb +2 -2
  31. data/lib/krane/kubernetes_resource/custom_resource_definition.rb +13 -10
  32. data/lib/krane/kubernetes_resource/deployment.rb +5 -7
  33. data/lib/krane/kubernetes_resource/persistent_volume_claim.rb +1 -0
  34. data/lib/krane/kubernetes_resource/pod.rb +12 -8
  35. data/lib/krane/psych_k8s_compatibility.rb +36 -0
  36. data/lib/krane/render_task.rb +2 -2
  37. data/lib/krane/renderer.rb +2 -0
  38. data/lib/krane/resource_deployer.rb +9 -5
  39. data/lib/krane/resource_watcher.rb +1 -1
  40. data/lib/krane/restart_task.rb +8 -8
  41. data/lib/krane/runner_task.rb +21 -24
  42. data/lib/krane/statsd.rb +2 -2
  43. data/lib/krane/task_config.rb +7 -2
  44. data/lib/krane/task_config_validator.rb +3 -3
  45. data/lib/krane/template_sets.rb +1 -1
  46. data/lib/krane/version.rb +1 -1
  47. metadata +17 -13
  48. data/lib/krane/kubernetes_resource/cloudsql.rb +0 -44
data/bin/ci CHANGED
@@ -17,5 +17,5 @@ docker run --rm \
17
17
  -e VERBOSE=1 \
18
18
  -e PARALLELISM=$PARALLELISM \
19
19
  -w /usr/src/app \
20
- ruby:2.4 \
20
+ ruby:"${RUBY_VERSION:-2.5}" \
21
21
  bin/test
data/bin/test CHANGED
@@ -41,7 +41,7 @@ bundle exec rake unit_test
41
41
  print_header "Run Non-Parallel Integration Tests"
42
42
  bundle exec rake serial_integration_test
43
43
 
44
- print_header "Run Parallel Integration Tests (N=$PARALLELISM)"
45
- PARALLELIZE_ME=1 N=$PARALLELISM bundle exec rake integration_test
44
+ print_header "Run Parallel Integration Tests (MT_CPU=$PARALLELISM)"
45
+ PARALLELIZE_ME=1 MT_CPU=$PARALLELISM bundle exec rake integration_test
46
46
 
47
47
  test $err -eq 0
data/dev.yml CHANGED
@@ -1,10 +1,11 @@
1
1
  ---
2
2
  name: krane
3
3
  up:
4
- - ruby: 2.4.6 # Matches gemspec
4
+ - ruby: 2.5.7 # Matches gemspec
5
5
  - bundler
6
6
  - homebrew:
7
- - Caskroom/cask/minikube
7
+ - homebrew/cask/minikube
8
+ - hyperkit
8
9
  - custom:
9
10
  name: Install the minikube fork of driver-hyperkit
10
11
  met?: command -v docker-machine-driver-hyperkit
@@ -23,7 +23,9 @@ Gem::Specification.new do |spec|
23
23
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
24
  spec.require_paths = %w(lib)
25
25
 
26
- spec.required_ruby_version = '>= 2.4.0'
26
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
27
+
28
+ spec.required_ruby_version = '>= 2.5.0'
27
29
  spec.add_dependency("activesupport", ">= 5.0")
28
30
  spec.add_dependency("kubeclient", "~> 4.3")
29
31
  spec.add_dependency("googleauth", "~> 0.8")
@@ -33,7 +35,7 @@ Gem::Specification.new do |spec|
33
35
  spec.add_dependency("oj", "~> 3.0")
34
36
  spec.add_dependency("concurrent-ruby", "~> 1.1")
35
37
  spec.add_dependency("jsonpath", "~> 0.9.6")
36
- spec.add_dependency("thor", ">= 0.20.3", "< 2.0")
38
+ spec.add_dependency("thor", ">= 1.0", "< 2.0")
37
39
 
38
40
  # Basics
39
41
  spec.add_development_dependency("bundler")
@@ -41,7 +43,7 @@ Gem::Specification.new do |spec|
41
43
  spec.add_development_dependency("yard")
42
44
 
43
45
  # Test framework
44
- spec.add_development_dependency("minitest", "~> 5.0")
46
+ spec.add_development_dependency("minitest", "~> 5.12")
45
47
  spec.add_development_dependency("minitest-stub-const", "~> 0.6")
46
48
  spec.add_development_dependency("minitest-reporters")
47
49
  spec.add_development_dependency("mocha", "~> 1.5")
@@ -54,6 +56,6 @@ Gem::Specification.new do |spec|
54
56
  spec.add_development_dependency("byebug")
55
57
  spec.add_development_dependency("ruby-prof")
56
58
  spec.add_development_dependency("ruby-prof-flamegraph")
57
- spec.add_development_dependency("rubocop", "~> 0.76.0")
59
+ spec.add_development_dependency("rubocop", "~> 0.89.1")
58
60
  spec.add_development_dependency("codecov")
59
61
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Krane
4
+ module Annotation
5
+ class << self
6
+ def for(suffix)
7
+ "krane.shopify.io/#{suffix}"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -14,7 +14,7 @@ module Krane
14
14
  aliases: :f, required: false, default: [],
15
15
  desc: "Directories and files that contains the configuration to apply" },
16
16
  "stdin" => { type: :boolean, default: false,
17
- desc: "Read resources from stdin" },
17
+ desc: "[DEPRECATED] Read resources from stdin" },
18
18
  "global-timeout" => { type: :string, banner: "duration", default: DEFAULT_DEPLOY_TIMEOUT,
19
19
  desc: "Max duration to monitor workloads correctly deployed" },
20
20
  "protected-namespaces" => { type: :array, banner: "namespace1 namespace2 namespaceN",
@@ -46,11 +46,10 @@ module Krane
46
46
  protected_namespaces = []
47
47
  end
48
48
 
49
- # never mutate options directly
50
49
  filenames = options[:filenames].dup
51
50
  filenames << "-" if options[:stdin]
52
51
  if filenames.empty?
53
- raise Thor::RequiredArgumentMissingError, 'At least one of --filenames or --stdin must be set'
52
+ raise(Thor::RequiredArgumentMissingError, '--filenames must be set and not empty')
54
53
  end
55
54
 
56
55
  ::Krane::OptionsHelper.with_processed_template_paths(filenames) do |paths|
@@ -8,7 +8,8 @@ module Krane
8
8
  "filenames" => { type: :array, banner: 'config/deploy/production config/deploy/my-extra-resource.yml',
9
9
  aliases: :f, required: false, default: [],
10
10
  desc: "Directories and files that contains the configuration to apply" },
11
- "stdin" => { type: :boolean, default: false, desc: "Read resources from stdin" },
11
+ "stdin" => { type: :boolean, default: false,
12
+ desc: "[DEPRECATED] Read resources from stdin" },
12
13
  "global-timeout" => { type: :string, banner: "duration", default: DEFAULT_DEPLOY_TIMEOUT,
13
14
  desc: "Max duration to monitor workloads correctly deployed" },
14
15
  "verify-result" => { type: :boolean, default: true,
@@ -28,11 +29,10 @@ module Krane
28
29
 
29
30
  selector = ::Krane::LabelSelector.parse(options[:selector])
30
31
 
31
- # never mutate options directly
32
32
  filenames = options[:filenames].dup
33
33
  filenames << "-" if options[:stdin]
34
34
  if filenames.empty?
35
- raise Thor::RequiredArgumentMissingError, 'At least one of --filenames or --stdin must be set'
35
+ raise(Thor::RequiredArgumentMissingError, '--filenames must be set and not empty')
36
36
  end
37
37
 
38
38
  ::Krane::OptionsHelper.with_processed_template_paths(filenames) do |paths|
@@ -7,7 +7,8 @@ module Krane
7
7
  "bindings" => { type: :array, banner: "foo=bar abc=def", desc: 'Bindings for erb' },
8
8
  "filenames" => { type: :array, banner: 'config/deploy/production config/deploy/my-extra-resource.yml',
9
9
  required: false, default: [], aliases: 'f', desc: 'Directories and files to render' },
10
- "stdin" => { type: :boolean, desc: "Read resources from stdin", default: false },
10
+ "stdin" => { type: :boolean, default: false,
11
+ desc: "[DEPRECATED] Read resources from stdin" },
11
12
  "current-sha" => { type: :string, banner: "SHA", desc: "Expose SHA `current_sha` in ERB bindings",
12
13
  lazy_default: '' },
13
14
  }
@@ -20,11 +21,10 @@ module Krane
20
21
  bindings_parser = ::Krane::BindingsParser.new
21
22
  options[:bindings]&.each { |b| bindings_parser.add(b) }
22
23
 
23
- # never mutate options directly
24
24
  filenames = options[:filenames].dup
25
25
  filenames << "-" if options[:stdin]
26
26
  if filenames.empty?
27
- raise Thor::RequiredArgumentMissingError, 'At least one of --filenames or --stdin must be set'
27
+ raise(Thor::RequiredArgumentMissingError, '--filenames must be set and not empty')
28
28
  end
29
29
 
30
30
  ::Krane::OptionsHelper.with_processed_template_paths(filenames, render_erb: true) do |paths|
@@ -37,7 +37,7 @@ module Krane
37
37
  def fetch_resources(namespaced: false)
38
38
  command = %w(api-resources)
39
39
  command << "--namespaced=#{namespaced}"
40
- raw, _, st = kubectl.run(*command, output: "wide", attempts: 5,
40
+ raw, err, st = kubectl.run(*command, output: "wide", attempts: 5,
41
41
  use_namespace: false)
42
42
  if st.success?
43
43
  rows = raw.split("\n")
@@ -59,7 +59,7 @@ module Krane
59
59
  resource
60
60
  end
61
61
  else
62
- []
62
+ raise FatalKubeAPIError, "Error retrieving api-resources: #{err}"
63
63
  end
64
64
  end
65
65
 
@@ -68,7 +68,7 @@ module Krane
68
68
  # kubectl api-versions returns a list of group/version strings e.g. autoscaling/v2beta2
69
69
  # A kind may not exist in all versions of the group.
70
70
  def fetch_api_versions
71
- raw, _, st = kubectl.run("api-versions", attempts: 5, use_namespace: false)
71
+ raw, err, st = kubectl.run("api-versions", attempts: 5, use_namespace: false)
72
72
  # The "core" group is represented by an empty string
73
73
  versions = { "" => %w(v1) }
74
74
  if st.success?
@@ -78,6 +78,8 @@ module Krane
78
78
  versions[group] ||= []
79
79
  versions[group] << version
80
80
  end
81
+ else
82
+ raise FatalKubeAPIError, "Error retrieving api-versions: #{err}"
81
83
  end
82
84
  versions
83
85
  end
@@ -85,7 +87,9 @@ module Krane
85
87
  def version_for_kind(versions, kind)
86
88
  # Override list for kinds that don't appear in the lastest version of a group
87
89
  version_override = { "CronJob" => "v1beta1", "VolumeAttachment" => "v1beta1",
88
- "CSIDriver" => "v1beta1", "Ingress" => "v1beta1", "CSINode" => "v1beta1" }
90
+ "CSIDriver" => "v1beta1", "Ingress" => "v1beta1",
91
+ "CSINode" => "v1beta1", "Job" => "v1",
92
+ "IngressClass" => "v1beta1" }
89
93
 
90
94
  pattern = /v(?<major>\d+)(?<pre>alpha|beta)?(?<minor>\d+)?/
91
95
  latest = versions.sort_by do |version|
@@ -97,12 +101,12 @@ module Krane
97
101
  end
98
102
 
99
103
  def fetch_crds
100
- raw_json, _, st = kubectl.run("get", "CustomResourceDefinition", output: "json", attempts: 5,
104
+ raw_json, err, st = kubectl.run("get", "CustomResourceDefinition", output: "json", attempts: 5,
101
105
  use_namespace: false)
102
106
  if st.success?
103
107
  JSON.parse(raw_json)["items"]
104
108
  else
105
- []
109
+ raise FatalKubeAPIError, "Error retrieving CustomResourceDefinition: #{err}"
106
110
  end
107
111
  end
108
112
 
@@ -15,12 +15,6 @@ module Krane
15
15
  logger.summary.add_paragraph(debug_msg)
16
16
  end
17
17
 
18
- def record_warnings(logger:, warning:, filename:)
19
- warn_msg = "Template warning: #{filename}\n"
20
- warn_msg += "> Warning message:\n#{Krane::FormattedLogger.indent_four(warning)}"
21
- logger.summary.add_paragraph(ColorizedString.new(warn_msg).yellow)
22
- end
23
-
24
18
  def add_para_from_list(logger:, action:, enum:)
25
19
  logger.summary.add_action(action)
26
20
  logger.summary.add_paragraph(enum.map { |e| "- #{e}" }.join("\n"))
@@ -3,7 +3,7 @@ module Krane
3
3
  class ContainerLogs
4
4
  attr_reader :lines, :container_name
5
5
 
6
- DEFAULT_LINE_LIMIT = 250
6
+ DEFAULT_LINE_LIMIT = 25
7
7
 
8
8
  def initialize(parent_id:, container_name:, namespace:, context:, logger:)
9
9
  @parent_id = parent_id
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+ module Krane
3
+ class ContainerOverrides
4
+ attr_reader :command, :arguments, :env_vars, :image_tag
5
+
6
+ def initialize(command: nil, arguments: nil, env_vars: [], image_tag: nil)
7
+ @command = command
8
+ @arguments = arguments
9
+ @env_vars = env_vars
10
+ @image_tag = image_tag
11
+ end
12
+
13
+ def apply!(container)
14
+ container.command = command if command
15
+ container.args = arguments if arguments
16
+
17
+ if image_tag
18
+ image = container.image
19
+ base_image, _old_tag = image.split(':')
20
+ new_image = "#{base_image}:#{image_tag}"
21
+
22
+ container.image = new_image
23
+ end
24
+
25
+ env_args = env_vars.map do |env|
26
+ key, value = env.split('=', 2)
27
+ { name: key, value: value }
28
+ end
29
+ container.env ||= []
30
+ container.env = container.env.map(&:to_h) + env_args
31
+ end
32
+ end
33
+ end
@@ -4,13 +4,13 @@ require 'shellwords'
4
4
  require 'tempfile'
5
5
  require 'fileutils'
6
6
 
7
+ require 'krane/annotation'
7
8
  require 'krane/common'
8
9
  require 'krane/concurrency'
9
10
  require 'krane/resource_cache'
10
11
  require 'krane/kubernetes_resource'
11
12
  %w(
12
13
  custom_resource
13
- cloudsql
14
14
  config_map
15
15
  deployment
16
16
  ingress
@@ -57,6 +57,7 @@ module Krane
57
57
  )
58
58
 
59
59
  def predeploy_sequence
60
+ default_group = { group: nil }
60
61
  before_crs = %w(
61
62
  ResourceQuota
62
63
  NetworkPolicy
@@ -66,12 +67,14 @@ module Krane
66
67
  Role
67
68
  RoleBinding
68
69
  Secret
69
- )
70
+ ).map { |r| [r, default_group] }
71
+
70
72
  after_crs = %w(
71
73
  Pod
72
- )
74
+ ).map { |r| [r, default_group] }
73
75
 
74
- before_crs + cluster_resource_discoverer.crds.select(&:predeployed?).map(&:kind) + after_crs
76
+ crs = cluster_resource_discoverer.crds.select(&:predeployed?).map { |cr| [cr.kind, { group: cr.group }] }
77
+ Hash[before_crs + crs + after_crs]
75
78
  end
76
79
 
77
80
  def prune_whitelist
@@ -82,6 +85,10 @@ module Krane
82
85
  kubectl.server_version
83
86
  end
84
87
 
88
+ attr_reader :task_config
89
+
90
+ delegate :kubeclient_builder, to: :task_config
91
+
85
92
  # Initializes the deploy task
86
93
  #
87
94
  # @param namespace [String] Kubernetes namespace (*required*)
@@ -98,10 +105,10 @@ module Krane
98
105
  # @param render_erb [Boolean] Enable ERB rendering
99
106
  def initialize(namespace:, context:, current_sha: nil, logger: nil, kubectl_instance: nil, bindings: {},
100
107
  global_timeout: nil, selector: nil, filenames: [], protected_namespaces: nil,
101
- render_erb: false)
108
+ render_erb: false, kubeconfig: nil)
102
109
  @logger = logger || Krane::FormattedLogger.build(namespace, context)
103
110
  @template_sets = TemplateSets.from_dirs_and_files(paths: filenames, logger: @logger, render_erb: render_erb)
104
- @task_config = Krane::TaskConfig.new(context, namespace, @logger)
111
+ @task_config = Krane::TaskConfig.new(context, namespace, @logger, kubeconfig)
105
112
  @bindings = bindings
106
113
  @namespace = namespace
107
114
  @namespace_tags = []
@@ -117,8 +124,8 @@ module Krane
117
124
  # Runs the task, returning a boolean representing success or failure
118
125
  #
119
126
  # @return [Boolean]
120
- def run(*args)
121
- run!(*args)
127
+ def run(**args)
128
+ run!(**args)
122
129
  true
123
130
  rescue FatalDeploymentError
124
131
  false
@@ -187,10 +194,6 @@ module Krane
187
194
  selector: @selector, statsd_tags: statsd_tags, current_sha: @current_sha)
188
195
  end
189
196
 
190
- def kubeclient_builder
191
- @kubeclient_builder ||= KubeclientBuilder.new
192
- end
193
-
194
197
  def cluster_resource_discoverer
195
198
  @cluster_resource_discoverer ||= ClusterResourceDiscovery.new(
196
199
  task_config: @task_config,
@@ -211,7 +214,10 @@ module Krane
211
214
  end
212
215
 
213
216
  def deploy_has_priority_resources?(resources)
214
- resources.any? { |r| predeploy_sequence.include?(r.type) }
217
+ resources.any? do |r|
218
+ next unless (pr = predeploy_sequence[r.type])
219
+ !pr[:group] || pr[:group] == r.group
220
+ end
215
221
  end
216
222
 
217
223
  def check_initial_status(resources)
@@ -243,6 +249,8 @@ module Krane
243
249
  @logger.info(" - #{secret.id} (from ejson)")
244
250
  end
245
251
 
252
+ StatsD.client.gauge('discover_resources.count', resources.size, tags: statsd_tags)
253
+
246
254
  resources.sort
247
255
  rescue InvalidTemplateError => e
248
256
  record_invalid_template(logger: @logger, err: e.message, filename: e.filename,
@@ -275,11 +283,6 @@ module Krane
275
283
  r.validate_definition(kubectl, selector: @selector)
276
284
  end
277
285
 
278
- resources.select(&:has_warnings?).each do |resource|
279
- record_warnings(logger: @logger, warning: resource.validation_warning_msg,
280
- filename: File.basename(resource.file_path))
281
- end
282
-
283
286
  failed_resources = resources.select(&:validation_failed?)
284
287
  if failed_resources.present?
285
288
 
@@ -12,10 +12,10 @@ module Krane
12
12
  end
13
13
 
14
14
  class EjsonSecretProvisioner
15
- EJSON_SECRET_ANNOTATION = "kubernetes-deploy.shopify.io/ejson-secret"
16
15
  EJSON_SECRET_KEY = "kubernetes_secrets"
17
16
  EJSON_SECRETS_FILE = "secrets.ejson"
18
17
  EJSON_KEYS_SECRET = "ejson-keys"
18
+
19
19
  delegate :namespace, :context, :logger, to: :@task_config
20
20
 
21
21
  def initialize(task_config:, ejson_keys_secret:, ejson_file:, statsd_tags:, selector: nil)
@@ -106,7 +106,6 @@ module Krane
106
106
  "name" => secret_name,
107
107
  "labels" => labels,
108
108
  "namespace" => namespace,
109
- "annotations" => { EJSON_SECRET_ANNOTATION => "true" },
110
109
  },
111
110
  "data" => encoded_data,
112
111
  }
@@ -25,7 +25,8 @@ module Krane
25
25
  class GlobalDeployTask
26
26
  extend Krane::StatsD::MeasureMethods
27
27
  include TemplateReporting
28
- delegate :context, :logger, :global_kinds, to: :@task_config
28
+ delegate :context, :logger, :global_kinds, :kubeclient_builder, to: :@task_config
29
+ attr_reader :task_config
29
30
 
30
31
  # Initializes the deploy task
31
32
  #
@@ -33,10 +34,10 @@ module Krane
33
34
  # @param global_timeout [Integer] Timeout in seconds
34
35
  # @param selector [Hash] Selector(s) parsed by Krane::LabelSelector (*required*)
35
36
  # @param filenames [Array<String>] An array of filenames and/or directories containing templates (*required*)
36
- def initialize(context:, global_timeout: nil, selector: nil, filenames: [], logger: nil)
37
+ def initialize(context:, global_timeout: nil, selector: nil, filenames: [], logger: nil, kubeconfig: nil)
37
38
  template_paths = filenames.map { |path| File.expand_path(path) }
38
39
 
39
- @task_config = TaskConfig.new(context, nil, logger)
40
+ @task_config = TaskConfig.new(context, nil, logger, kubeconfig)
40
41
  @template_sets = TemplateSets.from_dirs_and_files(paths: template_paths,
41
42
  logger: @task_config.logger, render_erb: false)
42
43
  @global_timeout = global_timeout
@@ -46,8 +47,8 @@ module Krane
46
47
  # Runs the task, returning a boolean representing success or failure
47
48
  #
48
49
  # @return [Boolean]
49
- def run(*args)
50
- run!(*args)
50
+ def run(**args)
51
+ run!(**args)
51
52
  true
52
53
  rescue FatalDeploymentError
53
54
  false
@@ -133,11 +134,6 @@ module Krane
133
134
  r.validate_definition(@kubectl, selector: @selector)
134
135
  end
135
136
 
136
- resources.select(&:has_warnings?).each do |resource|
137
- record_warnings(logger: logger, warning: resource.validation_warning_msg,
138
- filename: File.basename(resource.file_path))
139
- end
140
-
141
137
  failed_resources = resources.select(&:validation_failed?)
142
138
  if failed_resources.present?
143
139
  failed_resources.each do |r|
@@ -173,6 +169,8 @@ module Krane
173
169
  logger.info(" - #{r.id}")
174
170
  end
175
171
 
172
+ StatsD.client.gauge('discover_resources.count', resources.size, tags: statsd_tags)
173
+
176
174
  resources.sort
177
175
  rescue InvalidTemplateError => e
178
176
  record_invalid_template(logger: logger, err: e.message, filename: e.filename, content: e.content)
@@ -192,10 +190,6 @@ module Krane
192
190
  @kubectl ||= Kubectl.new(task_config: @task_config, log_failure_by_default: true)
193
191
  end
194
192
 
195
- def kubeclient_builder
196
- @kubeclient_builder ||= KubeclientBuilder.new
197
- end
198
-
199
193
  def prune_whitelist
200
194
  cluster_resource_discoverer.prunable_resources(namespaced: false)
201
195
  end