kontena-cli 1.4.3 → 1.5.0.pre1

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 (119) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +7 -3
  3. data/Gemfile +7 -3
  4. data/README.md +1 -1
  5. data/VERSION +1 -1
  6. data/bin/kontena +1 -0
  7. data/kontena-cli.gemspec +5 -6
  8. data/lib/kontena/cli/browser_launcher.rb +61 -0
  9. data/lib/kontena/cli/certificate/authorize_command.rb +40 -16
  10. data/lib/kontena/cli/certificate/get_command.rb +1 -1
  11. data/lib/kontena/cli/cloud/login_command.rb +3 -4
  12. data/lib/kontena/cli/cloud/master/add_command.rb +1 -1
  13. data/lib/kontena/cli/cloud/master/list_command.rb +1 -1
  14. data/lib/kontena/cli/cloud/master/remove_command.rb +1 -1
  15. data/lib/kontena/cli/cloud/master/update_command.rb +1 -1
  16. data/lib/kontena/cli/common.rb +2 -2
  17. data/lib/kontena/cli/etcd_command.rb +1 -1
  18. data/lib/kontena/cli/external_registries/add_command.rb +2 -2
  19. data/lib/kontena/cli/external_registries/remove_command.rb +1 -1
  20. data/lib/kontena/cli/grids/common.rb +14 -4
  21. data/lib/kontena/cli/grids/events_command.rb +2 -2
  22. data/lib/kontena/cli/grids/list_command.rb +1 -1
  23. data/lib/kontena/cli/grids/logs_command.rb +1 -1
  24. data/lib/kontena/cli/grids/remove_command.rb +12 -10
  25. data/lib/kontena/cli/grids/trusted_subnets/add_command.rb +1 -1
  26. data/lib/kontena/cli/grids/trusted_subnets/remove_command.rb +12 -10
  27. data/lib/kontena/cli/grids/use_command.rb +1 -1
  28. data/lib/kontena/cli/helpers/log_helper.rb +1 -1
  29. data/lib/kontena/cli/logout_command.rb +1 -1
  30. data/lib/kontena/cli/master/login_command.rb +2 -3
  31. data/lib/kontena/cli/master/logout_command.rb +2 -2
  32. data/lib/kontena/cli/master/token/common.rb +2 -1
  33. data/lib/kontena/cli/master/token/create_command.rb +5 -2
  34. data/lib/kontena/cli/master/token/current_command.rb +9 -4
  35. data/lib/kontena/cli/master/token/list_command.rb +1 -1
  36. data/lib/kontena/cli/master/token/show_command.rb +11 -1
  37. data/lib/kontena/cli/master/user/invite_command.rb +1 -1
  38. data/lib/kontena/cli/master_command.rb +0 -1
  39. data/lib/kontena/cli/nodes/create_command.rb +1 -1
  40. data/lib/kontena/cli/nodes/labels/remove_command.rb +17 -3
  41. data/lib/kontena/cli/nodes/remove_command.rb +12 -10
  42. data/lib/kontena/cli/nodes/reset_token_command.rb +1 -1
  43. data/lib/kontena/cli/nodes/update_command.rb +1 -1
  44. data/lib/kontena/cli/plugin_command.rb +2 -1
  45. data/lib/kontena/cli/plugins/install_command.rb +2 -2
  46. data/lib/kontena/cli/plugins/uninstall_command.rb +19 -10
  47. data/lib/kontena/cli/plugins/upgrade_command.rb +60 -0
  48. data/lib/kontena/cli/registry/create_command.rb +1 -1
  49. data/lib/kontena/cli/registry/remove_command.rb +2 -2
  50. data/lib/kontena/cli/services/containers_command.rb +1 -1
  51. data/lib/kontena/cli/services/create_command.rb +1 -1
  52. data/lib/kontena/cli/services/deploy_command.rb +1 -1
  53. data/lib/kontena/cli/services/envs/add_command.rb +1 -1
  54. data/lib/kontena/cli/services/envs/remove_command.rb +5 -3
  55. data/lib/kontena/cli/services/link_command.rb +1 -1
  56. data/lib/kontena/cli/services/logs_command.rb +1 -1
  57. data/lib/kontena/cli/services/monitor_command.rb +1 -1
  58. data/lib/kontena/cli/services/remove_command.rb +11 -9
  59. data/lib/kontena/cli/services/restart_command.rb +1 -1
  60. data/lib/kontena/cli/services/secrets/link_command.rb +1 -1
  61. data/lib/kontena/cli/services/services_helper.rb +6 -12
  62. data/lib/kontena/cli/services/start_command.rb +5 -3
  63. data/lib/kontena/cli/services/stop_command.rb +5 -3
  64. data/lib/kontena/cli/services/unlink_command.rb +1 -1
  65. data/lib/kontena/cli/services/update_command.rb +1 -1
  66. data/lib/kontena/cli/spinner.rb +10 -10
  67. data/lib/kontena/cli/stack_command.rb +1 -0
  68. data/lib/kontena/cli/stacks/build_command.rb +6 -6
  69. data/lib/kontena/cli/stacks/deploy_command.rb +12 -10
  70. data/lib/kontena/cli/stacks/inspect_command.rb +17 -0
  71. data/lib/kontena/cli/stacks/install_command.rb +15 -4
  72. data/lib/kontena/cli/stacks/list_command.rb +2 -3
  73. data/lib/kontena/cli/stacks/logs_command.rb +1 -1
  74. data/lib/kontena/cli/stacks/monitor_command.rb +2 -2
  75. data/lib/kontena/cli/stacks/remove_command.rb +28 -19
  76. data/lib/kontena/cli/stacks/restart_command.rb +5 -4
  77. data/lib/kontena/cli/stacks/stop_command.rb +6 -5
  78. data/lib/kontena/cli/stacks/upgrade_command.rb +84 -64
  79. data/lib/kontena/cli/stacks/yaml/reader.rb +9 -4
  80. data/lib/kontena/cli/vault/remove_command.rb +7 -5
  81. data/lib/kontena/cli/vault/update_command.rb +1 -1
  82. data/lib/kontena/cli/vault/write_command.rb +1 -1
  83. data/lib/kontena/cli/volumes/remove_command.rb +6 -4
  84. data/lib/kontena/cli/vpn/create_command.rb +1 -1
  85. data/lib/kontena/cli/vpn/remove_command.rb +1 -1
  86. data/lib/kontena/client.rb +23 -14
  87. data/lib/kontena/command.rb +2 -2
  88. data/lib/kontena/debug_instrumentor.rb +11 -2
  89. data/lib/kontena/plugin_manager/common.rb +5 -2
  90. data/lib/kontena/plugin_manager/installer.rb +34 -10
  91. data/lib/kontena/scripts/completer.rb +91 -43
  92. data/lib/kontena/{cli/stacks → stacks}/change_resolver.rb +38 -16
  93. data/lib/kontena/stacks/stack_data.rb +58 -0
  94. data/lib/kontena/stacks/stack_data_set.rb +51 -0
  95. data/lib/kontena_cli.rb +1 -0
  96. data/omnibus/Gemfile.lock +32 -22
  97. data/omnibus/config/projects/kontena.rb +2 -0
  98. data/omnibus/config/software/kontena-cli.rb +6 -4
  99. data/omnibus/package-scripts/kontena/postinstall +1 -1
  100. data/omnibus/wrappers/sh/kontena +1 -1
  101. data/spec/fixtures/kontena_v3_with_registry_extends.yml +20 -0
  102. data/spec/kontena/cli/certificates/authorize_command_spec.rb +81 -0
  103. data/spec/kontena/cli/cloud/login_command_spec.rb +4 -4
  104. data/spec/kontena/cli/common_spec.rb +8 -1
  105. data/spec/kontena/cli/grids/update_command_spec.rb +13 -0
  106. data/spec/kontena/cli/master/join_command_spec.rb +1 -4
  107. data/spec/kontena/cli/master/login_command_spec.rb +4 -4
  108. data/spec/kontena/cli/master/token/create_command_spec.rb +132 -0
  109. data/spec/kontena/cli/master/token/show_command_spec.rb +90 -0
  110. data/spec/kontena/cli/nodes/labels/remove_command_spec.rb +35 -5
  111. data/spec/kontena/cli/stacks/install_command_spec.rb +16 -6
  112. data/spec/kontena/cli/stacks/remove_command_spec.rb +23 -2
  113. data/spec/kontena/cli/stacks/validate_command_spec.rb +1 -1
  114. data/spec/kontena/cli/stacks/yaml/reader_spec.rb +33 -1
  115. data/spec/kontena/client_spec.rb +38 -1
  116. data/spec/kontena/stacks/change_resolver_spec.rb +44 -0
  117. data/spec/kontena/stacks/stack_data_set_spec.rb +59 -0
  118. metadata +36 -34
  119. data/lib/kontena/cli/master/users_command.rb +0 -13
