kontena-cli 0.10.3 → 0.11.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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/bin/kontena +2 -0
  4. data/kontena-cli.gemspec +2 -0
  5. data/lib/kontena/cli/apps/build_command.rb +3 -2
  6. data/lib/kontena/cli/apps/deploy_command.rb +10 -1
  7. data/lib/kontena/cli/apps/docker_helper.rb +17 -8
  8. data/lib/kontena/cli/apps/logs_command.rb +1 -1
  9. data/lib/kontena/cli/common.rb +58 -7
  10. data/lib/kontena/cli/external_registries/add_command.rb +6 -8
  11. data/lib/kontena/cli/grid_command.rb +1 -1
  12. data/lib/kontena/cli/grids/common.rb +1 -1
  13. data/lib/kontena/cli/grids/current_command.rb +8 -1
  14. data/lib/kontena/cli/grids/env_command.rb +9 -3
  15. data/lib/kontena/cli/login_command.rb +27 -17
  16. data/lib/kontena/cli/logout_command.rb +1 -2
  17. data/lib/kontena/cli/master/aws/create_command.rb +7 -1
  18. data/lib/kontena/cli/master/azure/create_command.rb +7 -1
  19. data/lib/kontena/cli/master/digital_ocean/create_command.rb +6 -0
  20. data/lib/kontena/cli/master/list_command.rb +18 -0
  21. data/lib/kontena/cli/master/use_command.rb +26 -0
  22. data/lib/kontena/cli/master/vagrant/create_command.rb +7 -1
  23. data/lib/kontena/cli/master_command.rb +4 -0
  24. data/lib/kontena/cli/node_command.rb +1 -1
  25. data/lib/kontena/cli/nodes/list_command.rb +40 -14
  26. data/lib/kontena/cli/services/create_command.rb +2 -0
  27. data/lib/kontena/cli/services/services_helper.rb +31 -0
  28. data/lib/kontena/cli/services/update_command.rb +2 -1
  29. data/lib/kontena/cli/vault/list_command.rb +15 -0
  30. data/lib/kontena/cli/vault/read_command.rb +16 -0
  31. data/lib/kontena/cli/vault/remove_command.rb +13 -0
  32. data/lib/kontena/cli/vault/write_command.rb +23 -0
  33. data/lib/kontena/cli/vault_command.rb +15 -0
  34. data/lib/kontena/cli/whoami_command.rb +6 -3
  35. data/lib/kontena/machine/aws/cloudinit.yml +5 -0
  36. data/lib/kontena/machine/aws/cloudinit_master.yml +3 -0
  37. data/lib/kontena/machine/aws/master_provisioner.rb +3 -1
  38. data/lib/kontena/machine/azure/cloudinit.yml +5 -0
  39. data/lib/kontena/machine/azure/cloudinit_master.yml +3 -0
  40. data/lib/kontena/machine/azure/master_provisioner.rb +3 -1
  41. data/lib/kontena/machine/digital_ocean/cloudinit.yml +5 -0
  42. data/lib/kontena/machine/digital_ocean/cloudinit_master.yml +3 -0
  43. data/lib/kontena/machine/digital_ocean/master_provisioner.rb +4 -2
  44. data/lib/kontena/machine/vagrant/Vagrantfile.master.rb.erb +3 -0
  45. data/lib/kontena/machine/vagrant/cloudinit.yml +5 -0
  46. data/lib/kontena/machine/vagrant/master_provisioner.rb +4 -0
  47. data/lib/kontena/scripts/completer +14 -2
  48. data/spec/kontena/cli/app/deploy_command_spec.rb +37 -4
  49. data/spec/kontena/cli/app/scale_spec.rb +6 -1
  50. data/spec/kontena/cli/common_spec.rb +69 -1
  51. data/spec/kontena/cli/deploy_command_spec.rb +29 -3
  52. data/spec/kontena/cli/login_command_spec.rb +10 -0
  53. data/spec/kontena/cli/master/use_command_spec.rb +29 -0
  54. metadata +13 -4
