kontena-cli 0.11.5 → 0.11.6

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
  SHA1:
3
- metadata.gz: 5d9098c361090e27d591cbc3aaf746971edd630c
4
- data.tar.gz: e94b8da1edbde7c98655dd8a18ea4cdfc5a8dc07
3
+ metadata.gz: 3615565de0efd69d3810d5e83d3d82c57346b113
4
+ data.tar.gz: 3b1e0c7d0ebab40e3c475e3a17162b1a99d4abd1
5
5
  SHA512:
6
- metadata.gz: f940dcc0927a58225f36484c4a8c19b0039a562c3a52b3463a40f6588236e92cf68afa314b476d01f20a19b081316f2816ab05ad64b9eb531361f723dfa611a5
7
- data.tar.gz: 1934f827f62632aaa7591dc6679fc1f7f76655fbf85283213b00b0d5913e9d57d28e2edaee97712b6b0d9b46f64a65e45f534fea462c53ee42c0cfd9696676c8
6
+ metadata.gz: fd94b5f72eefbc5d03a0def4247bc2d2fe485f88934b2c7b00665df2d19f041e0e692bd881a2afa92dbad5df3aa8e47633f48bde0efeed7a0b5eae74cb583d09
7
+ data.tar.gz: 63ca406ab1b5cfd55a2650eecf8e4ac0064ddd5692ff7aa704b626a93f3d5a98f3ceaf3e6080d2164cc3ead655a822050eed93f6a3cfbb5767c55c3a7d59cc3a
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.11.5
1
+ 0.11.6
@@ -146,15 +146,15 @@ module Kontena::Cli::Apps
146
146
  data[:image] = parse_image(options['image'])
147
147
  data[:env] = options['environment']
148
148
  data[:container_count] = options['instances']
149
- data[:links] = parse_links(options['links']) if options['links']
150
- data[:ports] = parse_ports(options['ports']) if options['ports']
149
+ data[:links] = parse_links(options['links'] || [])
150
+ data[:ports] = parse_ports(options['ports'] || [])
151
151
  data[:memory] = parse_memory(options['mem_limit']) if options['mem_limit']
152
152
  data[:memory_swap] = parse_memory(options['memswap_limit']) if options['memswap_limit']
153
153
  data[:cpu_shares] = options['cpu_shares'] if options['cpu_shares']
154
- data[:volumes] = options['volumes'] if options['volumes']
155
- data[:volumes_from] = options['volumes_from'] if options['volumes_from']
154
+ data[:volumes] = options['volumes'] || []
155
+ data[:volumes_from] = options['volumes_from'] || []
156
156
  data[:cmd] = options['command'].split(" ") if options['command']
157
- data[:affinity] = options['affinity'] if options['affinity']
157
+ data[:affinity] = options['affinity'] || []
158
158
  data[:user] = options['user'] if options['user']
159
159
  data[:stateful] = options['stateful'] == true
160
160
  data[:privileged] = options['privileged'] unless options['privileged'].nil?
@@ -1,7 +1,10 @@
1
1
  module Kontena::Cli::Apps
2
2
  module DockerHelper
3
3
 
4
- def process_docker_images(services, force_build = false, no_cache=false)
4
+ # @param [Hash] services
5
+ # @param [Boolean] force_build
6
+ # @param [Boolean] no_cache
7
+ def process_docker_images(services, force_build = false, no_cache = false)
5
8
  if services.none?{|name, service| service['build']}
6
9
  puts "Not found any service with build option"
7
10
  return
@@ -20,31 +23,44 @@ module Kontena::Cli::Apps
20
23
  end
21
24
  end
22
25
 
26
+ # @param [String] name
27
+ # @return [Boolean]
23
28
  def validate_image_name(name)
24
- !(/^[\w.\/\-]+:?+[\w+.]+$/ =~ name).nil?
29
+ !(/^[\w.\/\-:]+:?+[\w+.]+$/ =~ name).nil?
25
30
  end
26
31
 
27
-
32
+ # @param [String] name
33
+ # @param [String] path
34
+ # @param [String] dockerfile
35
+ # @param [Boolean] no_cache
36
+ # @return [Integer]
28
37
  def build_docker_image(name, path, dockerfile, no_cache=false)
29
38
  cmd = ["docker build -t #{name}"]