@@ -1,6 +1,6 @@
1
1
  require 'kontena/cli/cloud/login_command'
2
2
  require 'kontena/cli/localhost_web_server'
3
- require 'launchy'
3
+ require 'kontena/cli/browser_launcher'
4
4
 
5
5
  describe Kontena::Cli::Cloud::LoginCommand do
6
6
 
@@ -145,7 +145,7 @@ describe Kontena::Cli::Cloud::LoginCommand do
145
145
  expect(webserver).to receive(:serve_one).and_return({
146
146
  'access_token' => 'abcd'
147
147
  })
148
- expect(Launchy).to receive(:open).and_return(true)
148
+ expect(Kontena::Cli::BrowserLauncher).to receive(:open).and_return(true)
149
149
  expect(subject).to receive(:finish).and_return(true)
150
150
  subject.run([])
151
151
  expect(account.token.access_token).to eq 'abcd'
@@ -159,7 +159,7 @@ describe Kontena::Cli::Cloud::LoginCommand do
159
159
  expect(webserver).to receive(:serve_one).and_return({
160
160
  'code' => 'abcd'
161
161
  })
162
- expect(Launchy).to receive(:open).and_return(true)
162
+ expect(Kontena::Cli::BrowserLauncher).to receive(:open).and_return(true)
163
163
  expect(client).to receive(:exchange_code).with('abcd').and_return({
164
164
  'access_token' => 'abcdefg'
165
165
  })