@@ -13,6 +13,11 @@ write_files:
13
13
  content: |
14
14
  [Service]
15
15
  Environment='DOCKER_OPTS=--insecure-registry="10.81.0.0/19" --bip="172.17.43.1/16"'
16
+ - path: /etc/sysctl.d/99-inotify.conf
17
+ owner: root
18
+ permissions: 0644
19
+ content: |
20
+ fs.inotify.max_user_instances = 8192
16
21
  coreos:
17
22
  units:
18
23
  - name: 00-eth.network
@@ -5,6 +5,8 @@ write_files:
5
5
  owner: root
6
6
  content: |
7
7
  KONTENA_VERSION=<%= version %>
8
+ KONTENA_VAULT_KEY=<%= vault_secret %>
9
+ KONTENA_VAULT_IV=<%= vault_iv %>
8
10
  <% if ssl_cert %>SSL_CERT="/etc/kontena-server.pem"
9
11
 
10
12
  - path: /etc/kontena-server.pem
@@ -79,6 +81,7 @@ coreos:
79
81
  ExecStart=/usr/bin/docker run --name kontena-server-api \
80
82
  --link kontena-server-mongo:mongodb \
81
83
  -e MONGODB_URI=mongodb://mongodb:27017/kontena_server \
84
+ -e VAULT_KEY=${KONTENA_VAULT_KEY} -e VAULT_IV=${KONTENA_VAULT_IV} \
82
85
  <% if auth_server %>-e AUTH_API_URL=<%= auth_server %><% end %> \
83
86
  kontena/server:${KONTENA_VERSION}
84
87
 
@@ -37,7 +37,9 @@ module Kontena
37
37
  userdata_vars = {
38
38
  ssl_cert: ssl_cert,
39
39
  auth_server: opts[:auth_server],
40
- version: opts[:version]
40
+ version: opts[:version],
41
+ vault_secret: opts[:vault_secret],
42
+ vault_iv: opts[:vault_iv]
41
43
  }
42
44
 
43
45
  security_group = ensure_security_group(opts[:vpc])
@@ -12,6 +12,11 @@ write_files:
12
12
  content: |
13
13
  [Service]
14
14
  Environment='DOCKER_OPTS=--insecure-registry="10.81.0.0/19" --bip="172.17.43.1/16"'
15
+ - path: /etc/sysctl.d/99-inotify.conf
16
+ owner: root
17
+ permissions: 0644
18
+ content: |
19
+ fs.inotify.max_user_instances = 8192
15
20
  - path: /etc/resolv.conf
16
21
  permissions: 0644
17
22
  owner: root
@@ -5,6 +5,8 @@ write_files:
5
5
  owner: root
6
6
  content: |
7
7
  KONTENA_VERSION=<%= version %>
8
+ KONTENA_VAULT_KEY=<%= vault_secret %>
9
+ KONTENA_VAULT_IV=<%= vault_iv %>
8
10
  <% if ssl_cert %>SSL_CERT="/etc/kontena-server.pem"
9
11
 
10
12
  - path: /etc/kontena-server.pem
@@ -79,6 +81,7 @@ coreos:
79
81
  ExecStart=/usr/bin/docker run --name kontena-server-api \
80
82
  --link kontena-server-mongo:mongodb \
81
83
  -e MONGODB_URI=mongodb://mongodb:27017/kontena_server \
84
+ -e VAULT_KEY=${KONTENA_VAULT_KEY} -e VAULT_IV=${KONTENA_VAULT_IV} \
82
85
  <% if auth_server %>-e AUTH_API_URL=<%= auth_server %><% end %> \
83
86
  kontena/server:${KONTENA_VERSION}
84
87
 
