kontena-cli 0.16.3 → 0.17.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/.dockerignore +1 -0
  3. data/.gitignore +3 -1
  4. data/VERSION +1 -1
  5. data/lib/kontena/callbacks/master/deploy/40_install_ssl_certificate_after_deploy.rb +32 -0
  6. data/lib/kontena/cli/apps/deploy_command.rb +2 -2
  7. data/lib/kontena/cli/apps/scale_command.rb +2 -2
  8. data/lib/kontena/cli/apps/show_command.rb +3 -2
  9. data/lib/kontena/cli/apps/yaml/validations.rb +10 -6
  10. data/lib/kontena/cli/apps/yaml/validator.rb +1 -0
  11. data/lib/kontena/cli/apps/yaml/validator_v2.rb +1 -0
  12. data/lib/kontena/cli/cloud/login_command.rb +66 -64
  13. data/lib/kontena/cli/common.rb +0 -10
  14. data/lib/kontena/cli/grids/logs_command.rb +0 -1
  15. data/lib/kontena/cli/localhost_web_server.rb +11 -3
  16. data/lib/kontena/cli/master/login_command.rb +213 -163
  17. data/lib/kontena/cli/nodes/label_command.rb +2 -0
  18. data/lib/kontena/cli/nodes/labels/add_command.rb +7 -8
  19. data/lib/kontena/cli/nodes/labels/list_command.rb +17 -0
  20. data/lib/kontena/cli/nodes/labels/remove_command.rb +7 -12
  21. data/lib/kontena/cli/nodes/show_command.rb +1 -0
  22. data/lib/kontena/cli/plugins/common.rb +8 -0
  23. data/lib/kontena/cli/plugins/install_command.rb +21 -2
  24. data/lib/kontena/cli/plugins/list_command.rb +4 -2
  25. data/lib/kontena/cli/plugins/search_command.rb +4 -2
  26. data/lib/kontena/cli/registry/create_command.rb +19 -12
  27. data/lib/kontena/cli/registry/remove_command.rb +4 -4
  28. data/lib/kontena/cli/registry_command.rb +0 -1
  29. data/lib/kontena/cli/services/create_command.rb +6 -6
  30. data/lib/kontena/cli/services/deploy_command.rb +8 -4
  31. data/lib/kontena/cli/services/list_command.rb +34 -21
  32. data/lib/kontena/cli/services/logs_command.rb +1 -1
  33. data/lib/kontena/cli/services/scale_command.rb +3 -3
  34. data/lib/kontena/cli/services/services_helper.rb +18 -14
  35. data/lib/kontena/cli/services/show_command.rb +1 -0
  36. data/lib/kontena/cli/services/update_command.rb +6 -6
  37. data/lib/kontena/cli/stack_command.rb +12 -6
  38. data/lib/kontena/cli/stacks/build_command.rb +110 -0
  39. data/lib/kontena/cli/stacks/common.rb +85 -20
  40. data/lib/kontena/cli/stacks/deploy_command.rb +30 -7
  41. data/lib/kontena/cli/stacks/install_command.rb +30 -0
  42. data/lib/kontena/cli/stacks/list_command.rb +74 -14
  43. data/lib/kontena/cli/stacks/logs_command.rb +31 -0
  44. data/lib/kontena/cli/stacks/monitor_command.rb +91 -0
  45. data/lib/kontena/cli/stacks/remove_command.rb +24 -7
  46. data/lib/kontena/cli/stacks/service_generator.rb +115 -0
  47. data/lib/kontena/cli/stacks/service_generator_v2.rb +27 -0
  48. data/lib/kontena/cli/stacks/show_command.rb +65 -13
  49. data/lib/kontena/cli/stacks/upgrade_command.rb +28 -0
  50. data/lib/kontena/cli/stacks/yaml/custom_validators/affinities_validator.rb +19 -0
  51. data/lib/kontena/cli/stacks/yaml/custom_validators/build_validator.rb +22 -0
  52. data/lib/kontena/cli/stacks/yaml/custom_validators/extends_validator.rb +21 -0
  53. data/lib/kontena/cli/stacks/yaml/custom_validators/hooks_validator.rb +54 -0
  54. data/lib/kontena/cli/stacks/yaml/custom_validators/secrets_validator.rb +22 -0
  55. data/lib/kontena/cli/stacks/yaml/reader.rb +219 -0
  56. data/lib/kontena/cli/stacks/yaml/service_extender.rb +78 -0
  57. data/lib/kontena/cli/stacks/yaml/validations.rb +71 -0
  58. data/lib/kontena/cli/stacks/yaml/validator_v3.rb +52 -0
  59. data/lib/kontena/cli/version_command.rb +5 -1
  60. data/lib/kontena/cli/vpn/create_command.rb +20 -17
  61. data/lib/kontena/cli/vpn/remove_command.rb +4 -3
  62. data/lib/kontena/client.rb +21 -20
  63. data/lib/kontena/machine/cert_helper.rb +4 -0
  64. data/lib/kontena/machine/cloud_config/cloudinit.yml +1 -1
  65. data/lib/kontena/main_command.rb +1 -1
  66. data/spec/fixtures/kontena-build.yml +2 -2
  67. data/spec/fixtures/kontena-invalid.yml +1 -1
  68. data/spec/fixtures/kontena-not-hash-service-config.yml +1 -1
  69. data/spec/fixtures/kontena-with-env-file.yml +2 -2
  70. data/spec/fixtures/kontena_build_v3.yml +23 -0
  71. data/spec/fixtures/kontena_v3.yml +20 -0
  72. data/spec/fixtures/stack-internal-extend.yml +11 -0
  73. data/spec/fixtures/stack-with-env-file.yml +21 -0
  74. data/spec/fixtures/stack-with-variables.yml +22 -0
  75. data/spec/kontena/cli/app/scale_spec.rb +3 -1
  76. data/spec/kontena/cli/cloud/login_command_spec.rb +283 -0
  77. data/spec/kontena/cli/master/login_command_spec.rb +324 -145
  78. data/spec/kontena/cli/services/link_command_spec.rb +1 -1
  79. data/spec/kontena/cli/services/secrets/link_command_spec.rb +4 -4
  80. data/spec/kontena/cli/services/secrets/unlink_command_spec.rb +2 -2
  81. data/spec/kontena/cli/services/services_helper_spec.rb +15 -11
  82. data/spec/kontena/cli/services/unlink_command_spec.rb +1 -1
  83. data/spec/kontena/cli/stacks/deploy_command_spec.rb +26 -0
  84. data/spec/kontena/cli/stacks/install_command_spec.rb +54 -0
  85. data/spec/kontena/cli/stacks/list_command_spec.rb +27 -0
  86. data/spec/kontena/cli/stacks/remove_command_spec.rb +45 -0
  87. data/spec/kontena/cli/stacks/service_generator_spec.rb +385 -0
  88. data/spec/kontena/cli/stacks/service_generator_v2_spec.rb +74 -0
  89. data/spec/kontena/cli/stacks/show_command_spec.rb +26 -0
  90. data/spec/kontena/cli/stacks/upgrade_command_spec.rb +50 -0
  91. data/spec/kontena/cli/stacks/yaml/reader_spec.rb +370 -0
  92. data/spec/kontena/cli/stacks/yaml/service_extender_spec.rb +128 -0
  93. data/spec/kontena/cli/stacks/yaml/validator_v3_spec.rb +302 -0
  94. data/spec/spec_helper.rb +6 -4
  95. data/spec/support/client_helpers.rb +1 -0
  96. metadata +57 -7
  97. data/lib/kontena/cli/registry/delete_command.rb +0 -18
  98. data/lib/kontena/cli/stacks/create_command.rb +0 -27
  99. data/lib/kontena/cli/stacks/update_command.rb +0 -27