30
39
  cmd << "-f #{File.join(File.expand_path(path), dockerfile)}" if dockerfile != "Dockerfile"
31
40
  cmd << "--no-cache" if no_cache
32
- cmd << path
41
+ cmd << path
33
42
  ret = system(cmd.join(' '))
34
43
  abort("Failed to build image #{name.colorize(:cyan)}") unless ret
35
44
  ret
36
45
  end
37
46
 
47
+ # @param [String] image
48
+ # @return [Integer]
38
49
  def push_docker_image(image)
39
50
  ret = system("docker push #{image}")
40
51
  abort("Failed to push image #{image.colorize(:cyan)}") unless ret
41
52
  ret
42
53
  end
43
54
 
55
+ # @param [String] image
56
+ # @return [Boolean]
44
57
  def image_exist?(image)
45
58
  `docker history #{image} 2>&1` ; $?.success?
46
59
  end
47
60
 
61
+ # @param [String] path
62
+ # @param [String] dockerfile
63
+ # @return [Boolean]
48
64
  def dockerfile_exist?(path, dockerfile)
49
65
  file = File.join(File.expand_path(path), dockerfile)
50
66
  File.exist?(file)
@@ -10,7 +10,7 @@ module Kontena::Cli::Services
10
10
  def execute
11
11
  require_api_url
12
12
  token = require_token
13
- restart_service(token, name, {})
13
+ restart_service(token, name)
14
14
  end
15
15
  end
16
16
  end
@@ -153,6 +153,14 @@ module Kontena
153
153
  end
154
154
  end
155
155
 
156
+ unless service['memory'].to_s.empty?
157
+ puts " memory: #{int_to_filesize(service['memory'])}"
158
+ end
159
+
160
+ unless service['memory_swap'].to_s.empty?
161
+ puts " memory_swap: #{int_to_filesize(service['memory_swap'])}"
162
+ end
163
+
156
164
  unless service['pid'].to_s.empty?
157
165
  puts " pid: #{service['pid']}"
158
166
  end
@@ -212,7 +220,7 @@ module Kontena
212
220
  # @param [String] token
213
221
  # @param [String] service_id
214
222
  def restart_service(token, service_id)
215
- param = parse_service_id(service_id)
223
+ param = parse_service_id(service_id)
216
224
  client(token).post("services/#{param}/restart", {})
217
225
  end
218
226
 
@@ -310,6 +318,16 @@ module Kontena
310
318
  end
311
319
  secrets
312
320
  end
321
+
322
+ def int_to_filesize(int)
323
+ {
324
+ 'B' => 1000,
325
+ 'KB' => 1000 * 1000,
326
+ 'MB' => 1000 * 1000 * 1000,
327
+ 'GB' => 1000 * 1000 * 1000 * 1000,
328
+ 'TB' => 1000 * 1000 * 1000 * 1000 * 1000
329
+ }.each_pair { |e, s| return "#{(int.to_i / (s / 1000))}#{e}" if int < s }
330
+ end
313
331
  end
314
332
  end
315
333
  end
@@ -107,7 +107,7 @@ yml
107
107
  ["TEST_ENV_VAR=test2","", "TEST_ENV_VAR2=test3"]
108
108
  end
109
109
 
110
- describe '#deploy' do
110
+ describe '.run' do
111
111
 
112
112
  before(:each) do
113
113
  allow(subject).to receive(:wait_for_deploy_to_finish).and_return(true)
@@ -280,16 +280,348 @@ yml
280
280
  end
281
281
 
282
282
  describe '#parse_data' do
