kubernetes-cli 0.3.2 → 0.5.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 +4 -4
- data/CHANGELOG.md +8 -0
- data/Gemfile +15 -3
- data/README.md +49 -0
- data/Rakefile +3 -1
- data/kubernetes-cli.gemspec +2 -2
- data/lib/kubernetes-cli/version.rb +3 -1
- data/lib/kubernetes-cli.rb +274 -52
- data/rbi/kubernetes-cli.rbi +216 -0
- data/spec/cli_spec.rb +597 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/support/matchers.rb +123 -0
- data/spec/support/test_cli.rb +31 -0
- data/spec/support/test_config_map.yaml +7 -0
- data/spec/support/test_config_map_bad.yaml +8 -0
- data/spec/support/test_resource.rb +22 -0
- metadata +14 -5
data/lib/kubernetes-cli.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
56
|
+
# T::Sig::WithoutRuntime.sig { returns(String) }
|
57
|
+
attr_reader :kubeconfig_path
|
58
|
+
|
59
|
+
# T::Sig::WithoutRuntime.sig { returns(String) }
|
60
|
+
attr_reader :executable
|
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
|
24
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
|
-
|
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
|
-
|
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
|
-
|
73
|
-
err = InvalidResourceError.new("Could not apply #{res.kind_sym
|
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
|
-
|
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
|
-
|
99
|
-
|
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
|
-
|
111
|
-
raise GetResourceError, "couldn't get
|
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, '
|
120
|
-
|
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
|
-
|
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
|
-
|
156
|
-
raise
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
230
|
-
|
443
|
+
# T::Sig::WithoutRuntime.sig { returns(T::Hash[String, String]) }
|
231
444
|
def env
|
232
445
|
@env ||= {}
|
233
446
|
end
|
234
447
|
|
448
|
+
private
|
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
|
-
exec(cmd_s)
|
459
|
+
exec(env, 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,20 +468,22 @@ 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(' ')
|
256
|
-
system(cmd_s).tap do
|
475
|
+
system(env, cmd_s).tap do
|
257
476
|
self.last_status = $?
|
258
477
|
run_after_callbacks(cmd)
|
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(' ')
|
265
485
|
|
266
|
-
Open3.popen3(cmd_s) do |p_stdin, p_stdout, p_stderr, wait_thread|
|
486
|
+
Open3.popen3(env, cmd_s) do |p_stdin, p_stdout, p_stderr, wait_thread|
|
267
487
|
Thread.new(stdout) do |t_stdout|
|
268
488
|
begin
|
269
489
|
p_stdout.each { |line| t_stdout.puts(line) }
|
@@ -285,29 +505,18 @@ 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
|
-
|
290
|
-
backticks_default(cmd)
|
291
|
-
else
|
292
|
-
backticks_open3(cmd)
|
293
|
-
end
|
294
|
-
end
|
295
|
-
|
296
|
-
def backticks_default(cmd)
|
297
|
-
run_before_callbacks(cmd)
|
298
|
-
cmd_s = cmd.join(' ')
|
299
|
-
`#{cmd_s}`.tap do
|
300
|
-
self.last_status = $?
|
301
|
-
run_after_callbacks(cmd)
|
302
|
-
end
|
510
|
+
backticks_open3(cmd)
|
303
511
|
end
|
304
512
|
|
513
|
+
# T::Sig::WithoutRuntime.sig { params(cmd: T::Array[String]).returns(String) }
|
305
514
|
def backticks_open3(cmd)
|
306
515
|
run_before_callbacks(cmd)
|
307
516
|
cmd_s = cmd.join(' ')
|
308
517
|
result = StringIO.new
|
309
518
|
|
310
|
-
Open3.popen3(cmd_s) do |p_stdin, p_stdout, p_stderr, wait_thread|
|
519
|
+
Open3.popen3(env, cmd_s) do |p_stdin, p_stdout, p_stderr, wait_thread|
|
311
520
|
Thread.new do
|
312
521
|
begin
|
313
522
|
p_stdout.each { |line| result.puts(line) }
|
@@ -331,10 +540,20 @@ class KubernetesCLI
|
|
331
540
|
result.string
|
332
541
|
end
|
333
542
|
|
543
|
+
# T::Sig::WithoutRuntime.sig {
|
544
|
+
# params(
|
545
|
+
# env: T::Hash[String, String],
|
546
|
+
# cmd: T::Array[String],
|
547
|
+
# opts: T::Hash[Symbol, T.untyped],
|
548
|
+
# block: T.proc.params(p_stdin: IO).void
|
549
|
+
# ).void
|
550
|
+
# }
|
334
551
|
def open3_w(env, cmd, opts = {}, &block)
|
335
552
|
run_before_callbacks(cmd)
|
336
553
|
cmd_s = cmd.join(' ')
|
337
554
|
|
555
|
+
# unsafes here b/c popen3 takes an optional first argument hash
|
556
|
+
# with environment variables, which confuses the sh*t out of sorbet
|
338
557
|
Open3.popen3(env, cmd_s, opts) do |p_stdin, p_stdout, p_stderr, wait_thread|
|
339
558
|
Thread.new(stdout) do |t_stdout|
|
340
559
|
begin
|
@@ -350,23 +569,26 @@ class KubernetesCLI
|
|
350
569
|
end
|
351
570
|
end
|
352
571
|
|
353
|
-
yield(p_stdin)
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
572
|
+
yield(p_stdin)
|
573
|
+
|
574
|
+
p_stdin.close
|
575
|
+
self.last_status = wait_thread.value
|
576
|
+
run_after_callbacks(cmd)
|
577
|
+
wait_thread.join
|
359
578
|
end
|
360
579
|
end
|
361
580
|
|
581
|
+
# T::Sig::WithoutRuntime.sig { params(cmd: T::Array[String]).void }
|
362
582
|
def run_before_callbacks(cmd)
|
363
583
|
@before_execute.each { |cb| cb.call(cmd) }
|
364
584
|
end
|
365
585
|
|
586
|
+
# T::Sig::WithoutRuntime.sig { params(cmd: T::Array[String]).void }
|
366
587
|
def run_after_callbacks(cmd)
|
367
588
|
@after_execute.each { |cb| cb.call(cmd, last_status) }
|
368
589
|
end
|
369
590
|
|
591
|
+
# T::Sig::WithoutRuntime.sig { params(status: Process::Status).void }
|
370
592
|
def last_status=(status)
|
371
593
|
Thread.current[STATUS_KEY] = status
|
372
594
|
end
|