@@ -1,5 +1,8 @@
1
1
  require_relative "../../../spec_helper"
2
2
  require 'kontena/cli/master/login_command'
3
+ require 'kontena/cli/localhost_web_server'
4
+ require 'launchy'
5
+ require 'ostruct'
3
6
 
4
7
  describe Kontena::Cli::Master::LoginCommand do
5
8
 
@@ -9,207 +12,383 @@ describe Kontena::Cli::Master::LoginCommand do
9
12
  described_class.new(File.basename($0))
10
13
  end
11
14
 
12
- let(:config) { double }
15
+ let(:client) { double(:client) }
13
16
 
14
- before(:each) do
15
- allow(subject).to receive(:config).and_return(config)
17
+ it 'should exit with error if --code and --token both given' do
18
+ expect(subject).to receive(:exit_with_error).and_throw(:exit_with_error)
19
+ subject.run(%w(--code abcd --token defg))
16
20
  end
17
21
 
18
- describe '#use_current_master_if_available' do
19
- context 'url not given' do
20
- it 'sets local url current master url if defined' do
21
- expect(config).to receive(:current_master).twice.and_return(Kontena::Cli::Config::Server.new(url: 'foo'))
22
- expect(subject).to receive(:url=).with('foo')
23
- expect(subject.use_current_master_if_available).to be_truthy
22
+ it 'should exit with error if --code and --join both given' do
23
+ expect(subject).to receive(:exit_with_error).and_throw(:exit_with_error)
24
+ subject.run(%w(--code abcd --join defg))
25
+ end
26
+
27
+ it 'should exit with error if --code and --force both given' do
28
+ expect(subject).to receive(:exit_with_error).and_throw(:exit_with_error)
29
+ subject.run(%w(--code abcd --force))
30
+ end
31
+
32
+ it 'should exit with error if --token and --force both given' do
33
+ expect(subject).to receive(:exit_with_error).and_throw(:exit_with_error)
34
+ subject.run(%w(--token abcd --force))
35
+ end
36
+
37
+ describe '#select_a_server' do
38
+ let(:config) { double(:config) }
39
+ let(:server) { Kontena::Cli::Config::Server.new(url: 'https://foo', name: 'server') }
40
+
41
+ before(:each) do
42
+ allow(subject).to receive(:config).and_return(config)
43
+ end
44
+
45
+ context 'no url or name provided' do
46
+ it 'tries to use current_master' do
47
+ expect(config).to receive(:current_master).at_least(:once).and_return(server)
48
+ expect(subject.select_a_server(nil, nil)).to eq server
24
49
  end