283
- it 'adds empty hooks hash if not defined' do
284
- data = {'image' => 'foo/bar:latest'}
285
- result = subject.send(:parse_data, data)
286
- expect(result[:hooks]).to eq({})
283
+
284
+ context 'volumes' do
285
+ it 'returns volumes if set' do
286
+ data = {
287
+ 'image' => 'foo/bar:latest',
288
+ 'volumes' => [
289
+ 'mongodb-1'
290
+ ]
291
+ }
292
+ result = subject.send(:parse_data, data)
293
+ expect(result[:volumes]).to eq(data['volumes'])
294
+ end
295
+
296
+ it 'returns empty volumes if not set' do
297
+ data = {
298
+ 'image' => 'foo/bar:latest'
299
+ }
300
+ result = subject.send(:parse_data, data)
301
+ expect(result[:volumes]).to eq([])
302
+ end
303
+ end
304
+
305
+ context 'volumes_from' do
306
+ it 'returns volumes_from if set' do
307
+ data = {
308
+ 'image' => 'foo/bar:latest',
309
+ 'volumes_from' => [
310
+ 'mongodb-1'
311
+ ]
312
+ }
313
+ result = subject.send(:parse_data, data)
314
+ expect(result[:volumes_from]).to eq(data['volumes_from'])
315
+ end
316
+
317
+ it 'returns empty volumes_from if not set' do
318
+ data = {
319
+ 'image' => 'foo/bar:latest'
320
+ }
321
+ result = subject.send(:parse_data, data)
322
+ expect(result[:volumes_from]).to eq([])
323
+ end
324
+ end
325
+
326
+ context 'command' do
327
+ it 'returns cmd array if set' do
328
+ data = {
329
+ 'image' => 'foo/bar:latest',
330
+ 'command' => 'ls -la'
331
+ }
332
+ result = subject.send(:parse_data, data)
333
+ expect(result[:cmd]).to eq(data['command'].split(' '))
334
+ end
335
+
336
+ it 'does not return cmd if not set' do
337
+ data = {
338
+ 'image' => 'foo/bar:latest'
339
+ }
340
+ result = subject.send(:parse_data, data)
341
+ expect(result.has_key?(:cmd)).to be_falsey
342
+ end
343
+ end
344
+
345
+ context 'affinity' do
346
+ it 'returns affinity if set' do
347
+ data = {
348
+ 'image' => 'foo/bar:latest',
349
+ 'affinity' => [
350
+ 'label==az=b'
351
+ ]
352
+ }
353
+ result = subject.send(:parse_data, data)
354
+ expect(result[:affinity]).to eq(data['affinity'])
355
+ end
356
+
357
+ it 'returns affinity as empty array if not set' do
358
+ data = {
359
+ 'image' => 'foo/bar:latest'
360
+ }
361
+ result = subject.send(:parse_data, data)
362
+ expect(result.has_key?(:affinity)).to be_truthy
363
+ expect(result[:affinity]).to eq([])
364
+ end
365
+ end
366
+
367
+ context 'user' do
368
+ it 'returns user if set' do
369
+ data = {
370
+ 'image' => 'foo/bar:latest',
371
+ 'user' => 'user'
372
+ }
373
+ result = subject.send(:parse_data, data)
374
+ expect(result[:user]).to eq('user')
375
+ end
376
+
377
+ it 'does not return user if not set' do
378
+ data = {
379
+ 'image' => 'foo/bar:latest'
380
+ }
381
+ result = subject.send(:parse_data, data)
382
+ expect(result.has_key?(:user)).to be_falsey
383
+ end
384
+ end
385
+
386
+ context 'stateful' do
387
+ it 'returns stateful if set' do
388
+ data = {
389
+ 'image' => 'foo/bar:latest',
390
+ 'stateful' => true
391
+ }
392
+ result = subject.send(:parse_data, data)
393
+ expect(result[:stateful]).to eq(true)
394
+ end
395
+
396
+ it 'returns stateful as false if not set' do
397
+ data = {
398
+ 'image' => 'foo/bar:latest'
399
+ }
400
+ result = subject.send(:parse_data, data)
401
+ expect(result[:stateful]).to eq(false)
402
+ end
403
+ end
404
+
405
+ context 'privileged' do
406
+ it 'returns privileged if set' do
407
+ data = {
408
+ 'image' => 'foo/bar:latest',
409
+ 'privileged' => false
410
+ }
411
+ result = subject.send(:parse_data, data)
412
+ expect(result[:privileged]).to eq(false)
413
+ end
414
+
415
+ it 'does not return privileged if not set' do
416
+ data = {
417
+ 'image' => 'foo/bar:latest'
418
+ }
419
+ result = subject.send(:parse_data, data)
420
+ expect(result[:privileged]).to be_nil
421
+ end
422
+ end
423
+
424
+ context 'cap_add' do
425
+ it 'returns cap_drop if set' do
426
+ data = {
427
+ 'image' => 'foo/bar:latest',
428
+ 'cap_add' => [
429
+ 'NET_ADMIN'
430
+ ]
431
+ }
432
+ result = subject.send(:parse_data, data)
433
+ expect(result[:cap_add]).to eq(data['cap_add'])
434
+ end
435
+
436
+ it 'does not return cap_add if not set' do
437
+ data = {
438
+ 'image' => 'foo/bar:latest'
439
+ }
440
+ result = subject.send(:parse_data, data)
441
+ expect(result[:cap_add]).to be_nil
442
+ end
443
+ end
444
+
445
+ context 'cap_drop' do
446
+ it 'returns cap_drop if set' do
447
+ data = {
448
+ 'image' => 'foo/bar:latest',
449
+ 'cap_drop' => [
450
+ 'NET_ADMIN'
451
+ ]
452
+ }
453
+ result = subject.send(:parse_data, data)
454
+ expect(result[:cap_drop]).to eq(data['cap_drop'])
455
+ end
456
+
457
+ it 'does not return cap_drop if not set' do
458
+ data = {
459
+ 'image' => 'foo/bar:latest'
460
+ }
461
+ result = subject.send(:parse_data, data)
462
+ expect(result[:cap_drop]).to be_nil
463
+ end
464
+ end
465
+
466
+ context 'net' do
467
+ it 'returns net if set' do
468
+ data = {
469
+ 'image' => 'foo/bar:latest',
470
+ 'net' => 'host'
471
+ }
472
+ result = subject.send(:parse_data, data)
473
+ expect(result[:net]).to eq('host')
474
+ end
475
+
476
+ it 'does not return pid if not set' do
477
+ data = {
478
+ 'image' => 'foo/bar:latest'
479
+ }
480
+ result = subject.send(:parse_data, data)
481
+ expect(result[:net]).to be_nil
482
+ end
483
+ end
484
+
485
+ context 'pid' do
486
+ it 'returns pid if set' do
487
+ data = {
488
+ 'image' => 'foo/bar:latest',
489
+ 'pid' => 'host'
490
+ }
491
+ result = subject.send(:parse_data, data)
492
+ expect(result[:pid]).to eq('host')
493
+ end
494
+
495
+ it 'does not return pid if not set' do
496
+ data = {
497
+ 'image' => 'foo/bar:latest'
498
+ }
499
+ result = subject.send(:parse_data, data)
500
+ expect(result[:pid]).to be_nil
501
+ end
287
502
  end
