kubernetes-cli 0.3.2 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e2b3ae42d2a905be32a61c55740bff526f43874dfd9c194391814fea0bb4d8a5
4
- data.tar.gz: 624b91b4024dbed3b29ccdd8b2537b4e5a2f65d4df72d6a05f6e5141f7bb3c1c
3
+ metadata.gz: b93bf8e3f620c17f2781d2eb5f2748f970982a854d0aa622d3313b1d74104d3b
4
+ data.tar.gz: 9c7d170e2ab873b66cfbf6a12532260e3442781330c9e96363e472d354ff997a
5
5
  SHA512:
6
- metadata.gz: 892beee416b11f888cb91fa454bbfde2d4d9464cad77de079a9c1ccbe3c3c05ce285c24fb1e0036a00c999fb344101013cfb10e14a8aadaea95e4ca336bd0351
7
- data.tar.gz: ffbf3c1358d19e589b5763c3dbe51de8e622d1dccf9dfda05727cefc0ef3fc8fed4a037ff664a3f7e42e9a6052559e2d9f6a4dd8ca5cba8c4bf74e6e465fbe77
6
+ metadata.gz: 0156747413340bab08b571bf13db212d0a8397ceb0b733fbc152c7835080f203400f6f1554829c74dab4fe1b743b3f3eda3d2e11950896f01da6b9bedf5bc3ca
7
+ data.tar.gz: c21786be60e403d60d2c39fd7be371a7043539412000e9cff2ea197e37092fe38a2bc621a6413266aabd0b8633656375056ce46745ac65726eb08c3e31cd14e3
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 0.4.0
2
+ * Add `#version` method to get k8s client/server version info.
3
+ * Add Sorbet type definitions.
4
+ * Add tests.
5
+
1
6
  ## 0.3.2
2
7
  * Add missing require statement.
3
8
 
data/Gemfile CHANGED
@@ -6,10 +6,21 @@ gemspec
6
6
  # See: https://github.com/rubygems/rubygems/issues/3646
7
7
  gem 'kubectl-rb'
8
8
 
9
+ group :test do
10
+ gem 'rspec'
11
+ gem 'kind-rb', '~> 0.1'
12
+ gem 'kube-dsl', '~> 0.6'
13
+ end
14
+
9
15
  group :development do
10
- gem 'rake'
16
+ gem 'curdle', '~> 1.0'
17
+
18
+ # lock to same version as kuby-core
19
+ gem 'sorbet', '= 0.5.6433'
20
+ gem 'parlour', '~> 6.0'
11
21
  end
12
22
 
13
- group :test do
14
- gem 'rspec'
23
+ group :development, :test do
24
+ gem 'pry-byebug'
25
+ gem 'rake'
15
26
  end
