kontena-cli 0.10.3 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
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)