25
50
 
26
- it 'raises if no current master and no url' do
27
- subject.url = nil
51
+ it 'exits with error if current_master not set' do
28
52
  expect(config).to receive(:current_master).and_return(nil)
29
- expect(subject).to receive(:exit_with_error)
30
- subject.use_current_master_if_available
53
+ expect(subject).to receive(:exit_with_error).and_throw(:exit_with_error)
54
+ subject.select_a_server(nil, nil)
31
55
  end
32
56
  end
33
57
 
34
- context 'url given' do
35
- it 'returns nil' do
36
- subject.url = 'foofoo'
37
- expect(subject.use_current_master_if_available).to be_nil
58
+ context 'name provided' do
59
+ context 'with url' do
60
+ it 'should return the existing server if an exact match is found' do
61
+ expect(config).to receive(:find_server_by).and_return(server)
62
+ expect(subject.select_a_server(server.name, server.url)).to be server
63
+ end
64
+
65
+ it 'should return the existing one but update its url if a name match is found' do
66
+ allow(config).to receive(:find_server_by).and_return(nil)
67
+ expect(config).to receive(:find_server).and_return(server)
68
+ expect(subject.select_a_server(server.name, 'http://foofoo')).to be server
69
+ expect(server.url).to eq 'http://foofoo'
70
+ end
71
+
72
+ it 'should create a new server entry if no exact match or name match is found' do
73
+ allow(config).to receive(:find_server_by).and_return(nil)
74
+ allow(config).to receive(:find_server).and_return(nil)
75
+ new_server = subject.select_a_server('fooserver', 'http://foofoo')
76
+ expect(new_server).not_to be server
77
+ expect(new_server.url).to eq 'http://foofoo'
78
+ expect(new_server.name).to eq 'fooserver'
79
+ end
38
80
  end
39
- end
40
- end
41
81
 
42
- describe '#use_master_by_name' do
43
- context 'url given' do
44
- it 'should return nil when url looks like an url' do
45
- subject.url = 'http://foo'
46
- expect(subject).not_to receive(:config)
47
- expect(subject.use_master_by_name).to be_nil
82
+ context 'without url' do
83
+ it 'should return a server with that name if it has an url' do
84
+ expect(config).to receive(:find_server).with('foo').and_return(server)
85
+ expect(subject.select_a_server('foo', nil)).to be server
86
+ expect(server.url).not_to be_nil
87
+ end
88
+
89
+ it 'should exit with error if a server with that name is found but it does not have an url' do
90
+ server.url = nil
91
+ expect(config).to receive(:find_server).with('foo').and_return(server)
92
+ expect(subject).to receive(:exit_with_error).and_throw(:exit_with_error)
93
+ subject.select_a_server('foo', nil)
94
+ end
48
95
  end
49
96
  end
50
97
 