data/README.md ADDED
@@ -0,0 +1,49 @@
1
+ ## kubernetes-cli
2
+
3
+ ![Unit Tests](https://github.com/getkuby/kuby-core/actions/workflows/unit_tests.yml/badge.svg?branch=master)
4
+ ![Integration Tests](https://github.com/getkuby/kuby-core/actions/workflows/integration_tests.yml/badge.svg?branch=master)
5
+
6
+ A Ruby wrapper around the Kubernetes CLI.
7
+
8
+ ### Usage
9
+
10
+ Create a new instance by passing the path to your Kube config (usually ~/.kube/config) and optionally the path to the kubectl executable (by default, the executable path comes from the [kubectl-rb gem](https://github.com/getkuby/kubectl-rb)).
11
+
12
+ ```ruby
13
+ cli = KubernetesCLI(File.join(ENV['HOME'], '.kube', 'config'))
14
+ ```
15
+
16
+ ### Available Methods
17
+
18
+ - `annotate`
19
+ - `api_resources`
20
+ - `apply`
21
+ - `apply_uri`
22
+ - `current_context`
23
+ - `delete_object`
24
+ - `delete_objects`
25
+ - `exec_cmd`
26
+ - `executable`
27
+ - `get_object`
28
+ - `get_objects`
29
+ - `kubeconfig_path`
30
+ - `last_status`
31
+ - `logtail`
32
+ - `patch_object`
33
+ - `restart_deployment`
34
+ - `run_cmd`
35
+ - `system_cmd`
36
+
37
+ Please see the source code for available options.
38
+
39
+ ## Running Tests
40
+
41
+ `bundle exec rspec` should do the trick. Requires that you have Docker installed.
42
+
43
+ ## License
44
+
45
+ Licensed under the MIT license. See LICENSE for details.
46
+
47
+ ## Authors
48
+
49
+ * Cameron C. Dutro: http://github.com/camertron
data/Rakefile CHANGED
@@ -2,9 +2,11 @@ require 'bundler'
2
2
  require 'rspec/core/rake_task'
3
3
  require 'rubygems/package_task'
4
4
 
5
+ require 'sorbet-runtime'
5
6
  require 'kubernetes-cli'
7
+ require 'curdle'
6
8
 
7
- Bundler::GemHelper.install_tasks
9
+ Curdle::Tasks.install
8
10
 
9
11
  task default: :spec
10
12
 
@@ -11,8 +11,8 @@ Gem::Specification.new do |s|
11
11
 
12
12
  s.description = s.summary = 'Ruby wrapper around the Kubernetes CLI.'
13
13
 
14
- s.add_dependency 'kubectl-rb', '~> 0.1'
14
+ s.add_dependency 'kubectl-rb', '~> 0.2'
15
15
 
16
16
  s.require_path = 'lib'
17
- s.files = Dir['{lib,spec,vendor}/**/*', 'Gemfile', 'LICENSE', 'CHANGELOG.md', 'README.md', 'Rakefile', 'kubernetes-cli.gemspec']
17
+ s.files = Dir['{lib,spec,rbi}/**/*', 'Gemfile', 'LICENSE', 'CHANGELOG.md', 'README.md', 'Rakefile', 'kubernetes-cli.gemspec']
18
18
  end
@@ -1,3 +1,5 @@
1
+ # typed: ignore
2
+
1
3
  class KubernetesCLI
2
- VERSION = '0.3.2'
4
+ VERSION = '0.4.0'.freeze
3
5
  end
@@ -1,65 +1,161 @@
1
+ # typed: strict
2
+
3
+ require 'json'
1
4
  require 'kubectl-rb'
2
5
  require 'open3'
6
+ require 'shellwords'
3
7
  require 'stringio'
4
- require 'json'
5
8
 
6
9
  class KubernetesCLI
10
+ # extend T::Sig
11
+
7
12
  class KubernetesError < StandardError; end
8
13
 
9
14
  class InvalidResourceError < KubernetesError
10
- attr_accessor :resource
15
+ # extend T::Sig
16
+
17
+ # T::Sig::WithoutRuntime.sig { returns(T.nilable(::KubeDSL::DSLObject)) }
18
+ attr_reader :resource
19
+
20
+ # T::Sig::WithoutRuntime.sig { params(resource: ::KubeDSL::DSLObject).returns(::KubeDSL::DSLObject) }
21
+ attr_writer :resource
22
+
23
+ # T::Sig::WithoutRuntime.sig { params(args: T.untyped).void }
24
+ def initialize(*args)
25
+ # @resource = T.let(@resource, T.nilable(::KubeDSL::DSLObject))
26
+ super
27
+ end
11
28
  end
12
29
 
13
30
  class InvalidResourceUriError < KubernetesError
14
- attr_accessor :resource_uri
31
+ # extend T::Sig
32
+
33
+ # T::Sig::WithoutRuntime.sig { returns(T.nilable(String)) }
34
+ attr_reader :resource_uri
35
+
36
+ # T::Sig::WithoutRuntime.sig { params(resource_uri: String).returns(String) }
37
+ attr_writer :resource_uri
38
+
39
+ # T::Sig::WithoutRuntime.sig { params(args: T.untyped).void }
40
+ def initialize(*args)
41
+ # @resource_uri = T.let(@resource_uri, T.nilable(String))
42
+ super
43
+ end
15
44
  end
16
45
 
17
46
  class GetResourceError < KubernetesError; end
47
+ class DeleteResourceError < KubernetesError; end
48
+ class PatchResourceError < KubernetesError; end
49
+ class AnnotateResourceError < KubernetesError; end
50
+ class GetVersionError < KubernetesError; end
18
51
 
19
52
  STATUS_KEY = :kubernetes_cli_last_status
20
53
  STDOUT_KEY = :kubernetes_cli_stdout
21
54
  STDERR_KEY = :kubernetes_cli_stderr
22
55
 
23
- attr_reader :kubeconfig_path, :executable
56
+ # T::Sig::WithoutRuntime.sig { returns(String) }
57
+ attr_reader :kubeconfig_path
58
+
59
+ # T::Sig::WithoutRuntime.sig { returns(String) }
60
+ attr_reader :executable
24
61
 
62
+ # BeforeCallback = T.type_alias { T.proc.params(cmd: T::Array[String]).void }
63
+ # AfterCallback = T.type_alias do
64
+ # T.proc.params(cmd: T::Array[String], last_status: Process::Status).void
65
+ # end
66
+
67
+ # T::Sig::WithoutRuntime.sig { params(kubeconfig_path: String, executable: String).void }
25
68
  def initialize(kubeconfig_path, executable = KubectlRb.executable)
26
69
  @kubeconfig_path = kubeconfig_path
27
70
  @executable = executable
28
71
  @before_execute = []
29
72
  @after_execute = []
73
+ # @env = T.let(@env, T.nilable(T::Hash[String, String]))
30
74
  end
31
75
 
76
+ # T::Sig::WithoutRuntime.sig { params(block: BeforeCallback).void }
32
77
  def before_execute(&block)
33
78
  @before_execute << block
34
79
  end
35
80
 
81
+ # T::Sig::WithoutRuntime.sig { params(block: AfterCallback).void }
36
82
  def after_execute(&block)
37
83
  @after_execute << block
38
84
  end
39
85
 
86
+ # T::Sig::WithoutRuntime.sig { returns(T.nilable(Process::Status)) }
40
87
  def last_status
41
88
  Thread.current[STATUS_KEY]
42
89
  end
43
90
 
91
+ # T::Sig::WithoutRuntime.sig { params(block: T.proc.params(last_status: Process::Status).void).void }
92
+ def with_last_status(&block)
93
+ block.call(last_status)
94
+ end
95
+
96
+ # T::Sig::WithoutRuntime.sig { params(block: T.proc.params(last_status: Process::Status).void).void }
97
+ def on_last_status_failure(&block)
98
+ with_last_status do |ls|
99
+ block.call(ls) unless ls.success?
100
+ end
101
+ end
102
+
103
+ # T::Sig::WithoutRuntime.sig { returns(T::Hash[T.untyped, T.untyped]) }
104
+ def version
105
+ cmd = [executable, '--kubeconfig', kubeconfig_path, 'version', '-o', 'json']
106
+ result = backticks(cmd)
107
+
108
+ on_last_status_failure do |last_status|
109
+ raise GetVersionError, "couldn't get version info: "\
110
+ "kubectl exited with status code #{last_status.exitstatus}"
111
+ end
112
+
113
+ JSON.parse(result)
114
+ end
115
+
116
+ # T::Sig::WithoutRuntime.sig { params(cmd: T.any(String, T::Array[String])).void }
44
117
  def run_cmd(cmd)
45
118
  cmd = [executable, '--kubeconfig', kubeconfig_path, *Array(cmd)]
46
119
  execc(cmd)
47
120
  end
48
121
 
49
- def exec_cmd(container_cmd, namespace, pod, tty = true)
122
+ # T::Sig::WithoutRuntime.sig {
123
+ # params(
124
+ # container_cmd: T.any(String, T::Array[String]),
125
+ # namespace: String,
126
+ # pod: String,
127
+ # tty: T::Boolean,
128
+ # container: T.nilable(String),
129
+ # out_file: T.nilable(String)
130
+ # ).void
131
+ # }
132
+ def exec_cmd(container_cmd, namespace, pod, tty = true, container = nil, out_file = nil)
50
133
  cmd = [executable, '--kubeconfig', kubeconfig_path, '-n', namespace, 'exec']
51
134
  cmd += ['-it'] if tty
135
+ cmd += ['-c', container] if container
52
136
  cmd += [pod, '--', *Array(container_cmd)]
137
+ cmd += ['>', out_file] if out_file
53
138
  execc(cmd)
54
139
  end
55
140
 
56
- def system_cmd(container_cmd, namespace, pod, tty = true)
141
+ # T::Sig::WithoutRuntime.sig {
142
+ # params(
143
+ # container_cmd: T.any(String, T::Array[String]),
144
+ # namespace: String,
145
+ # pod: String,
146
+ # tty: T::Boolean,
147
+ # container: T.nilable(String)
148
+ # ).void
149
+ # }
150
+ def system_cmd(container_cmd, namespace, pod, tty = true, container = nil)
57
151
  cmd = [executable, '--kubeconfig', kubeconfig_path, '-n', namespace, 'exec']
58
152
  cmd += ['-it'] if tty
153
+ cmd += ['-c', container] if container
59
154
  cmd += [pod, '--', *Array(container_cmd)]
60
155
  systemm(cmd)
61
156
  end
62
157
 
158
+ # T::Sig::WithoutRuntime.sig { params(res: ::KubeDSL::DSLObject, dry_run: T::Boolean).void }
63
159
  def apply(res, dry_run: false)
64
160
  cmd = [executable, '--kubeconfig', kubeconfig_path, 'apply', '--validate']
65
161
  cmd << '--dry-run=client' if dry_run
@@ -69,8 +165,8 @@ class KubernetesCLI
69
165
  stdin.puts(res.to_resource.to_yaml)
70
166
  end
71
167
 
72
- unless last_status.success?
73
- err = InvalidResourceError.new("Could not apply #{res.kind_sym.to_s.humanize.downcase} "\
168
+ on_last_status_failure do |last_status|
169
+ err = InvalidResourceError.new("Could not apply #{res.kind_sym} "\
74
170
  "'#{res.metadata.name}': kubectl exited with status code #{last_status.exitstatus}"
75
171
  )
76
172
 
@@ -79,13 +175,14 @@ class KubernetesCLI
79
175
  end
80
176
  end
81
177
 
178
+ # T::Sig::WithoutRuntime.sig { params(uri: String, dry_run: T::Boolean).void }
82
179
  def apply_uri(uri, dry_run: false)
83
180
  cmd = [executable, '--kubeconfig', kubeconfig_path, 'apply', '--validate']
84
181
  cmd << '--dry-run=client' if dry_run
85
182
  cmd += ['-f', uri]
86
183
  systemm(cmd)
87
184
 
88
- unless last_status.success?
185
+ on_last_status_failure do |last_status|
89
186
  err = InvalidResourceUriError.new("Could not apply #{uri}: "\
90
187
  "kubectl exited with status code #{last_status.exitstatus}"
91
188
  )
@@ -95,29 +192,48 @@ class KubernetesCLI
95
192
  end
96
193
  end
97
194
 
98
- def get_object(type, namespace, name = nil, match_labels = {})
99
- cmd = [executable, '--kubeconfig', kubeconfig_path, '-n', namespace]
195
+ # T::Sig::WithoutRuntime.sig {
196
+ # params(
197
+ # type: String,
198
+ # namespace: String,
199
+ # name: String
200
+ # ).returns(
201
+ # T::Hash[String, T.untyped]
202
+ # )
203
+ # }
204
+ def get_object(type, namespace, name)
205
+ cmd = [executable, '--kubeconfig', kubeconfig_path]
206
+ cmd += ['-n', namespace] if namespace
100
207
  cmd += ['get', type, name]
101
-
102
- unless match_labels.empty?
103
- cmd += ['--selector', match_labels.map { |key, value| "#{key}=#{value}" }.join(',')]
104
- end
105
-
106
208
  cmd += ['-o', 'json']
107
209
 
108
210
  result = backticks(cmd)
109
211
 
110
- unless last_status.success?
111
- raise GetResourceError, "couldn't get resources of type '#{type}' "\
212
+ on_last_status_failure do |last_status|
213
+ raise GetResourceError, "couldn't get resource of type '#{type}' named '#{name}' "\
112
214
  "in namespace #{namespace}: kubectl exited with status code #{last_status.exitstatus}"
113
215
  end
114
216
 
115
217
  JSON.parse(result)
116
218
  end
117
219
 
220
+ # T::Sig::WithoutRuntime.sig {
221
+ # params(
222
+ # type: String,
223
+ # namespace: T.any(String, Symbol),
224
+ # match_labels: T::Hash[String, String]
225
+ # ).returns(
226
+ # T::Array[T.untyped]
227
+ # )
228
+ # }
118
229
  def get_objects(type, namespace, match_labels = {})
119
- cmd = [executable, '--kubeconfig', kubeconfig_path, '-n', namespace]
120
- cmd += ['get', type]
230
+ cmd = [executable, '--kubeconfig', kubeconfig_path, 'get', type]
231
+
232
+ if namespace == :all
233
+ cmd << '--all-namespaces'
234
+ elsif namespace
235
+ cmd += ['-n', namespace.to_s]
236
+ end
121
237
 
122
238
  unless match_labels.empty?
123
239
  cmd += ['--selector', match_labels.map { |key, value| "#{key}=#{value}" }.join(',')]
@@ -127,7 +243,7 @@ class KubernetesCLI
127
243
 
128
244
  result = backticks(cmd)
129
245
 
130
- unless last_status.success?
246
+ on_last_status_failure do |last_status|
131
247
  raise GetResourceError, "couldn't get resources of type '#{type}' "\
132
248
  "in namespace #{namespace}: kubectl exited with status code #{last_status.exitstatus}"
133
249
  end
@@ -135,6 +251,89 @@ class KubernetesCLI
135
251
  JSON.parse(result)['items']
136
252
  end
137
253
 
254
+ # T::Sig::WithoutRuntime.sig {
255
+ # params(
256
+ # type: String,
257
+ # namespace: String,
258
+ # name: String
259
+ # ).void
260
+ # }
261
+ def delete_object(type, namespace, name)
262
+ cmd = [executable, '--kubeconfig', kubeconfig_path]
263
+ cmd += ['-n', namespace] if namespace
264
+ cmd += ['delete', type, name]
265
+
266
+ systemm(cmd)
267
+
268
+ on_last_status_failure do |last_status|
269
+ raise DeleteResourceError, "couldn't delete resource of type '#{type}' named '#{name}' "\
270
+ "in namespace #{namespace}: kubectl exited with status code #{last_status.exitstatus}"
271
+ end
272
+ end
273
+
274
+ # T::Sig::WithoutRuntime.sig {
275
+ # params(
276
+ # type: String,
277
+ # namespace: T.any(String, Symbol),
278
+ # match_labels: T::Hash[String, String]
279
+ # ).void
280
+ # }
281
+ def delete_objects(type, namespace, match_labels = {})
282
+ cmd = [executable, '--kubeconfig', kubeconfig_path]
283
+
284
+ if namespace == :all
285
+ cmd << '--all-namespaces'
286
+ elsif namespace
287
+ cmd += ['-n', namespace.to_s]
288
+ end
289
+
290
+ cmd += ['delete', type]
291
+
292
+ unless match_labels.empty?
293
+ cmd += ['--selector', match_labels.map { |key, value| "#{key}=#{value}" }.join(',')]
294
+ end
295
+
296
+ systemm(cmd)
297
+
298
+ on_last_status_failure do |last_status|
299
+ raise DeleteResourceError, "couldn't delete resources of type '#{type}' "\
300
+ "in namespace #{namespace}: kubectl exited with status code #{last_status.exitstatus}"
301
+ end
302
+ end
303
+
304
+ # T::Sig::WithoutRuntime.sig {
305
+ # params(
306
+ # type: String,
307
+ # namespace: String,
308
+ # name: String,
309
+ # patch_data: String,
310
+ # patch_type: String
311
+ # ).void
312
+ # }
313
+ def patch_object(type, namespace, name, patch_data, patch_type = 'merge')
314
+ cmd = [executable, '--kubeconfig', kubeconfig_path]
315
+ cmd += ['-n', namespace] if namespace
316
+ cmd += ['patch', type, name]
317
+ cmd += ['-p', Shellwords.shellescape(patch_data)]
318
+ cmd += ['--type', patch_type]
319
+
320
+ systemm(cmd)
321
+
322
+ on_last_status_failure do |last_status|
323
+ raise PatchResourceError, "couldn't patch resource of type '#{type}' named '#{name}' "\
324
+ "in namespace #{namespace}: kubectl exited with status code #{last_status.exitstatus}"
325
+ end
326
+ end
327
+
328
+ # T::Sig::WithoutRuntime.sig {
329
+ # params(
330
+ # type: String,
331
+ # namespace: String,
332
+ # name: String,
333
+ # annotations: T::Hash[String, String],
334
+ # overwrite: T::Boolean
335
+ # ).void
336
+ # }
138
337
  def annotate(type, namespace, name, annotations, overwrite: true)
139
338
  cmd = [
140
339
  executable,
@@ -152,12 +351,19 @@ class KubernetesCLI
152
351
 
153
352
  systemm(cmd)
154
353
 
155
- unless last_status.success?
156
- raise KubernetesError, "could not annotate resource '#{name}': kubectl "\
354
+ on_last_status_failure do |last_status|
355
+ raise AnnotateResourceError, "could not annotate resource '#{name}': kubectl "\
157
356
  "exited with status code #{last_status.exitstatus}"
158
357
  end
159
358
  end
160
359
 
360
+ # T::Sig::WithoutRuntime.sig {
361
+ # params(
362
+ # namespace: String,
363
+ # selector: T::Hash[String, String],
364
+ # follow: T::Boolean
365
+ # ).void
366
+ # }
161
367
  def logtail(namespace, selector, follow: true)
162
368
  cmd = [executable, '--kubeconfig', kubeconfig_path, '-n', namespace, 'logs']
163
369
  cmd << '-f' if follow
@@ -166,16 +372,18 @@ class KubernetesCLI
166
372
  execc(cmd)
167
373
  end
168
374
 
375
+ # T::Sig::WithoutRuntime.sig { returns(String) }
169
376
  def current_context
170
377
  cmd = [executable, '--kubeconfig', kubeconfig_path, 'config', 'current-context']
171
378
  backticks(cmd).strip
172
379
  end
173
380
 
381
+ # T::Sig::WithoutRuntime.sig { returns(String) }
174
382
  def api_resources
175
383
  cmd = [executable, '--kubeconfig', kubeconfig_path, 'api-resources']
176
384
  result = backticks(cmd)
177
385
 
178
- unless last_status.success?
386
+ on_last_status_failure do |last_status|
179
387
  raise KubernetesError, 'could not fetch API resources: kubectl exited with '\
180
388
  "status code #{last_status.exitstatus}. #{result}"
181
389
  end
@@ -183,6 +391,7 @@ class KubernetesCLI
183
391
  result
184
392
  end
185
393
 
394
+ # T::Sig::WithoutRuntime.sig { params(namespace: String, deployment: String).void }
186
395
  def restart_deployment(namespace, deployment)
187
396
  cmd = [
188
397
  executable,
@@ -193,13 +402,14 @@ class KubernetesCLI
193
402
 
194
403
  systemm(cmd)
195
404
 
196
- unless last_status.success?
405
+ on_last_status_failure do |last_status|
197
406
  raise KubernetesError, 'could not restart deployment: kubectl exited with '\
198
407
  "status code #{last_status.exitstatus}"
199
408
  end
200
409
  end
201
410
 
202
- def with_pipes(out = STDOUT, err = STDERR)
411
+ # T::Sig::WithoutRuntime.sig { params(out: T.any(StringIO, IO), err: T.any(StringIO, IO), block: T.proc.void).void }
412
+ def with_pipes(out = STDOUT, err = STDERR, &block)
203
413
  previous_stdout = self.stdout
204
414
  previous_stderr = self.stderr
205
415
  self.stdout = out
@@ -210,38 +420,46 @@ class KubernetesCLI
210
420
  self.stderr = previous_stderr
211
421
  end
212
422
 
423
+ # T::Sig::WithoutRuntime.sig { returns(T.any(StringIO, IO)) }
213
424
  def stdout
214
425
  Thread.current[STDOUT_KEY] || STDOUT
215
426
  end
216
427
 
428
+ # T::Sig::WithoutRuntime.sig { params(new_stdout: T.nilable(T.any(StringIO, IO))).void }
217
429
  def stdout=(new_stdout)
218
430
  Thread.current[STDOUT_KEY] = new_stdout
219
431
  end
220
432
 
433
+ # T::Sig::WithoutRuntime.sig { returns(T.any(StringIO, IO)) }
221
434
  def stderr
222
435
  Thread.current[STDERR_KEY] || STDERR
223
436
  end
224
437
 
438
+ # T::Sig::WithoutRuntime.sig { params(new_stderr: T.nilable(T.any(StringIO, IO))).void }
225
439
  def stderr=(new_stderr)
226
440
  Thread.current[STDERR_KEY] = new_stderr
227
441
  end
228
442
 
229
443
  private
230
444
 
445
+ # T::Sig::WithoutRuntime.sig { returns(T::Hash[String, String]) }
231
446
  def env
232
447
  @env ||= {}
233
448
  end
234
449
 
450
+ # T::Sig::WithoutRuntime.sig { returns(T::Array[String]) }
235
451
  def base_cmd
236
452
  [executable, '--kubeconfig', kubeconfig_path]
237
453
  end
238
454
 
455
+ # T::Sig::WithoutRuntime.sig { params(cmd: T::Array[String]).void }
239
456
  def execc(cmd)
240
457
  run_before_callbacks(cmd)
241
458
  cmd_s = cmd.join(' ')
242
459
  exec(cmd_s)
243
460
  end
244
461
 
462
+ # T::Sig::WithoutRuntime.sig { params(cmd: T::Array[String]).void }
245
463
  def systemm(cmd)
246
464
  if stdout == STDOUT && stderr == STDERR
247
465
  systemm_default(cmd)
@@ -250,6 +468,7 @@ class KubernetesCLI
250
468
  end
251
469
  end
252
470
 
471
+ # T::Sig::WithoutRuntime.sig { params(cmd: T::Array[String]).void }
253
472
  def systemm_default(cmd)
254
473
  run_before_callbacks(cmd)
255
474
  cmd_s = cmd.join(' ')
@@ -259,6 +478,7 @@ class KubernetesCLI
259
478
  end
260
479
  end
261
480
 
481
+ # T::Sig::WithoutRuntime.sig { params(cmd: T::Array[String]).void }
262
482
  def systemm_open3(cmd)
263
483
  run_before_callbacks(cmd)
264
484
  cmd_s = cmd.join(' ')
@@ -285,6 +505,7 @@ class KubernetesCLI
285
505
  end
286
506
  end
287
507
 
508
+ # T::Sig::WithoutRuntime.sig { params(cmd: T::Array[String]).returns(String) }
288
509
  def backticks(cmd)
289
510
  if stdout == STDOUT && stderr == STDERR
290
511
  backticks_default(cmd)
@@ -293,6 +514,7 @@ class KubernetesCLI
293
514
  end
294
515
  end
295
516
 
517
+ # T::Sig::WithoutRuntime.sig { params(cmd: T::Array[String]).returns(String) }
296
518
  def backticks_default(cmd)
297
519
  run_before_callbacks(cmd)
298
520
  cmd_s = cmd.join(' ')
@@ -302,6 +524,7 @@ class KubernetesCLI
302
524
  end
303
525
  end
304
526
 
527
+ # T::Sig::WithoutRuntime.sig { params(cmd: T::Array[String]).returns(String) }
305
528
  def backticks_open3(cmd)
306
529
  run_before_callbacks(cmd)
307
530
  cmd_s = cmd.join(' ')
@@ -331,10 +554,20 @@ class KubernetesCLI
331
554
  result.string
332
555
  end
333
556
 
557
+ # T::Sig::WithoutRuntime.sig {
558
+ # params(
559
+ # env: T::Hash[String, String],
560
+ # cmd: T::Array[String],
561
+ # opts: T::Hash[Symbol, T.untyped],
562
+ # block: T.proc.params(p_stdin: IO).void
563
+ # ).void
564
+ # }
334
565
  def open3_w(env, cmd, opts = {}, &block)
335
566
  run_before_callbacks(cmd)
336
567
  cmd_s = cmd.join(' ')
337
568
 
569
+ # unsafes here b/c popen3 takes an optional first argument hash
570
+ # with environment variables, which confuses the sh*t out of sorbet
338
571
  Open3.popen3(env, cmd_s, opts) do |p_stdin, p_stdout, p_stderr, wait_thread|
339
572
  Thread.new(stdout) do |t_stdout|
340
573
  begin
@@ -350,23 +583,26 @@ class KubernetesCLI
350
583
  end
351
584
  end
352
585
 
353
- yield(p_stdin).tap do
354
- p_stdin.close
355
- self.last_status = wait_thread.value
356
- run_after_callbacks(cmd)
357
- wait_thread.join
358
- end
586
+ yield(p_stdin)
587
+
588
+ p_stdin.close
589
+ self.last_status = wait_thread.value
590
+ run_after_callbacks(cmd)
591
+ wait_thread.join
359
592
  end
360
593
  end
361
594
 
595
+ # T::Sig::WithoutRuntime.sig { params(cmd: T::Array[String]).void }
362
596
  def run_before_callbacks(cmd)
363
597
  @before_execute.each { |cb| cb.call(cmd) }
364
598
  end
365
599
 
600
+ # T::Sig::WithoutRuntime.sig { params(cmd: T::Array[String]).void }
366
601
  def run_after_callbacks(cmd)
367
602
  @after_execute.each { |cb| cb.call(cmd, last_status) }
368
603
  end
369
604
 
605
+ # T::Sig::WithoutRuntime.sig { params(status: Process::Status).void }
370
606
  def last_status=(status)
371
607
  Thread.current[STATUS_KEY] = status
372
608
  end