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 +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
data/spec/cli_spec.rb
ADDED
@@ -0,0 +1,597 @@
|
|
1
|
+
# typed: ignore
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
describe KubernetesCLI do
|
7
|
+
let(:kubeconfig_path) { File.join(ENV['HOME'], '.kube', 'config') }
|
8
|
+
let(:cli) { described_class.new(kubeconfig_path) }
|
9
|
+
let(:fake_cli) { TestCLI.new(kubeconfig_path) }
|
10
|
+
|
11
|
+
let(:deployment) do
|
12
|
+
KubeDSL.deployment do
|
13
|
+
metadata do
|
14
|
+
name 'test-deployment'
|
15
|
+
namespace 'test'
|
16
|
+
end
|
17
|
+
|
18
|
+
spec do
|
19
|
+
replicas 1
|
20
|
+
|
21
|
+
selector do
|
22
|
+
match_labels do
|
23
|
+
add :foo, 'bar'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
template do
|
28
|
+
metadata do
|
29
|
+
labels do
|
30
|
+
add :foo, 'bar'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
spec do
|
35
|
+
container(:ruby) do
|
36
|
+
image 'ruby:3.0'
|
37
|
+
image_pull_policy 'IfNotPresent'
|
38
|
+
name 'ruby'
|
39
|
+
command ['ruby', '-e', 'STDOUT.sync = true; loop { puts "alive"; sleep 5 }']
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
around do |example|
|
48
|
+
if ENV.fetch('SHOW_STDOUT', 'false') == 'true'
|
49
|
+
example.run
|
50
|
+
else
|
51
|
+
File.open(File::NULL, 'w') do |f|
|
52
|
+
cli.with_pipes(f, f) { example.run }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '#run_cmd' do
|
58
|
+
it 'includes the kubeconfig' do
|
59
|
+
fake_cli.run_cmd(%w(ls))
|
60
|
+
expect(fake_cli).to run_exec.with_args(['--kubeconfig', kubeconfig_path])
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'runs a kubectl command' do
|
64
|
+
fake_cli.run_cmd(%w(ls))
|
65
|
+
expect(fake_cli).to run_exec.with_args(['ls'])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '#system_cmd' do
|
70
|
+
it 'runs a command in a pod' do
|
71
|
+
cli.apply(deployment)
|
72
|
+
wait_for_deployment(deployment)
|
73
|
+
|
74
|
+
pods = cli.get_objects(
|
75
|
+
'Pod',
|
76
|
+
deployment.metadata.namespace,
|
77
|
+
deployment.spec.selector.match_labels.kv_pairs
|
78
|
+
)
|
79
|
+
|
80
|
+
stdout = StringIO.new
|
81
|
+
|
82
|
+
cli.with_pipes(stdout) do
|
83
|
+
cli.system_cmd(
|
84
|
+
['ruby', '-e', '"STDOUT.sync = true; puts 1 + 1"'],
|
85
|
+
deployment.metadata.namespace,
|
86
|
+
pods.first.dig(*%w(metadata name)),
|
87
|
+
false,
|
88
|
+
deployment.spec.template.spec.container(:ruby).name
|
89
|
+
)
|
90
|
+
end
|
91
|
+
|
92
|
+
expect(stdout.string.to_i).to eq(2)
|
93
|
+
ensure
|
94
|
+
safely_delete_res(deployment)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe '#exec_cmd' do
|
99
|
+
let(:container_cmd) { %w(ls) }
|
100
|
+
let(:namespace) { 'namespace' }
|
101
|
+
let(:pod) { 'pod' }
|
102
|
+
let(:container) { 'container' }
|
103
|
+
let(:out_file) { '/path/to/file' }
|
104
|
+
|
105
|
+
it 'includes the path to the kubeconfig' do
|
106
|
+
fake_cli.exec_cmd(container_cmd, namespace, pod)
|
107
|
+
expect(fake_cli).to run_exec.with_args(['--kubeconfig', kubeconfig_path])
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'includes the container command, namespace, and pod' do
|
111
|
+
fake_cli.exec_cmd(container_cmd, namespace, pod)
|
112
|
+
expect(fake_cli).to run_exec.with_args(['-n', namespace], [pod], ['--', 'ls'])
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'starts a TTY by default' do
|
116
|
+
fake_cli.exec_cmd(container_cmd, namespace, pod)
|
117
|
+
expect(fake_cli).to run_exec.with_args(['-it'])
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'does not start a TTY when asked not to' do
|
121
|
+
fake_cli.exec_cmd(container_cmd, namespace, pod, false)
|
122
|
+
expect(fake_cli).to run_exec.without_args(['-it'])
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'selects the container when given' do
|
126
|
+
fake_cli.exec_cmd(container_cmd, namespace, pod, true, container)
|
127
|
+
expect(fake_cli).to run_exec.with_args(['-c', container])
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'redirects standard output to a file when a file is given' do
|
131
|
+
fake_cli.exec_cmd(container_cmd, namespace, pod, true, nil, out_file)
|
132
|
+
expect(fake_cli).to run_exec.and_redirect_to(out_file)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
describe '#apply' do
|
137
|
+
let(:res) do
|
138
|
+
KubeDSL.config_map do
|
139
|
+
metadata do
|
140
|
+
namespace 'test'
|
141
|
+
name 'test-config'
|
142
|
+
end
|
143
|
+
|
144
|
+
data do
|
145
|
+
add 'key', 'value'
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
let(:bad_res) do
|
151
|
+
klass = Class.new(KubeDSL::DSL::V1::ConfigMap) do
|
152
|
+
value_field :non_existent
|
153
|
+
|
154
|
+
def serialize
|
155
|
+
super.merge(nonExistent: non_existent)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
klass.new do
|
160
|
+
metadata do
|
161
|
+
namespace 'test'
|
162
|
+
name 'test-config'
|
163
|
+
end
|
164
|
+
|
165
|
+
non_existent 'bad'
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'applies the resource' do
|
170
|
+
cli.apply(res)
|
171
|
+
obj = get_object(res)
|
172
|
+
expect(obj['data']).to eq({ 'key' => 'value' })
|
173
|
+
ensure
|
174
|
+
safely_delete_res(res)
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'raises an error if the resource is malformed' do
|
178
|
+
expect { cli.apply(bad_res) }.to raise_error do |error|
|
179
|
+
expect(error).to be_a(KubernetesCLI::InvalidResourceError)
|
180
|
+
expect(error.resource).to eq(bad_res)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
it "doesn't apply the resource if asked to perform a dry run" do
|
185
|
+
cli.apply(res, dry_run: true)
|
186
|
+
expect { get_object(res) }.to raise_error(KubernetesCLI::GetResourceError)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
describe '#apply_uri' do
|
191
|
+
let(:url) { 'https://raw.githubusercontent.com/getkuby/kubernetes-cli/master/spec/support/test_config_map.yaml' }
|
192
|
+
let(:bad_url) { 'https://raw.githubusercontent.com/getkuby/kubernetes-cli/master/spec/support/test_config_map_bad.yaml' }
|
193
|
+
let(:kind) { 'ConfigMap' }
|
194
|
+
let(:name) { 'test' }
|
195
|
+
let(:namespace) { 'test-config-external' }
|
196
|
+
|
197
|
+
it 'applies the external file' do
|
198
|
+
cli.apply_uri(url)
|
199
|
+
obj = cli.get_object(kind, name, namespace)
|
200
|
+
expect(obj['data']).to eq({ 'key' => 'external value' })
|
201
|
+
ensure
|
202
|
+
begin
|
203
|
+
cli.delete_object(kind, name, namespace)
|
204
|
+
rescue KubernetesCLI::DeleteResourceError
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'raises an error if the resource is malformed' do
|
209
|
+
expect { cli.apply_uri(bad_url) }.to raise_error do |error|
|
210
|
+
expect(error).to be_a(KubernetesCLI::InvalidResourceUriError)
|
211
|
+
expect(error.resource_uri).to eq(bad_url)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
it "doesn't apply the resource if asked to perform a dry run" do
|
216
|
+
cli.apply_uri(url, dry_run: true)
|
217
|
+
expect { cli.get_object(kind, name, namespace) }.to raise_error(KubernetesCLI::GetResourceError)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe '#get_object' do
|
222
|
+
let(:res) do
|
223
|
+
KubeDSL.config_map do
|
224
|
+
metadata do
|
225
|
+
namespace 'test'
|
226
|
+
name 'test-config'
|
227
|
+
labels do
|
228
|
+
add :foo, 'bar'
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
data do
|
233
|
+
add 'key', 'value'
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'gets the object by name' do
|
239
|
+
cli.apply(res)
|
240
|
+
obj = cli.get_object('ConfigMap', res.metadata.namespace, res.metadata.name)
|
241
|
+
expect(obj['data']).to eq({ 'key' => 'value' })
|
242
|
+
ensure
|
243
|
+
safely_delete_res(res)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
describe '#get_objects' do
|
248
|
+
let(:res1) do
|
249
|
+
KubeDSL.config_map do
|
250
|
+
metadata do
|
251
|
+
namespace 'test'
|
252
|
+
name 'test-config1'
|
253
|
+
labels do
|
254
|
+
add :foo, 'bar'
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
data do
|
259
|
+
add 'key1', 'value1'
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
let(:res2) do
|
265
|
+
KubeDSL.config_map do
|
266
|
+
metadata do
|
267
|
+
namespace 'test'
|
268
|
+
name 'test-config2'
|
269
|
+
labels do
|
270
|
+
add :baz, 'boo'
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
data do
|
275
|
+
add 'key2', 'value2'
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
let(:res3) do
|
281
|
+
KubeDSL.config_map do
|
282
|
+
metadata do
|
283
|
+
namespace 'test'
|
284
|
+
name 'test-config3'
|
285
|
+
labels do
|
286
|
+
add :foo, 'bar'
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
data do
|
291
|
+
add 'key3', 'value3'
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
it 'gets the object by its labels' do
|
297
|
+
cli.apply(res1)
|
298
|
+
cli.apply(res2)
|
299
|
+
cli.apply(res3)
|
300
|
+
obj = cli.get_objects('ConfigMap', res1.metadata.namespace, foo: 'bar')
|
301
|
+
expect(obj.size).to eq(2)
|
302
|
+
expect(obj.map { |o| o['metadata']['name'] }.sort).to eq(
|
303
|
+
['test-config1', 'test-config3']
|
304
|
+
)
|
305
|
+
ensure
|
306
|
+
safely_delete_res(res1)
|
307
|
+
safely_delete_res(res2)
|
308
|
+
safely_delete_res(res3)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
describe '#delete_object' do
|
313
|
+
let(:res) do
|
314
|
+
KubeDSL.config_map do
|
315
|
+
metadata do
|
316
|
+
namespace 'test'
|
317
|
+
name 'test-config'
|
318
|
+
end
|
319
|
+
|
320
|
+
data do
|
321
|
+
add 'key', 'value'
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
it 'deletes the resource' do
|
327
|
+
cli.apply(res)
|
328
|
+
cli.delete_object('ConfigMap', res.metadata.namespace, res.metadata.name)
|
329
|
+
expect { get_object(res) }.to raise_error(KubernetesCLI::GetResourceError)
|
330
|
+
ensure
|
331
|
+
safely_delete_res(res)
|
332
|
+
end
|
333
|
+
|
334
|
+
it "raises an error if the resource doesn't exist" do
|
335
|
+
expect { cli.delete_object('ConfigMap', res.metadata.namespace, res.metadata.name) }.to(
|
336
|
+
raise_error(KubernetesCLI::DeleteResourceError)
|
337
|
+
)
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
describe '#delete_objects' do
|
342
|
+
let(:res1) do
|
343
|
+
KubeDSL.config_map do
|
344
|
+
metadata do
|
345
|
+
namespace 'test'
|
346
|
+
name 'test-config1'
|
347
|
+
labels do
|
348
|
+
add :foo, 'bar'
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
data do
|
353
|
+
add 'key1', 'value1'
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
let(:res2) do
|
359
|
+
KubeDSL.config_map do
|
360
|
+
metadata do
|
361
|
+
namespace 'test'
|
362
|
+
name 'test-config2'
|
363
|
+
labels do
|
364
|
+
add :baz, 'boo'
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
data do
|
369
|
+
add 'key2', 'value2'
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
let(:res3) do
|
375
|
+
KubeDSL.config_map do
|
376
|
+
metadata do
|
377
|
+
namespace 'test'
|
378
|
+
name 'test-config3'
|
379
|
+
labels do
|
380
|
+
add :foo, 'bar'
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
data do
|
385
|
+
add 'key3', 'value3'
|
386
|
+
end
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
it 'deletes objects by their labels' do
|
391
|
+
cli.apply(res1)
|
392
|
+
cli.apply(res2)
|
393
|
+
cli.apply(res3)
|
394
|
+
cli.delete_objects('ConfigMap', res1.metadata.namespace, foo: 'bar')
|
395
|
+
expect { get_object(res1) }.to raise_error(KubernetesCLI::GetResourceError)
|
396
|
+
expect { get_object(res3) }.to raise_error(KubernetesCLI::GetResourceError)
|
397
|
+
ensure
|
398
|
+
safely_delete_res(res1)
|
399
|
+
safely_delete_res(res2)
|
400
|
+
safely_delete_res(res3)
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
describe '#patch_object' do
|
405
|
+
let(:res) do
|
406
|
+
KubeDSL.config_map do
|
407
|
+
metadata do
|
408
|
+
namespace 'test'
|
409
|
+
name 'test-config'
|
410
|
+
end
|
411
|
+
|
412
|
+
data do
|
413
|
+
add 'key', 'value'
|
414
|
+
end
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
it 'patches the object' do
|
419
|
+
cli.apply(res)
|
420
|
+
cli.patch_object('ConfigMap', res.metadata.namespace, res.metadata.name, '{"data":{"key":"patched"}}')
|
421
|
+
obj = get_object(res)
|
422
|
+
expect(obj['data']).to eq({ "key" => "patched" })
|
423
|
+
ensure
|
424
|
+
safely_delete_res(res)
|
425
|
+
end
|
426
|
+
|
427
|
+
it 'raises an error when patching fails' do
|
428
|
+
cli.apply(res)
|
429
|
+
expect {
|
430
|
+
cli.patch_object('ConfigMap', res.metadata.namespace, res.metadata.name, '{"data":{"key":}}')
|
431
|
+
}.to raise_error(KubernetesCLI::PatchResourceError)
|
432
|
+
ensure
|
433
|
+
safely_delete_res(res)
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
describe '#annotate' do
|
438
|
+
let(:res) do
|
439
|
+
KubeDSL.config_map do
|
440
|
+
metadata do
|
441
|
+
namespace 'test'
|
442
|
+
name 'test-config'
|
443
|
+
end
|
444
|
+
|
445
|
+
data do
|
446
|
+
add 'key', 'value'
|
447
|
+
end
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
it 'annotates the resource' do
|
452
|
+
cli.apply(res)
|
453
|
+
cli.annotate('ConfigMap', res.metadata.namespace, res.metadata.name, { foo: 'bar' })
|
454
|
+
obj = get_object(res)
|
455
|
+
annotations = obj.dig(*%w(metadata annotations))
|
456
|
+
expect(annotations).to include('foo' => 'bar')
|
457
|
+
ensure
|
458
|
+
safely_delete_res(res)
|
459
|
+
end
|
460
|
+
|
461
|
+
it 'does not overwrite annotations when option is given' do
|
462
|
+
cli.apply(res)
|
463
|
+
cli.annotate('ConfigMap', res.metadata.namespace, res.metadata.name, { foo: 'bar' })
|
464
|
+
expect {
|
465
|
+
cli.annotate('ConfigMap', res.metadata.namespace, res.metadata.name, { foo: 'baz' }, overwrite: false)
|
466
|
+
}.to raise_error(KubernetesCLI::AnnotateResourceError)
|
467
|
+
obj = get_object(res)
|
468
|
+
annotations = obj.dig(*%w(metadata annotations))
|
469
|
+
expect(annotations).to include('foo' => 'bar')
|
470
|
+
ensure
|
471
|
+
safely_delete_res(res)
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
describe '#logtail' do
|
476
|
+
let(:namespace) { 'namespace' }
|
477
|
+
let(:selector) { { role: 'web' } }
|
478
|
+
|
479
|
+
it 'includes the path to the kubeconfig' do
|
480
|
+
fake_cli.logtail(namespace, selector)
|
481
|
+
expect(fake_cli).to run_exec.with_args(['--kubeconfig', kubeconfig_path])
|
482
|
+
end
|
483
|
+
|
484
|
+
it 'includes the selector' do
|
485
|
+
fake_cli.logtail(namespace, selector)
|
486
|
+
expect(fake_cli).to run_exec.with_args(['--selector', 'role=web'])
|
487
|
+
end
|
488
|
+
|
489
|
+
it 'follows log output by default' do
|
490
|
+
fake_cli.logtail(namespace, selector)
|
491
|
+
expect(fake_cli).to run_exec.with_args(['-f'])
|
492
|
+
end
|
493
|
+
|
494
|
+
it "doesn't follows log output when asked" do
|
495
|
+
fake_cli.logtail(namespace, selector, follow: false)
|
496
|
+
expect(fake_cli).to run_exec.without_args(['-f'])
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
500
|
+
describe '#current_context' do
|
501
|
+
it 'fetches the current context' do
|
502
|
+
expect(cli.current_context).to eq('kind-kubernetes-cli-tests')
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
506
|
+
describe '#api_resources' do
|
507
|
+
it 'gets the set of available API resources' do
|
508
|
+
api_resources = cli.api_resources
|
509
|
+
pairs = api_resources.split("\n").map { |line| line.split(/[\s]+/)[0...2] }
|
510
|
+
expect(pairs).to include(['namespaces', 'ns'])
|
511
|
+
expect(pairs).to include(['configmaps', 'cm'])
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
515
|
+
describe '#restart_deployment' do
|
516
|
+
it 'restarts the deployment' do
|
517
|
+
cli.apply(deployment)
|
518
|
+
wait_for_deployment(deployment)
|
519
|
+
|
520
|
+
obj_v1 = get_object(deployment)
|
521
|
+
expect(obj_v1.dig(*%w(status observedGeneration))).to eq(1)
|
522
|
+
|
523
|
+
cli.restart_deployment(
|
524
|
+
deployment.metadata.namespace,
|
525
|
+
deployment.metadata.name
|
526
|
+
)
|
527
|
+
|
528
|
+
obj_v2 = get_object(deployment)
|
529
|
+
expect(obj_v2.dig(*%w(status observedGeneration))).to eq(2)
|
530
|
+
ensure
|
531
|
+
safely_delete_res(deployment)
|
532
|
+
end
|
533
|
+
end
|
534
|
+
|
535
|
+
def wait_for_deployment(depl)
|
536
|
+
start = Time.now
|
537
|
+
|
538
|
+
loop do
|
539
|
+
obj = get_object(depl)
|
540
|
+
desired = obj.dig(*%w(status replicas))
|
541
|
+
updated = obj.dig(*%w(status updatedReplicas))
|
542
|
+
available = obj.dig(*%w(status availableReplicas))
|
543
|
+
|
544
|
+
if updated == desired && updated == available
|
545
|
+
break
|
546
|
+
else
|
547
|
+
if (Time.now - start) > 60
|
548
|
+
raise 'timed out waiting for deployment'
|
549
|
+
end
|
550
|
+
|
551
|
+
sleep 1
|
552
|
+
end
|
553
|
+
end
|
554
|
+
|
555
|
+
start = Time.now
|
556
|
+
|
557
|
+
loop do
|
558
|
+
obj = get_object(depl)
|
559
|
+
pods = begin
|
560
|
+
cli.get_objects(
|
561
|
+
'Pod',
|
562
|
+
deployment.metadata.namespace,
|
563
|
+
deployment.spec.selector.match_labels.kv_pairs
|
564
|
+
)
|
565
|
+
rescue KubernetesCLI::GetResourceError
|
566
|
+
[]
|
567
|
+
end
|
568
|
+
|
569
|
+
pod_phases = pods.map { |p| p.dig(*%w(status phase)) }
|
570
|
+
|
571
|
+
if pods.size == obj.dig(*%w(status replicas)) && pod_phases.all?('Running')
|
572
|
+
break
|
573
|
+
else
|
574
|
+
if (Time.now - start) > 60
|
575
|
+
raise 'timed out waiting for pods'
|
576
|
+
end
|
577
|
+
|
578
|
+
sleep 1
|
579
|
+
end
|
580
|
+
end
|
581
|
+
end
|
582
|
+
|
583
|
+
def delete_res(res)
|
584
|
+
kind = res.to_resource.contents[:kind]
|
585
|
+
cli.delete_object(kind, res.metadata.namespace, res.metadata.name)
|
586
|
+
end
|
587
|
+
|
588
|
+
def safely_delete_res(res)
|
589
|
+
delete_res(res)
|
590
|
+
rescue KubernetesCLI::DeleteResourceError
|
591
|
+
end
|
592
|
+
|
593
|
+
def get_object(res)
|
594
|
+
kind = res.to_resource.contents[:kind]
|
595
|
+
cli.get_object(kind, res.metadata.namespace, res.metadata.name)
|
596
|
+
end
|
597
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# typed: ignore
|
2
|
+
|
3
|
+
$:.push(File.expand_path('.', __dir__))
|
4
|
+
|
5
|
+
require 'sorbet-runtime'
|
6
|
+
require 'kubernetes-cli'
|
7
|
+
require 'pry-byebug'
|
8
|
+
require 'kind-rb'
|
9
|
+
require 'kube-dsl'
|
10
|
+
|
11
|
+
require 'support/matchers'
|
12
|
+
require 'support/test_cli'
|
13
|
+
require 'support/test_resource'
|
14
|
+
|
15
|
+
RSpec.configure do |config|
|
16
|
+
config.before(:suite) do
|
17
|
+
system("#{KindRb.executable} create cluster --name kubernetes-cli-tests")
|
18
|
+
system("#{KubectlRb.executable} create namespace test")
|
19
|
+
end
|
20
|
+
|
21
|
+
config.after(:suite) do
|
22
|
+
puts # newline to separate test output from kind output
|
23
|
+
system("#{KindRb.executable} delete cluster --name kubernetes-cli-tests")
|
24
|
+
end
|
25
|
+
end
|