51
- context 'name given' do
52
- it 'should try to look for servers by name' do
53
- expect(config).to receive(:find_server).and_return(Kontena::Cli::Config::Server.new(url: 'https://foo'))
54
- subject.url = 'foomaster'
55
- expect(subject).to receive(:url=).with('https://foo')
56
- subject.use_master_by_name
98
+ context 'url provided without name' do
99
+ context 'url looks like an url' do
100
+ it 'should try to find a server with that url and return it if found' do
101
+ expect(config).to receive(:find_server_by).with({ :url => 'https://foo' }).and_return(server)
102
+ expect(subject.select_a_server(nil, 'https://foo')).to be server
103
+ end
104
+
105
+ it 'should create a new server entry if not found' do
106
+ expect(config).to receive(:find_server_by).with({ :url => 'https://foo' }).and_return(nil)
107
+ new_server = subject.select_a_server(nil, 'https://foo')
108
+ expect(new_server).not_to be server
109
+ expect(new_server.url).to eq 'https://foo'
110
+ end
111
+ end
112
+
113
+ context 'url looks like a name' do
114
+ it 'should return a server with that name if it has an url' do
115
+ expect(config).to receive(:find_server).with('foo').and_return(server)
116
+ expect(subject.select_a_server(nil, 'foo')).to be server
117
+ expect(server.url).not_to be_nil
118
+ end
119
+
120
+ it 'should exit with error if a server with that name is found but it does not have an url' do
121
+ server.url = nil
122
+ expect(config).to receive(:find_server).with('foo').and_return(server)
123
+ expect(subject).to receive(:exit_with_error).and_throw(:exit_with_error)
124
+ subject.select_a_server(nil, 'foo')
125
+ end
126
+
127
+ it 'should exit with error if a server with that name is not found' do
128
+ expect(config).to receive(:find_server).with('foo').and_return(nil)
129
+ expect(subject).to receive(:exit_with_error).and_throw(:exit_with_error)
130
+ subject.select_a_server(nil, 'foo')
131
+ end
57
132
  end
58
133
  end
59
134
  end
60
135
 