288
503
 
289
- it 'read secrets if defined' do
290
- data = {'image' => 'foo/bar:latest', 'secrets' => [{'secret' => 'MYSQL_ADMIN_PASSWORD', 'name' => 'WORDPRESS_DB_PASSWORD', 'type' => 'env'}]}
291
- result = subject.send(:parse_data, data)
292
- expect(result[:secrets]).to eq([{'secret' => 'MYSQL_ADMIN_PASSWORD', 'name' => 'WORDPRESS_DB_PASSWORD', 'type' => 'env'}])
504
+ context 'log_driver' do
505
+ it 'returns log_driver if set' do
506
+ data = {
507
+ 'image' => 'foo/bar:latest',
508
+ 'log_driver' => 'syslog'
509
+ }
510
+ result = subject.send(:parse_data, data)
511
+ expect(result[:log_driver]).to eq('syslog')
512
+ end
513
+
514
+ it 'does not return log_driver if not set' do
515
+ data = {
516
+ 'image' => 'foo/bar:latest'
517
+ }
518
+ result = subject.send(:parse_data, data)
519
+ expect(result[:log_driver]).to be_nil
520
+ end
521
+ end
522
+
523
+ context 'log_opt' do
524
+ it 'returns log_opts hash if log_opt is set' do
525
+ data = {
526
+ 'image' => 'foo/bar:latest',
527
+ 'log_driver' => 'fluentd',
528
+ 'log_opt' => {
529
+ 'fluentd-address' => '192.168.99.1:24224',
530
+ 'fluentd-tag' => 'docker.{{.Name}}'
531
+ }
532
+ }
533
+ result = subject.send(:parse_data, data)
534
+ expect(result[:log_opts]).to eq(data['log_opt'])
535
+ end
536
+
537
+ it 'does not return log_opts if log_opt is not set' do
538
+ data = {
539
+ 'image' => 'foo/bar:latest'
540
+ }
541
+ result = subject.send(:parse_data, data)
542
+ expect(result[:log_opts]).to be_nil
543
+ end
544
+ end
545
+
546
+ context 'deploy_opts' do
547
+ it 'returns deploy_opts if deploy.wait_for_port is defined' do
548
+ data = {
549
+ 'image' => 'foo/bar:latest',
550
+ 'deploy' => {
551
+ 'wait_for_port' => '8080'
552
+ }
553
+ }
554
+ result = subject.send(:parse_data, data)
555
+ expect(result[:deploy_opts][:wait_for_port]).to eq('8080')
556
+ end
557
+
558
+ it 'returns deploy_opts if deploy.min_health is defined' do
559
+ data = {
560
+ 'image' => 'foo/bar:latest',
561
+ 'deploy' => {
562
+ 'min_health' => '0.5'
563
+ }
564
+ }
565
+ result = subject.send(:parse_data, data)
566
+ expect(result[:deploy_opts][:min_health]).to eq('0.5')
567
+ end
568
+
569
+ it 'sets strategy if deploy.strategy is defined' do
570
+ data = {
571
+ 'image' => 'foo/bar:latest',
572
+ 'deploy' => {
573
+ 'strategy' => 'daemon'
574
+ }
575
+ }
576
+ result = subject.send(:parse_data, data)
577
+ expect(result[:strategy]).to eq('daemon')
578
+ end
579
+
580
+ it 'does not return deploy_opts if no deploy options are defined' do
581
+ data = {
582
+ 'image' => 'foo/bar:latest'
583
+ }
584
+ result = subject.send(:parse_data, data)
585
+ expect(result[:deploy_opts]).to be_nil
586
+ end
587
+ end
588
+
589
+ context 'hooks' do
590
+ it 'returns hooks hash if defined' do
591
+ data = {
592
+ 'image' => 'foo/bar:latest',
593
+ 'hooks' => {
594
+ 'post_start' => []
595
+ }
596
+ }
597
+ result = subject.send(:parse_data, data)
598
+ expect(result[:hooks]).to eq(data['hooks'])
599
+ end
600
+
601
+ it 'does returns empty hook hash if not defined' do
602
+ data = {'image' => 'foo/bar:latest'}
603
+ result = subject.send(:parse_data, data)
604
+ expect(result[:hooks]).to eq({})
605
+ end
606
+ end
607
+
608
+ context 'secrets' do
609
+ it 'returns secrets array if defined' do
610
+ data = {
611
+ 'image' => 'foo/bar:latest',
612
+ 'secrets' => [
613
+ {'secret' => 'MYSQL_ADMIN_PASSWORD', 'name' => 'WORDPRESS_DB_PASSWORD', 'type' => 'env'}
614
+ ]
615
+ }
616
+ result = subject.send(:parse_data, data)
617
+ expect(result[:secrets]).to eq(data['secrets'])
618
+ end
619
+
620
+ it 'does not return secrets if not defined' do
621
+ data = {'image' => 'foo/bar:latest'}
622
+ result = subject.send(:parse_data, data)
623
+ expect(result[:secrets]).to be_nil
624
+ end
293
625
  end