@@ -44,7 +44,9 @@ module Kontena
44
44
  userdata_vars = {
45
45
  ssl_cert: ssl_cert,
46
46
  auth_server: opts[:auth_server],
47
- version: opts[:version]
47
+ version: opts[:version],
48
+ vault_secret: opts[:vault_secret],
49
+ vault_iv: opts[:vault_iv]
48
50
  }
49
51
 
50
52
  params = {
@@ -12,6 +12,11 @@ write_files:
12
12
  content: |
13
13
  [Service]
14
14
  Environment='DOCKER_OPTS=--insecure-registry="10.81.0.0/19" --bip="172.17.43.1/16"'
15
+ - path: /etc/sysctl.d/99-inotify.conf
16
+ owner: root
17
+ permissions: 0644
18
+ content: |
19
+ fs.inotify.max_user_instances = 8192
15
20
  - path: /etc/resolv.conf
16
21
  permissions: 0644
17
22
  owner: root
@@ -5,6 +5,8 @@ write_files:
5
5
  owner: root
6
6
  content: |
7
7
  KONTENA_VERSION=<%= version %>
8
+ KONTENA_VAULT_KEY=<%= vault_secret %>
9
+ KONTENA_VAULT_IV=<%= vault_iv %>
8
10
  <% if ssl_cert %>SSL_CERT="/etc/kontena-server.pem"
9
11
 
10
12
  - path: /etc/kontena-server.pem
@@ -79,6 +81,7 @@ coreos:
79
81
  ExecStart=/usr/bin/docker run --name kontena-server-api \
80
82
  --link kontena-server-mongo:mongodb \
81
83
  -e MONGODB_URI=mongodb://mongodb:27017/kontena_server \
84
+ -e VAULT_KEY=${KONTENA_VAULT_KEY} -e VAULT_IV=${KONTENA_VAULT_IV} \
82
85
  <% if auth_server %>-e AUTH_API_URL=<%= auth_server %><% end %> \
83
86
  kontena/server:${KONTENA_VERSION}
84
87
 
@@ -30,7 +30,9 @@ module Kontena
30
30
  userdata_vars = {
31
31
  ssl_cert: ssl_cert,
32
32
  auth_server: opts[:auth_server],
33
- version: opts[:version]
33
+ version: opts[:version],
34
+ vault_secret: opts[:vault_secret],
35
+ vault_iv: opts[:vault_iv]
34
36
  }
35
37
 
36
38
  droplet = DropletKit::Droplet.new(
@@ -76,7 +78,7 @@ module Kontena
76
78
  end
77
79
 
78
80
  def ssh_key(public_key)
79
- ssh_key = client.ssh_keys.all.find{|key| key.public_key == public_key}
81
+ client.ssh_keys.all.find{|key| key.public_key == public_key}
80
82
  end
81
83
 
82
84
  def master_running?
@@ -12,6 +12,8 @@ write_files:
12
12
  owner: root
13
13
  content: |
14
14
  KONTENA_VERSION=<%= version %>
15
+ KONTENA_VAULT_KEY=<%= vault_secret %>
16
+ KONTENA_VAULT_IV=<%= vault_iv %>
15
17
  coreos:
16
18
  update:
17
19
  reboot-strategy: off
@@ -65,6 +67,7 @@ coreos:
65
67
  ExecStart=/usr/bin/docker run --name kontena-server-api \
66
68
  --link kontena-server-mongo:mongodb \
67
69
  -e MONGODB_URI=mongodb://mongodb:27017/kontena_server \
70
+ -e VAULT_KEY=${KONTENA_VAULT_KEY} -e VAULT_IV=${KONTENA_VAULT_IV} \
68
71
  <% if auth_server %>-e AUTH_API_URL=<%= auth_server %><% end %> \
69
72
  -p 8080:9292 \
70
73
  kontena/server:${KONTENA_VERSION}
@@ -12,6 +12,11 @@ write_files:
12
12
  content: |
13
13
  [Service]
14
14
  Environment='DOCKER_OPTS=--insecure-registry="10.81.0.0/19" --bip="172.17.43.1/16"'
15
+ - path: /etc/sysctl.d/99-inotify.conf
16
+ owner: root
17
+ permissions: 0644
18
+ content: |
19
+ fs.inotify.max_user_instances = 8192
15
20
  coreos:
16
21
  units:
17
22
  - name: 00-eth.network
@@ -21,6 +21,8 @@ module Kontena
21
21
  version = opts[:version]
22
22
  memory = opts[:memory] || 1024
23
23
  auth_server = opts[:auth_server]
24
+ vault_secret = opts[:vault_secret]
25
+ vault_iv = opts[:vault_iv]
24
26
  vagrant_path = "#{Dir.home}/.kontena/vagrant_master/"
25
27
  if Dir.exist?(vagrant_path)
26
28
  abort("Oops... cannot create Kontena Master! You can run only one Kontena Master with Vagrant".colorize(:red))
@@ -34,6 +36,8 @@ module Kontena
34
36
  version: version,
35
37
  memory: memory,
36
38
  auth_server: auth_server,
39
+ vault_secret: vault_secret,
40
+ vault_iv: vault_iv,
37
41
  cloudinit: "#{vagrant_path}/cloudinit.yml"
38
42
  }
39
43
  vagrant_data = erb(File.read(template), vars)
@@ -63,6 +63,16 @@ class Helper
63
63
  []
64
64
  end
65
65
 
66
+ def master_names
67
+ config_file = File.expand_path('~/.kontena_client.json')
68
+ if(File.exist?(config_file))
69
+ config = JSON.parse(File.read(config_file))
70
+ return config['servers'].map{|s| s['name']}
71
+ end
72
+ rescue
73
+ []
74
+ end
75
+
66
76
  end
67
77
 
68
78
  helper = Helper.new
@@ -94,8 +104,10 @@ if words.size > 0
94
104
  end
95
105
  when 'master'
96
106
  completion.clear
97
- sub_commands = %w(vagrant digitalocean azure aws)
98
- if words[1]
107
+ sub_commands = %w(list use vagrant digitalocean azure aws)
108
+ if words[1] && words[1] == 'use'
109
+ completion.push helper.master_names
110
+ elsif words[1]
99
111
  completion.push(sub_commands) unless sub_commands.include?(words[1])
100
112
  completion.push %w(create)
101
113
  else
@@ -8,7 +8,28 @@ describe Kontena::Cli::Apps::DeployCommand do
8
8
  end
9
9
 
10
10
  let(:settings) do
11
- {'server' => {'url' => 'http://kontena.test', 'token' => token}}
11
+ {'current_server' => 'alias',
12
+ 'servers' => [
13
+ {'name' => 'some_master', 'url' => 'some_master'},
14
+ {'name' => 'alias', 'url' => 'someurl', 'token' => token}
15
+ ]
16
+ }
17
+ end
18
+
19
+ let(:settings_without_api_url) do
20
+ {'current_server' => 'alias',
21
+ 'servers' => [
22
+ {'name' => 'alias', 'token' => token}
23
+ ]
24
+ }
25
+ end
26
+
27
+ let(:settings_without_token) do
28
+ {'current_server' => 'alias',
29
+ 'servers' => [
30
+ {'name' => 'alias', 'url' => 'url'}
31
+ ]
32
+ }
12
33
  end
13
34
 
14
35
  let(:token) do
@@ -87,16 +108,21 @@ yml
87
108
  end
88
109
 
89
110
  describe '#deploy' do
111
+
112
+ before(:each) do
113
+ allow(subject).to receive(:wait_for_deploy_to_finish).and_return(true)
114
+ end
115
+
90
116
  context 'when api_url is nil' do
91
117
  it 'raises error' do
92
- allow(subject).to receive(:settings).and_return({'server' => {}})
118
+ allow(subject).to receive(:settings).and_return(settings_without_api_url)
93
119
  expect{subject.run([])}.to raise_error(ArgumentError)
94
120
  end
95
121
  end
96
122
 
97
123
  context 'when token is nil' do
98
124
  it 'raises error' do
99
- allow(subject).to receive(:settings).and_return({'server' => {'url' => 'http://kontena.test'}})
125
+ allow(subject).to receive(:settings).and_return(settings_without_token)
100
126
  expect{subject.run([])}.to raise_error(ArgumentError)
101
127
  end
102
128
  end
@@ -256,7 +282,14 @@ yml
256
282
  describe '#parse_data' do
257
283
  it 'adds empty hooks hash if not defined' do
258
284
  data = {'image' => 'foo/bar:latest'}
259
- subject.send(:parse_data, data)
285
+ result = subject.send(:parse_data, data)
286
+ expect(result[:hooks]).to eq({})
287
+ end
288
+
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'}])
260
293
  end
261
294
  end
262
295
  end
@@ -8,7 +8,12 @@ describe Kontena::Cli::Apps::ScaleCommand do
8
8
  end
9
9
 
10
10
  let(:settings) do
11
- {'server' => {'url' => 'http://kontena.test', 'token' => token}}
11
+ {'current_server' => 'alias',
12
+ 'servers' => [
13
+ {'name' => 'some_master', 'url' => 'some_master'},
14
+ {'name' => 'alias', 'url' => 'someurl', 'token' => token}
15
+ ]
16
+ }
12
17
  end
13
18
 
14
19
  let(:token) do
@@ -3,6 +3,10 @@ require "kontena/cli/common"
3
3
 
4
4
  describe Kontena::Cli::Common do
5
5
 
6
+ let(:masters) do
7
+
8
+ end
9
+
6
10
  let(:subject) do
7
11
  Class.new do
8
12
  include Kontena::Cli::Common
@@ -10,12 +14,20 @@ describe Kontena::Cli::Common do
10
14
  end
11
15
 
12
16
  before(:each) do
13
- allow(subject).to receive(:settings).and_return({'server' => {}})
17
+ allow(subject).to receive(:settings).and_return({'current_server' => 'default',
18
+ 'servers' => [{}]
19
+ })
14
20
  allow(subject).to receive(:save_settings)
15
21
  end
16
22
 
17
23
  describe '#current_grid' do
18
24
  it 'returns nil by default' do
25
+ allow(subject).to receive(:settings).and_return({'current_server' => 'alias',
26
+ 'servers' => [
27
+ {'name' => 'some_master', 'url' => 'some_master'},
28
+ {'name' => 'alias', 'url' => 'someurl'}
29
+ ]
30
+ })
19
31
  expect(subject.current_grid).to eq(nil)
20
32
  end
21
33
 
@@ -23,6 +35,17 @@ describe Kontena::Cli::Common do
23
35
  expect(ENV).to receive(:[]).with('KONTENA_GRID').and_return('foo')
24
36
  expect(subject.current_grid).to eq('foo')
25
37
  end
38
+
39
+ it 'returns grid from json' do
40
+ allow(subject).to receive(:settings).and_return({'current_server' => 'alias',
41
+ 'servers' => [
42
+ {'name' => 'some_master', 'url' => 'some_master'},
43
+ {'name' => 'alias', 'url' => 'someurl', 'grid' => 'foo_grid'}
44
+ ]
45
+ })
46
+ expect(subject.current_grid).to eq('foo_grid')
47
+ end
48
+
26
49
  end
27
50
 
28
51
  describe '#api_url' do
@@ -50,4 +73,49 @@ describe Kontena::Cli::Common do
50
73
  expect(subject.require_token).to eq('secret_token')
51
74
  end
52
75
  end
76
+
77
+ describe '#current_master' do
78
+ it 'return correct master info' do
79
+ allow(subject).to receive(:settings).and_return({'current_server' => 'alias',
80
+ 'servers' => [
81
+ {'name' => 'some_master', 'url' => 'some_master'},
82
+ {'name' => 'alias', 'url' => 'someurl'}
83
+ ]
84
+ })
85
+
86
+ expect(subject.current_master['url']).to eq('someurl')
87
+ expect(subject.current_master['name']).to eq('alias')
88
+
89
+ end
90
+ end
91
+
92
+ describe '#settings' do
93
+ it 'migrates old settings' do
94
+ RSpec::Mocks.space.proxy_for(subject).reset
95
+
96
+ allow(File).to receive(:exists?).and_return(true)
97
+ allow(File).to receive(:read).and_return('{
98
+ "server": {
99
+ "url": "https://master.domain.com:8443",
100
+ "grid": "my-grid",
101
+ "token": "kontena-token"
102
+ }
103
+ }')
104
+ expected_settings = {
105
+ 'current_server' => 'default',
106
+ 'servers' => [
107
+ {
108
+ "url" => "https://master.domain.com:8443",
109
+ "grid" => "my-grid",
110
+ "token" => "kontena-token",
111
+ "name" => "default"
112
+ }
113
+ ]
114
+ }
115
+ expect(File).to receive(:write).with(subject.settings_filename, JSON.pretty_generate(expected_settings))
116
+
117
+ subject.settings
118
+ end
119
+
120
+ end
53
121
  end
@@ -8,9 +8,31 @@ describe Kontena::Cli::DeployCommand do
8
8
  end
9
9
 
10
10
  let(:settings) do
11
- {'server' => {'url' => 'http://kontena.test', 'token' => token}}
11
+ {'current_server' => 'alias',
12
+ 'servers' => [
13
+ {'name' => 'some_master', 'url' => 'some_master'},
14
+ {'name' => 'alias', 'url' => 'someurl', 'token' => token}
15
+ ]
16
+ }
17
+ end
18
+
19
+ let(:settings_without_api_url) do
20
+ {'current_server' => 'alias',
21
+ 'servers' => [
22
+ {'name' => 'alias', 'token' => token}
23
+ ]
24
+ }
25
+ end
26
+
27
+ let(:settings_without_token) do
28
+ {'current_server' => 'alias',
29
+ 'servers' => [
30
+ {'name' => 'alias', 'url' => 'url'}
31
+ ]
32
+ }
12
33
  end
13
34
 
35
+
14
36
  let(:token) do
15
37
  '1234567'
16
38
  end
@@ -75,14 +97,14 @@ yml
75
97
  describe '#deploy' do
76
98
  context 'when api_url is nil' do
77
99
  it 'raises error' do
78
- allow(subject).to receive(:settings).and_return({'server' => {}})
100
+ allow(subject).to receive(:settings).and_return(settings_without_api_url)
79
101
  expect{subject.run([])}.to raise_error(ArgumentError)
80
102
  end
81
103
  end
82
104
 
83
105
  context 'when token is nil' do
84
106
  it 'raises error' do
85
- allow(subject).to receive(:settings).and_return({'server' => {'url' => 'http://kontena.test'}})
107
+ allow(subject).to receive(:settings).and_return(settings_without_token)
86
108
  expect{subject.run([])}.to raise_error(ArgumentError)
87
109
  end
88
110
  end
@@ -118,6 +140,10 @@ yml
118
140
  end
119
141
 
120
142
  context 'when yml file has multiple env files' do
143
+ before(:each) do
144
+ allow(subject).to receive(:settings).and_return(settings)
145
+ end
146
+
121
147
  it 'merges environment variables correctly' do
122
148
  allow(subject).to receive(:current_dir).and_return("kontena-test")
123
149
  allow(YAML).to receive(:load).and_return(services)