@@ -176,7 +176,7 @@ describe Kontena::Cli::Cloud::LoginCommand do
176
176
  expect(webserver).to receive(:serve_one).and_return({
177
177
  'error' => 'foo'
178
178
  })
179
- expect(Launchy).to receive(:open).and_return(true)
179
+ expect(Kontena::Cli::BrowserLauncher).to receive(:open).and_return(true)
180
180
  expect{subject.run([])}.to exit_with_error.and output(/Authentication failed: foo/).to_stderr
181
181
  end
182
182
  end
@@ -137,8 +137,15 @@ describe Kontena::Cli::Common do
137
137
  it 'returns true if input matches' do
138
138
  allow(subject).to receive(:ask).and_return('name-to-confirm')
139
139
 
140
- expect(subject.confirm_command('name-to-confirm')).to be_truthy
141
140
  expect{subject.confirm_command('name-to-confirm')}.to_not raise_error
141
+ expect(subject.confirm_command('name-to-confirm')).to be_truthy
142
+ end
143
+
144
+ it 'returns true if input matches and param is not a string' do
145
+ allow(subject).to receive(:ask).and_return('123')
146
+
147
+ expect{subject.confirm_command(123)}.to_not raise_error
148
+ expect(subject.confirm_command(123)).to be_truthy
142
149
  end
143
150
 
144
151
  it 'raises error unless input matches' do
@@ -51,6 +51,19 @@ describe Kontena::Cli::Grids::UpdateCommand do
51
51
  subject.run(['--no-statsd-server', 'test'])
52
52
  end
53
53
 