294
626
  end
295
627
  end
@@ -12,6 +12,7 @@ describe Kontena::Cli::Apps::DockerHelper do
12
12
  it 'returns true' do
13
13
  expect(subject.validate_image_name('registry.kontena.local/image-name:latest')).to be_truthy
14
14
  expect(subject.validate_image_name('my-registry.com/organization/image_name:latest')).to be_truthy
15
+ expect(subject.validate_image_name('my-registry.com:5000/organization/image_name:latest')).to be_truthy
15
16
  expect(subject.validate_image_name('mysql:5.1')).to be_truthy
16
17
  expect(subject.validate_image_name('wordpress')).to be_truthy
17
18
  end
@@ -26,7 +27,6 @@ describe Kontena::Cli::Apps::DockerHelper do
26
27
  expect(subject.validate_image_name('mysql 5.1')).to be_falsey
27
28
  expect(subject.validate_image_name('*.mydomain.com/mysql')).to be_falsey
28
29
  end
29
-
30
30
  end
31
31
  end
32
32
  end
@@ -0,0 +1,51 @@
1
+ require_relative "../../../spec_helper"
2
+ require "kontena/cli/services/restart_command"
3
+
4
+ describe Kontena::Cli::Services::RestartCommand do
5
+
6
+ let(:subject) do
7
+ described_class.new(File.basename($0))
8
+ end
9
+
10
+ let(:client) do
11
+ double
12
+ end
13
+
14
+ let(:token) do
15
+ '1234567'
16
+ end
17
+
18
+ let(:settings) do
19
+ {'current_server' => 'alias',
20
+ 'servers' => [
21
+ {'name' => 'some_master', 'url' => 'some_master'},
22
+ {'name' => 'alias', 'url' => 'someurl', 'token' => token}
23
+ ]
24
+ }
25
+ end
26
+
27
+ describe '#execute' do
28
+
29
+ before(:each) do
30
+ allow(subject).to receive(:client).with(token).and_return(client)
31
+ allow(subject).to receive(:current_grid).and_return('test-grid')
32
+ allow(subject).to receive(:settings).and_return(settings)
33
+ allow(subject).to receive(:restart_service).and_return({})
34
+ end
35
+
36
+ it 'requires api url' do
37
+ expect(subject).to receive(:require_api_url).once
38
+ subject.run(['service'])
39
+ end
40
+
41
+ it 'requires token' do
42
+ expect(subject).to receive(:require_token).once
43
+ subject.run(['service'])
44
+ end
45
+
46
+ it 'triggers restart command' do
47
+ expect(subject).to receive(:restart_service).with(token, 'service')
48
+ subject.run(['service'])
49
+ end
50
+ end
51
+ end
@@ -41,6 +41,27 @@ module Kontena::Cli::Services
41
41
  end