61
- describe '#find_server_or_create_new' do
62
-
63
- let(:existing_server) { Kontena::Cli::Config::Server.new(url: 'https://foo', name: 'existing') }
136
+ context 'with a server with a token in config' do
137
+ before(:each) do
138
+ allow(File).to receive(:read).and_return('
139
+ {
140
+ "current_server": null,
141
+ "current_account": "kontena",
142
+ "servers": [
143
+ {
144
+ "name": "fooserver",
145
+ "url": "http://foo.example.com:80",
146
+ "username": "admin",
147
+ "grid": "test",
148
+ "token": "abcd",
149
+ "token_expires_at": 0,
150
+ "refresh_token": null
151
+ }
152
+ ]
153
+ }
154
+ ')
155
+ allow(File).to receive(:write).and_return(true)
156
+ allow(File).to receive(:exist?).and_return(true)
157
+ allow(File).to receive(:readable?).and_return(true)
158
+ allow(Kontena::Client).to receive(:new).and_return(client)
159
+ allow(Launchy).to receive(:open).and_return(true)
160
+ allow(Kontena::LocalhostWebServer).to receive(:port).and_return(12345)
161
+ allow(Kontena::LocalhostWebServer).to receive(:serve_one).and_return(
162
+ { 'code' => 'abcd1234' }
163
+ )
164
+ end
64
165
 
65
- it 'should try to pick up an existing server from config' do
66
- subject.name = 'name'
67
- expect(config).to receive(:find_server_by).with(url: 'foo', name: 'name').and_return(existing_server)
68
- expect(config).to receive(:current_server=).with(existing_server.name)
69
- expect(subject.find_server_or_create_new('foo')).to eq existing_server
166
+ it 'logs in and changes the url of a named server in config' do
167
+ expect(File).to receive(:write) do |fn, content|
168
+ data = JSON.parse(content)
169
+ expect(data['servers'].size).to eq 1
170
+ expect(data['servers'].first['name']).to eq 'fooserver'
171
+ expect(data['servers'].first['url']).to eq 'http://foo2.example.com'
172
+ expect(data['servers'].first['token']).to eq 'abcdefg'
173
+ end.and_return(true)
174
+ expect(subject.config).to receive(:find_server).at_least(:once).with('fooserver').and_call_original
175
+ expect(client).to receive(:authentication_ok?).and_return(true)
176
+ subject.run(%w(--token abcdefg --name fooserver --grid foogrid http://foo2.example.com))
70
177
  end
71
178
 
72
- it 'should create a new server instance if existing not found' do
73
- expect(config).to receive(:find_server_by).and_return(nil)
74
- subject.name = "foofoo1"
75
- servers = []
76
- expect(config).to receive(:servers).and_return(servers)
77
- expect(config).to receive(:current_server=).with('foofoo1')
78
- expect(subject.find_server_or_create_new('http://foo').name).to eq 'foofoo1'
79
- expect(servers.first.url).to eq 'http://foo'
80
- expect(servers.first.name).to eq 'foofoo1'
179
+ it 'logs in and creates a new entry in config' do
180
+ expect(File).to receive(:write) do |fn, content|
181
+ data = JSON.parse(content)
182
+ expect(data['servers'].size).to eq 2
183
+ expect(data['servers'].first['name']).to eq 'fooserver'
184
+ expect(data['servers'].first['url']).to eq 'http://foo.example.com:80'
185
+ expect(data['servers'].first['token']).to eq 'abcd'
186
+ expect(data['servers'].last['name']).to eq 'fooserver2'
187
+ expect(data['servers'].last['url']).to eq 'http://foo2.example.com'
188
+ expect(data['servers'].last['token']).to eq 'abcdefg'
189
+ end.and_return(true)
190
+ expect(subject.config).to receive(:find_server).at_least(:once).with('fooserver2').and_call_original
191
+ expect(client).to receive(:authentication_ok?).and_return(true)
192
+ subject.run(%w(--token abcdefg --name fooserver2 --grid foogrid http://foo2.example.com))
81
193
  end
82
- end
83
194
 
84
- describe '#set_server_token' do
85
- let(:server) { Kontena::Cli::Config::Server.new(name: 'some_server') }
86
- let(:token) { Kontena::Cli::Config::Token.new(access_token: 'bartoken') }
195
+ it 'uses the existing token if it works and no --code --token --join or --force set when using url' do
196
+ expect(client).to receive(:authentication_ok?).and_return(true)
197
+ subject.run(%w(http://foo.example.com:80))
198
+ expect(subject.config.servers.size).to eq 1
199
+ expect(subject.config.current_server).to eq 'fooserver'
200
+ expect(subject.config.servers.first.name).to eq 'fooserver'
201
+ expect(subject.config.servers.first.url).to eq 'http://foo.example.com:80'
202
+ end
87
203
 
88
- it 'should set token from parameters as the servers access token' do
89
- subject.token = 'footoken'
90
- expect(server).to receive(:token=) do |token|
91
- expect(token.access_token).to eq 'footoken'
92
- end
93
- subject.set_server_token(server)
204
+ it 'uses the existing token if it works and no --code --token --join or --force set when using --name' do
205
+ expect(client).to receive(:authentication_ok?).and_return(true)
206
+ subject.run(%w(--name fooserver))
207
+ expect(subject.config.servers.size).to eq 1
208
+ expect(subject.config.current_server).to eq 'fooserver'
209
+ expect(subject.config.servers.first.name).to eq 'fooserver'
210
+ expect(subject.config.servers.first.url).to eq 'http://foo.example.com:80'
94
211
  end
95
212
 
96
- it 'should clear servers existing token when forced' do
97
- subject.force = true
98
- server.token = token
99
- subject.set_server_token(server)
100
- expect(server.access_token).to be_nil
213
+ it 'uses the existing token if it works and no --code --token --join or --force set when using name in url param' do
214
+ expect(client).to receive(:authentication_ok?).and_return(true)
215
+ subject.run(%w(fooserver))
216
+ expect(subject.config.servers.size).to eq 1
217
+ expect(subject.config.current_server).to eq 'fooserver'
218
+ expect(subject.config.servers.first.name).to eq 'fooserver'
219
+ expect(subject.config.servers.first.url).to eq 'http://foo.example.com:80'
101
220
  end
102
221
 
103
- it 'should add a blank token if server has none' do
104
- server.token = nil
105
- subject.set_server_token(server)
106
- expect(server.access_token).to be_nil
107
- expect(server.token.parent_name).to eq 'some_server'
222
+ it 'uses current master and its token token if it works and no --code --token --join or --force set when no params' do
223
+ subject.config.current_server = 'fooserver'
224
+ expect(client).to receive(:authentication_ok?).and_return(true)
225
+ subject.run([])
226
+ expect(subject.config.servers.size).to eq 1
227
+ expect(subject.config.current_server).to eq 'fooserver'
228
+ expect(subject.config.servers.first.name).to eq 'fooserver'
229
+ expect(subject.config.servers.first.url).to eq 'http://foo.example.com:80'
108
230
  end
109
231
 
110
- it 'should keep the existing token unless a new one is supplied' do
111
- server.token = token
112
- subject.token = nil
113
- subject.force = false
114
- subject.set_server_token(server)
115
- expect(server.token).to eq token
232
+ it 'goes to web flow when the existing token does not work' do
233
+ expect(client).to receive(:authentication_ok?).and_return(false)
234
+ expect(subject).to receive(:web_flow).and_return(true)
235
+ subject.run(%w(fooserver))
116
236
  end
117
237
  end
118
238
 
119
- describe '#use_authorization_code' do
120
- let(:client) { double }
121
-
239
+ context 'with no servers in config' do
240
+ let(:webserver) { double(:webserver) }
122
241
  before(:each) do
123
- allow(subject.config).to receive(:current_server=)
124
- end
125
-
126
- it 'should set the local name to name provided from server if no name was set' do
127
- expect(Kontena::Client).to receive(:new).and_return(client)
128
- expect(client).to receive(:exchange_code).with('abcd1234').and_return(
129
- {
130
- 'access_token' => 'token',
131
- 'refresh_token' => 'refresh_token',
132
- 'expires_in' => 1000,
133
- 'server' => {
134
- 'name' => 'foofoo1'
135
- }
242
+ allow(File).to receive(:read).and_return('
243
+ {
244
+ "current_server": null,
245
+ "current_account": "kontena",
246
+ "servers": []
136
247
  }
248
+ ')
249
+ allow(File).to receive(:write).and_return(true)
250
+ allow(File).to receive(:exist?).and_return(true)
251
+ allow(File).to receive(:readable?).and_return(true)
252
+ allow(Kontena::Client).to receive(:new).and_return(client)
253
+ allow(Kontena::LocalhostWebServer).to receive(:new).and_return(webserver)
254
+ allow(webserver).to receive(:port).and_return(12345)
255
+ allow(webserver).to receive(:serve_one).and_return(
256
+ { 'code' => 'abcd1234' }
137
257
  )
258
+ end
138
259
 
139
- server = Kontena::Cli::Config::Server.new(name: nil, url: 'http://foo')
140
- subject.use_authorization_code(server, 'abcd1234')
141
- expect(server.token.access_token).to eq 'token'
142
- expect(server.name).to eq 'foofoo1'
143
- end
144
-
145
- it 'should not touch the local name if the server already has a name' do
146
- expect(Kontena::Client).to receive(:new).and_return(client)
147
- expect(client).to receive(:exchange_code).with('abcd1234').and_return(
148
- {
149
- 'access_token' => 'token',
150
- 'refresh_token' => 'refresh_token',
151
- 'expires_in' => 1000,
152
- 'server' => {
153
- 'name' => 'foofoo1'
154
- }
155
- }
156
- )
260
+ it 'creates a new entry when successful login using web flow' do
261
+ expect(client).to receive(:last_response).at_least(:once).and_return(OpenStruct.new(status: 302, headers: { 'Location' => 'http://authprovider.example.com/authplz' }))
262
+ expect(client).to receive(:request) do |opts|
263
+ expect(opts[:path]).to eq "/authenticate?redirect_uri=http%3A%2F%2Flocalhost%3A12345%2Fcb&expires_in=7200"
264
+ expect(opts[:http_method]).to eq :get
265
+ end.and_return({})
266
+ expect(Launchy).to receive(:open).with('http://authprovider.example.com/authplz').and_return(true)
267
+ expect(client).to receive(:exchange_code).with('abcd1234').and_return('access_token' => 'defg456', 'server' => { 'name' => 'foobar' }, 'user' => { 'name' => 'testuser' })
268
+ subject.run(%w(--skip-grid-auto-select http://foobar.example.com))
269
+ expect(subject.config.servers.size).to eq 1
270
+ server = subject.config.servers.first
271
+ expect(server.url).to eq 'http://foobar.example.com'
272
+ expect(server.name).to eq 'foobar'
273
+ expect(server.username).to eq 'testuser'
274
+ expect(server.token.access_token).to eq 'defg456'
275
+ expect(server.token.refresh_token).to be_nil
276
+ expect(server.token.expires_at).to be_nil
277
+ end
157
278
 
158
- server = Kontena::Cli::Config::Server.new(name: 'foofoo2', url: 'http://foo')
159
- subject.use_authorization_code(server, 'abcd1234')
160
- expect((Time.now.utc.to_i+800..Time.now.utc.to_i+1100).cover?(server.token.expires_at.to_i)).to be_truthy
161
- expect(server.name).to eq 'foofoo2'
279
+ it 'creates a new entry when successful login using --code' do
280
+ expect(client).to receive(:exchange_code).with('defg').and_return('access_token' => 'defg456', 'server' => { 'name' => 'foobar' }, 'user' => { 'name' => 'testuser' })
281
+ subject.run(%w(--skip-grid-auto-select --code defg http://foobar.example.com))
282
+ expect(subject.config.servers.size).to eq 1
283
+ server = subject.config.servers.first
284
+ expect(server.url).to eq 'http://foobar.example.com'
285
+ expect(server.name).to eq 'foobar'
286
+ expect(server.username).to eq 'testuser'
287
+ expect(server.token.access_token).to eq 'defg456'
288
+ expect(server.token.refresh_token).to be_nil
289
+ expect(server.token.expires_at).to be_nil
290
+ end
291
+
292
+ it 'creates an entry when using --remote' do
293
+ expect(client).to receive(:last_response).at_least(:once).and_return(OpenStruct.new(status: 302, headers: { 'Location' => 'http//authprovider.example.com/authplz' }))
294
+ expect(client).to receive(:request) do |opts|
295
+ expect(opts[:path]).to eq "/authenticate?redirect_uri=%2Fcode&expires_in=7200"
296
+ expect(opts[:http_method]).to eq :get
297
+ end.and_return({})
298
+ expect(subject.config).to receive(:find_server).with('kontena-master').and_return(true)
299
+ expect(subject.config).to receive(:find_server).with('kontena-master-2').at_least(:once).and_return(nil)
300
+ expect{subject.run(%w(--remote http://foobar.example.com))}.to raise_error(SystemExit) do |ex|
301
+ expect(ex.status).to eq 1
302
+ end
303
+ expect(subject.config.servers.size).to eq 1
304
+ server = subject.config.servers.first
305
+ expect(server.url).to eq 'http://foobar.example.com'
306
+ expect(server.name).to eq 'kontena-master-2'
307
+ expect(server.username).to be_nil
308
+ expect(server.token.access_token).to be_nil
309
+ expect(server.token.refresh_token).to be_nil
310
+ expect(server.token.expires_at).to be_nil
162
311
  end
163
312
  end
164
313
 
165
- describe '#in_to_at' do
166
- it 'should return nil when expires_in is <0 or nil' do
167
- expect(subject.in_to_at(0)).to be_nil
168
- expect(subject.in_to_at(-1)).to be_nil
169
- expect(subject.in_to_at(nil)).to be_nil
314
+ describe '#authentication_url_from_master' do
315
+ it 'should exit with error if master returns a json with error' do
316
+ allow(Kontena::Client).to receive(:new).and_return(client)
317
+ expect(client).to receive(:last_response).at_least(:once).and_return(OpenStruct.new(status: 400, headers: {}))
318
+ expect(client).to receive(:request).and_return('error' => 'no good')
319
+ expect(subject).to receive(:exit_with_error).with(/no good/).and_throw(:exit_with_error)
320
+ subject.authentication_url_from_master('https://foo.example.com', remote: true)
170
321
  end
171
322
 
172
- it 'should return a timestamp when expires_in is >0' do
173
- time = Time.now.utc.to_i
174
- expect((time + 80..time + 120).cover?(subject.in_to_at(100))).to be_truthy
323
+ it 'should exit with error if master returns text' do
324
+ allow(Kontena::Client).to receive(:new).and_return(client)
325
+ expect(client).to receive(:last_response).at_least(:once).and_return(OpenStruct.new(status: 400, headers: {}))
326
+ expect(client).to receive(:request).and_return('Fail!')
327
+ expect(subject).to receive(:exit_with_error).and_throw(:exit_with_error)
328
+ subject.authentication_url_from_master('https://foo.example.com', remote: true)
175
329
  end
176
- end
177
330
 
178
- describe '#update_server_name' do
179
- let(:server) { Kontena::Cli::Config::Server.new }
180
- let(:response) { { 'access_token' => 'token', 'server' => { 'name' => 'foo2' } } }
331
+ it 'should exit with error if master returns nil' do
332
+ allow(Kontena::Client).to receive(:new).and_return(client)
333
+ expect(client).to receive(:last_response).at_least(:once).and_return(OpenStruct.new(status: 400, headers: {}))
334
+ expect(client).to receive(:request).and_return(nil)
335
+ expect(subject).to receive(:exit_with_error).with(/Invalid.+?400/).and_throw(:exit_with_error)
336
+ subject.authentication_url_from_master('https://foo.example.com', remote: true)
337
+ end
338
+ end
181
339
 
182
- it 'should do nothing if server already has a name' do
183
- server.name = 'foofoofoo'
184
- subject.update_server_name(server, response)
185
- expect(server.name).to eq 'foofoofoo'
340
+ describe '#display_remote_message' do
341
+ it 'should only print out the url if --silent' do
342
+ subject.silent = true
343
+ server = Kontena::Cli::Config::Server.new(url: 'https://foo', name: 'server')
344
+ expect(subject).to receive(:authentication_url_from_master).and_return('http://foo')
345
+ expect{subject.display_remote_message(server, {})}.to output("http://foo\n").to_stdout
186
346
  end
347
+ end
187
348
 
188
- it 'should set the name from name parameter if set' do
189
- subject.name = 'abcd'
190
- subject.update_server_name(server, response)
191
- expect(server.name).to eq 'abcd'
349
+ describe '#authentication_path' do
350
+ it 'should raise if not doing --remote and the local port is missing' do
351
+ expect{subject.authentication_path(local_port: nil, remote: false)}.to raise_error(ArgumentError)
192
352
  end
353
+ end
354
+
355
+ describe '#update_server_token' do
356
+ let(:server) { Kontena::Cli::Config::Server.new(url: 'https://foo', name: 'server') }
193
357
 
194
- it 'should set the name from server response if returned' do
195
- subject.update_server_name(server, response)
196
- expect(server.name).to eq 'foo2'
358
+ it 'should raise unless response is a hash' do
359
+ expect{subject.update_server_token(server, nil)}.to raise_error(TypeError)
197
360
  end
198
361
 
199
- it 'should use a default name if no other can be figured out' do
200
- expect(subject.config).to receive(:find_server).with('kontena-master').and_return(nil)
201
- subject.update_server_name(server, response.reject{|k,v| k=='server'})
202
- expect(server.name).to eq 'kontena-master'
362
+ it 'should do a code exchange if response has "code"' do
363
+ expect(subject).to receive(:use_authorization_code).with(server, "abcd")
364
+ subject.update_server_token(server, "code" => "abcd")
203
365
  end
204
366
 
205
- it 'should use a default name with suffix if one already exists' do
206
- expect(subject.config).to receive(:find_server).with('kontena-master').and_return(true)
207
- expect(subject.config).to receive(:find_server).with('kontena-master-2').and_return(true)
208
- expect(subject.config).to receive(:find_server).with('kontena-master-3').and_return(nil)
209
- subject.update_server_name(server, response.reject{|k,v| k=='server'})
210
- expect(server.name).to eq 'kontena-master-3'
367
+ it 'should exit with error if response has error' do
368
+ expect(subject).to receive(:exit_with_error).and_throw(:exit_with_error)
369
+ subject.update_server_token(server, "error" => "abcd")
211
370
  end
212
371
 
372
+ it 'should update the token if all is good' do
373
+ subject.update_server_token(server, 'access_token' => 'abcd1234', 'refresh_token' => 'defg', 'expires_at' => 1234)
374
+ expect(server.token.access_token).to eq 'abcd1234'
375
+ expect(server.token.refresh_token).to eq 'defg'
376
+ expect(server.token.expires_at).to eq 1234
377
+ end
213
378
  end
214
379
 
380
+ describe '#update_server_name' do
381
+ let(:server) { Kontena::Cli::Config::Server.new(url: 'https://foo', name: nil) }
382
+
383
+ it 'should use a default name if response has no name' do
384
+ subject.update_server_name(server, "foo" => "foofoo")
385
+ expect(server.name).to eq 'kontena-master'
386
+ end
387
+
388
+ it 'should not mess with the server name if it already has one' do
389
+ server.name = 'foofoo'
390
+ subject.update_server_name(server, "server" => { "name" => "barbar" })
391
+ expect(server.name).to eq 'foofoo'
392
+ end
393
+ end
215
394
  end