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 +4 -4
- data/CHANGELOG.md +5 -0
- data/Gemfile +14 -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 +268 -32
- data/rbi/kubernetes-cli.rbi +219 -0
- data/spec/cli_spec.rb +597 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/support/matchers.rb +122 -0
- data/spec/support/test_cli.rb +37 -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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b93bf8e3f620c17f2781d2eb5f2748f970982a854d0aa622d3313b1d74104d3b
|
4
|
+
data.tar.gz: 9c7d170e2ab873b66cfbf6a12532260e3442781330c9e96363e472d354ff997a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0156747413340bab08b571bf13db212d0a8397ceb0b733fbc152c7835080f203400f6f1554829c74dab4fe1b743b3f3eda3d2e11950896f01da6b9bedf5bc3ca
|
7
|
+
data.tar.gz: c21786be60e403d60d2c39fd7be371a7043539412000e9cff2ea197e37092fe38a2bc621a6413266aabd0b8633656375056ce46745ac65726eb08c3e31cd14e3
|
data/CHANGELOG.md
CHANGED
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 '
|
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 '
|
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
data/kubernetes-cli.gemspec
CHANGED
@@ -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.
|
14
|
+
s.add_dependency 'kubectl-rb', '~> 0.2'
|
15
15
|
|
16
16
|
s.require_path = 'lib'
|
17
|
-
s.files = Dir['{lib,spec,
|
17
|
+
s.files = Dir['{lib,spec,rbi}/**/*', 'Gemfile', 'LICENSE', 'CHANGELOG.md', 'README.md', 'Rakefile', 'kubernetes-cli.gemspec']
|
18
18
|
end
|
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
|
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
|
-
|
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
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)
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
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
|