54
+ it 'should send "none" as log forwarder when --no-log-forwarder given' do
55
+ expect(client).to receive(:put).with(
56
+ 'grids/test', hash_including(
57
+ logs: hash_including(forwarder: 'none')
58
+ )
59
+ )
60
+ subject.run(['--no-log-forwarder', 'test'])
61
+ end
62
+
63
+ it 'should exit with error if --log-forwarder and --no-log-forwarder given' do
64
+ expect{subject.run(['--log-forwarder', 'fluentd', '--no-log-forwarder', 'test'])}.to exit_with_error.and output(/together/).to_stderr
65
+ end
66
+
54
67
  it 'should send empty default_affinity when --no-default-affinity given' do
55
68
  expect(client).to receive(:put).with(
56
69
  'grids/test', hash_including({
@@ -1,7 +1,4 @@
1
1
  require 'kontena/cli/master/join_command'
2
- require 'kontena/cli/localhost_web_server'
3
- require 'launchy'
4
- require 'ostruct'
5
2
 
6
3
  describe Kontena::Cli::Master::JoinCommand do
7
4
 
@@ -30,4 +27,4 @@ describe Kontena::Cli::Master::JoinCommand do
30
27
  expect(Kontena).to receive(:run!).with(%w(master login --join xyz --verbose someurl))
31
28
  subject.run(%w(--verbose someurl xyz))
32
29
  end
33
- end
30
+ end
@@ -1,6 +1,6 @@
1
1
  require 'kontena/cli/master/login_command'
2
2
  require 'kontena/cli/localhost_web_server'
3
- require 'launchy'
3
+ require 'kontena/cli/browser_launcher'
4
4
  require 'ostruct'
5
5
 
6
6
  describe Kontena::Cli::Master::LoginCommand do
@@ -147,7 +147,7 @@ describe Kontena::Cli::Master::LoginCommand do
147
147
  allow(File).to receive(:exist?).and_return(true)
148
148
  allow(File).to receive(:readable?).and_return(true)
149
149
  allow(Kontena::Client).to receive(:new).and_return(client)
150
- allow(Launchy).to receive(:open).and_return(true)
150
+ allow(Kontena::Cli::BrowserLauncher).to receive(:open).and_return(true)
151
151
  allow(Kontena::LocalhostWebServer).to receive(:port).and_return(12345)
152
152
  allow(Kontena::LocalhostWebServer).to receive(:serve_one).and_return(
153
153
  { 'code' => 'abcd1234' }
@@ -254,7 +254,7 @@ describe Kontena::Cli::Master::LoginCommand do
254
254
  expect(opts[:path]).to eq "/authenticate?redirect_uri=http%3A%2F%2Flocalhost%3A12345%2Fcb&expires_in=7200"
255
255
  expect(opts[:http_method]).to eq :get
256
256
  end.and_return({})
257
- expect(Launchy).to receive(:open).with('http://authprovider.example.com/authplz').and_return(true)
257
+ expect(Kontena::Cli::BrowserLauncher).to receive(:open).with('http://authprovider.example.com/authplz').and_return(true)
258
258
  expect(client).to receive(:exchange_code).with('abcd1234').and_return('access_token' => 'defg456', 'server' => { 'name' => 'foobar' }, 'user' => { 'name' => 'testuser' })
259
259
  subject.run(%w(--no-remote --skip-grid-auto-select http://foobar.example.com))
260
260
  expect(subject.config.servers.size).to eq 1
@@ -328,7 +328,7 @@ describe Kontena::Cli::Master::LoginCommand do
328
328
  it 'changes current master to created master' do
329
329
  allow(client).to receive(:last_response).at_least(:once).and_return(OpenStruct.new(status: 302, headers: { 'Location' => 'http://authprovider.example.com/authplz' }))
330
330
  allow(client).to receive(:request).and_return({})
331
- allow(Launchy).to receive(:open).with('http://authprovider.example.com/authplz').and_return(true)
331
+ allow(Kontena::Cli::BrowserLauncher).to receive(:open).with('http://authprovider.example.com/authplz').and_return(true)
332
332
  allow(client).to receive(:exchange_code).with('abcd1234').and_return('access_token' => 'defg456', 'server' => { 'name' => 'foobar' }, 'user' => { 'name' => 'testuser' })
333
333
  subject.config.current_master = 'fooserver'
334
334
  subject.config.current_master
@@ -0,0 +1,132 @@
1
+ require 'kontena/cli/master/token_command'
2
+ require 'kontena/cli/master/token/create_command'
3
+
4
+ describe Kontena::Cli::Master::Token::CreateCommand do
5
+ include ClientHelpers
6
+ include RequirementsHelper
7
+ include OutputHelpers
8
+
9
+ expect_to_require_current_master
10
+ expect_to_require_current_master_token
11
+
12
+ let(:response) do
13
+ {
14
+ "id" => "123",
15
+ "token_type" => "bearer",
16
+ "access_token" => '1234abcd',
17
+ "refresh_token" => '2345defg',
18
+ "access_token_last_four" => "abcd",
19
+ "refresh_token_last_four" => "defg",
20
+ "expires_in" => 100,
21
+ "scopes" => "user",
22
+ "user" => {
23
+ "id" => "abc",
24
+ "email" => "user@email",
25
+ "name" => "username"
26
+ },
27
+ "server" => {
28
+ "name" => "foo"
29
+ },
30
+ "description" => "description test"
31
+ }
32
+ end
33
+
34
+ context '--description' do
35
+ it 'adds a description to token create request' do
36
+ expect(client).to receive(:post) do |path, data|
37
+ expect(path).to eq '/oauth2/authorize'
38
+ expect(data[:description]).to eq 'description test'
39
+ end.and_return(response)
40
+ expect{subject.run(['--description', 'description test'])}.not_to exit_with_error
41
+ end
42
+ end
43
+
44
+ context '--scopes' do
45
+ it 'accepts a comma separated list of scopes' do
46
+ expect(client).to receive(:post) do |path, data|
47
+ expect(path).to eq '/oauth2/authorize'
48
+ expect(data[:scope]).to eq 'xyz,zyx'
49
+ end.and_return(response)
50
+ expect{subject.run(['--scopes', 'xyz,zyx'])}.not_to exit_with_error
51
+ end
52
+ end
53
+
54
+ context '--code' do
55
+ it 'can request an authorization_code' do
56
+ expect(client).to receive(:post) do |path, data|
57
+ expect(path).to eq '/oauth2/authorize'
58
+ expect(data[:response_type]).to eq 'code'
59
+ end.and_return(response)
60
+ expect{subject.run(['--code'])}.not_to exit_with_error
61
+ end
62
+ end
63
+
64
+ context '--expires-in' do
65
+ it 'can request a token without expiration' do
66
+ expect(client).to receive(:post) do |path, data|
67
+ expect(path).to eq '/oauth2/authorize'
68
+ expect(data[:expires_in]).to eq '0'
69
+ end.and_return(response)
70
+ expect{subject.run(['--expires-in', '0'])}.not_to exit_with_error
71
+ end
72
+ end
73
+
74
+ context '--token' do
75
+ it 'requests a token and outputs the generated token' do
76
+ expect(client).to receive(:post) do |path, data|
77
+ expect(path).to eq '/oauth2/authorize'
78
+ expect(data[:response_type]).to eq 'token'
79
+ end.and_return(response)
80
+ expect{subject.run(['--token'])}.to output(/\A1234abcd\Z/).to_stdout
81
+ end
82
+ end
83
+
84
+ context '--id' do
85
+ it 'requests a token and outputs the generated token id' do
86
+ expect(client).to receive(:post) do |path, data|
87
+ expect(path).to eq '/oauth2/authorize'
88
+ expect(data[:response_type]).to eq 'token'
89
+ end.and_return(response)
90
+ expect{subject.run(['--id'])}.to output(/\A123\Z/).to_stdout
91
+ end
92
+ end
93
+
94
+ context '--user' do
95
+ it 'can request a token for another user' do
96
+ expect(client).to receive(:post) do |path, data|
97
+ expect(path).to eq '/oauth2/authorize'
98
+ expect(data[:user]).to eq 'foo@example.com'
99
+ end.and_return(response)
100
+ expect{subject.run(['--user', 'foo@example.com'])}.not_to exit_with_error
101
+ end
102
+ end
103
+
104
+ context 'no parameters' do
105
+ it 'requests an expiring user scoped token with an empty description and outputs token and refresh token' do
106
+ expect(client).to receive(:post) do |path, data|
107
+ expect(path).to eq '/oauth2/authorize'
108
+ expect(data[:user]).to be_nil
109
+ expect(data[:description]).to be_nil
110
+ expect(data[:response_type]).to eq 'token'
111
+ expect(data[:expires_in]).to eq '7200'
112
+ expect(data[:scope]).to eq 'user'
113
+ end.and_return(response)
114
+ expect{subject.run([])}.to output_yaml(
115
+ 123 => {
116
+ 'access_token' => '1234abcd',
117
+ 'refresh_token' => '2345defg',
118
+ 'access_token_last_four' => 'abcd',
119
+ 'refresh_token_last_four' => 'defg',
120
+ 'expires_in' => 100,
121
+ 'token_type' => 'bearer',
122
+ 'scopes' => 'user',
123
+ 'user_id' => 'abc',
124
+ 'user_email' => 'user@email',
125
+ 'user_name' => 'username',
126
+ 'server_name' => 'foo',
127
+ 'description' => 'description test'
128
+ }
129
+ )
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,90 @@
1
+ require 'kontena/cli/master/token_command'
2
+ require 'kontena/cli/master/token/show_command'
3
+
4
+ describe Kontena::Cli::Master::Token::ShowCommand do
5
+
6
+ include ClientHelpers
7
+ include RequirementsHelper
8
+ include OutputHelpers
9
+
10
+ expect_to_require_current_master
11
+ expect_to_require_current_master_token
12
+
13
+ context 'for an access token' do
14
+ let(:response) do
15
+ {
16
+ "id" => "123",
17
+ "token_type" => "bearer",
18
+ "access_token" => nil,
19
+ "refresh_token" => nil,
20
+ "access_token_last_four" => "abcd",
21
+ "refresh_token_last_four" => "efgh",
22
+ "expires_in" => 100,
23
+ "scopes" => "user",
24
+ "user" => {
25
+ "id" => "abc",
26
+ "email" => "user@email",
27
+ "name" => "username"
28
+ },
29
+ "server" => {
30
+ "name" => "foo"
31
+ },
32
+ "description" => "description test"
33
+ }
34
+ end
35
+
36
+ it 'requests token data from master and displays it' do
37
+ expect(client).to receive(:get).with("/oauth2/tokens/123").and_return(response)
38
+ expect{subject.run(['123'])}.to output_yaml(
39
+ 123 => {
40
+ 'token_type' => 'bearer',
41
+ 'scopes' => 'user',
42
+ 'user_id' => 'abc',
43
+ 'user_email' => 'user@email',
44
+ 'user_name' => 'username',
45
+ 'server_name' => 'foo',
46
+ 'access_token_last_four' => 'abcd',
47
+ 'refresh_token_last_four' => 'efgh',
48
+ 'expires_in' => 100,
49
+ 'description' => 'description test'
50
+ }
51
+ )
52
+ end
53
+ end
54
+
55
+ context 'for an authorization code' do
56
+ let(:response) do
57
+ {
58
+ "id" => 123,
59
+ "grant_type" => "authorization_code",
60
+ "code" => "abcd",
61
+ "scopes" => "user",
62
+ "user" => {
63
+ "id" => "abc",
64
+ "email" => "user@email",
65
+ "name" => "username"
66
+ },
67
+ "server" => {
68
+ "name" => "foo"
69
+ },
70
+ "description" => 'description test'
71
+ }
72
+ end
73
+
74
+ it 'requests auth code data from master and displays it' do
75
+ expect(client).to receive(:get).with("/oauth2/tokens/123").and_return(response)
76
+ expect{subject.run(['123'])}.to output_yaml(
77
+ 123 => {
78
+ 'code' => 'abcd',
79
+ 'token_type' => 'authorization_code',
80
+ 'scopes' => 'user',
81
+ 'user_id' => 'abc',
82
+ 'user_email' => 'user@email',
83
+ 'user_name' => 'username',
84
+ 'server_name' => 'foo',
85
+ 'description' => 'description test'
86
+ }
87
+ )
88
+ end
89
+ end
90
+ end
@@ -18,11 +18,20 @@ describe Kontena::Cli::Nodes::Labels::RemoveCommand do
18
18
  }
19
19
  end
20
20
 
21
- it "doesn't remove anything" do
22
- expect(client).to receive(:put).with('nodes/test-grid/node', {
23
- labels: [],
24
- })
25
- subject.run(['node', 'test=yes'])
21
+ context "when removing an unknown label" do
22
+ context "with --force" do
23
+ it 'does nothing' do
24
+ expect(client).not_to receive(:put)
25
+ expect{subject.run(['--force', 'node', 'test=yes'])}.not_to exit_with_error
26
+ end
27
+ end
28
+
29
+ context "without --force" do
30
+ it "exits with error" do
31
+ expect(client).not_to receive(:put)
32
+ expect{subject.run(['node', 'test=yes'])}.to exit_with_error.and output(/not found/).to_stderr
33
+ end
34
+ end
26
35
  end
27
36
  end
28
37
 
@@ -53,5 +62,26 @@ describe Kontena::Cli::Nodes::Labels::RemoveCommand do
53
62
 
54
63
  subject.run(['node', 'test=yes', 'test=no'])
55
64
  end
65
+
66
+ context "when removing an unknown label" do
67
+ context "without --force" do
68
+ it "exits with error" do
69
+ expect{subject.run(['node', 'test=yes', 'test=no', 'test=maybe'])}.to exit_with_error.and output(/Label test=maybe not found/).to_stderr
70
+ end
71
+
72
+ it "exits with plural error" do
73
+ expect{subject.run(['node', 'test=yes', 'test=no', 'test=maybe', 'test=almost'])}.to exit_with_error.and output(/Labels test=maybe, test=almost not found/).to_stderr
74
+ end
75
+ end
76
+ context "with --force" do
77
+ it 'ignores any labels that were not found with --force' do
78
+ expect(client).to receive(:put).with('nodes/test-grid/node', {
79
+ labels: ['test=yes'],
80
+ })
81
+
82
+ expect{subject.run(['--force', 'node', 'test=no', 'test=maybe', 'test=almost'])}.not_to exit_with_error
83
+ end
84
+ end
85
+ end
56
86
  end
57
87
  end
@@ -24,7 +24,7 @@ describe Kontena::Cli::Stacks::InstallCommand do
24
24
  'volumes' => [],
25
25
  'dependencies' => nil,
26
26
  'source' => /stack:/,
27
- 'parent_name' => nil,
27
+ 'parent' => nil,
28
28
  'expose' => nil
29
29
  }
30
30
  end
@@ -73,10 +73,14 @@ describe Kontena::Cli::Stacks::InstallCommand do
73
73
  end
74
74
 
75
75
  context 'with a stack including dependencies' do
76
-
77
76
  it 'installs all the dependencies' do
78
- expect(Kontena).to receive(:run!).with(["stack", "install", "-n", "deptest-dep_1", "--parent-name", "deptest", '-v', 'dep_1.dep_var=1', '--no-deploy', fixture_path('stack-with-dependencies-dep-1.yml')])
79
- expect(Kontena).to receive(:run!).with(["stack", "install", "-n", "deptest-dep_2", "--parent-name", "deptest", "-v", "dep_var=1", '--no-deploy', fixture_path('stack-with-dependencies-dep-2.yml')])
77
+ expect(Kontena).to receive(:run!).with([
78
+ "stack", "install", "-n", "deptest-dep_1", "--parent-name", "deptest", "--no-deploy",
79
+ '-v', 'dep_1.dep_var=1', fixture_path('stack-with-dependencies-dep-1.yml')
80
+ ])
81
+ expect(Kontena).to receive(:run!).with([
82
+ "stack", "install", "-n", "deptest-dep_2", "--parent-name", "deptest", '--no-deploy',
83
+ "-v", "dep_var=1", fixture_path('stack-with-dependencies-dep-2.yml')])
80
84
  expect(client).to receive(:post).with('grids/test-grid/stacks', hash_including('stack' => 'user/depstack1', 'name' => 'deptest'))
81
85
  subject.run(['-n', 'deptest', '--no-deploy', '-v', 'dep_1.dep_1.dep_var=1', fixture_path('stack-with-dependencies.yml')])
82
86
  end
@@ -143,8 +147,14 @@ describe Kontena::Cli::Stacks::InstallCommand do
143
147
  'children' => [ ]
144
148
  )
145
149
 
146
- expect(Kontena).to receive(:run!).with(["stack", "install", "-n", "deptest-dep_1", "--parent-name", "deptest", '-v', 'dep1var=test', '-v', 'dep_1.dep1dep1var=test11', '--no-deploy', fixture_path('stack-with-dependencies-dep-1.yml')]).and_return(true)
147
- expect(Kontena).to receive(:run!).with(["stack", "install", "-n", "deptest-dep_2", "--parent-name", "deptest", '-v', 'dep_var=1', '-v', 'dep2var=test2', '--no-deploy', fixture_path('stack-with-dependencies-dep-2.yml')]).and_return(true)
150
+ expect(Kontena).to receive(:run!).with([
151
+ "stack", "install", "-n", "deptest-dep_1", "--parent-name", "deptest", "--no-deploy",
152
+ '-v', 'dep1var=test', '-v', 'dep_1.dep1dep1var=test11', fixture_path('stack-with-dependencies-dep-1.yml')
153
+ ]).and_return(true)
154
+ expect(Kontena).to receive(:run!).with([
155
+ "stack", "install", "-n", "deptest-dep_2", "--parent-name", "deptest", "--no-deploy",
156
+ '-v', 'dep_var=1', '-v', 'dep2var=test2', fixture_path('stack-with-dependencies-dep-2.yml')
157
+ ]).and_return(true)
148
158
 
149
159
  allow(client).to receive(:post).and_return({})
150
160
 
@@ -50,9 +50,11 @@ describe Kontena::Cli::Stacks::RemoveCommand do
50
50
  { 'children' => [ { 'name' => 'foofoo' }, { 'name' => 'foobar' } ] }
51
51
  end
52
52
 
53
- it 'removes the children' do
53
+ before(:each) do
54
54
  allow(subject).to receive(:wait_stack_removal)
55
+ end
55
56
 
57
+ it 'removes the children' do
56
58
  expect(client).to receive(:get).with('stacks/test-grid/test-stack').and_return(
57
59
  stack_response_with_children
58
60
  )
@@ -61,7 +63,26 @@ describe Kontena::Cli::Stacks::RemoveCommand do
61
63
  expect(Kontena).to receive(:run!).with(['stack', 'remove', '--force', 'foobar'])
62
64
 
63
65
  expect(subject).to receive(:remove_stack).with('test-stack')
64
- expect{subject.run(['--force', 'test-stack'])}.not_to exit_with_error
66
+ expect {
67
+ subject.run(['--force', 'test-stack'])
68
+ }.not_to exit_with_error
69
+ end
70
+
71
+ it 'does not remove the children if keep dependencies given' do
72
+ allow(subject).to receive(:confirm_command)
73
+ expect(client).to receive(:get).with('stacks/test-grid/test-stack').and_return(
74
+ stack_response_with_children
75
+ )
76
+
77
+ expect(Kontena).not_to receive(:run!).with(['stack', 'remove', '--force', 'foofoo'])
78
+ expect(Kontena).not_to receive(:run!).with(['stack', 'remove', '--force', 'foobar'])
79
+
80
+ expect(subject).to receive(:remove_stack).with('test-stack')
81
+ expect {
82
+ expect {
83
+ subject.run(['--keep-dependencies', 'test-stack'])
84
+ }.not_to output(/depends on/).to_stdout
85
+ }.not_to exit_with_error
65
86
  end
66
87
  end
67
88
  end