kubernetes-cli 0.3.2 → 0.4.0

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