42
42
  end
43
43
 
44
+ describe '#stop_service' do
45
+ it 'creates POST services/:id/stop request to Kontena Server' do
46
+ expect(client).to receive(:post).with('services/test-grid/test-service/stop', {})
47
+ subject.stop_service(token, 'test-service')
48
+ end
49
+ end
50
+
51
+ describe '#start_service' do
52
+ it 'creates POST services/:id/start request to Kontena Server' do
53
+ expect(client).to receive(:post).with('services/test-grid/test-service/start', {})
54
+ subject.start_service(token, 'test-service')
55
+ end
56
+ end
57
+
58
+ describe '#restart_service' do
59
+ it 'creates POST services/:id/restart request to Kontena Server' do
60
+ expect(client).to receive(:post).with('services/test-grid/test-service/restart', {})
61
+ subject.restart_service(token, 'test-service')
62
+ end
63
+ end
64
+
44
65
  describe '#deploy_service' do
45
66
  it 'creates POST services/:id/deploy request to Kontena Server' do
46
67
  allow(client).to receive(:get).with('services/test-grid/1').and_return({'state' => 'running'})
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kontena-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.5
4
+ version: 0.11.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kontena, Inc
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-08 00:00:00.000000000 Z
11
+ date: 2016-02-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -301,6 +301,7 @@ files:
301
301
  - spec/kontena/cli/login_command_spec.rb
302
302
  - spec/kontena/cli/master/use_command_spec.rb
303
303
  - spec/kontena/cli/register_command_spec.rb
304
+ - spec/kontena/cli/services/restart_command_spec.rb
304
305
  - spec/kontena/cli/services/services_helper_spec.rb
305
306
  - spec/spec_helper.rb
306
307
  - tasks/rspec.rake
@@ -324,7 +325,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
324
325
  version: '0'
325
326
  requirements: []
326
327
  rubyforge_project:
327
- rubygems_version: 2.4.8
328
+ rubygems_version: 2.4.5.1
328
329
  signing_key:
329
330
  specification_version: 4
330
331
  summary: Kontena command line tool
@@ -338,5 +339,6 @@ test_files:
338
339
  - spec/kontena/cli/login_command_spec.rb
339
340
  - spec/kontena/cli/master/use_command_spec.rb
340
341
  - spec/kontena/cli/register_command_spec.rb
342
+ - spec/kontena/cli/services/restart_command_spec.rb
341
343
  - spec/kontena/cli/services/services_helper_spec.rb
342
344
  - spec/spec_helper.rb