kontena-cli 0.16.0.pre7 → 0.16.0.pre8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/kontena-cli.gemspec +2 -5
  4. data/lib/kontena/callbacks/master/deploy/05_before_deploy_configuration_wizard.rb +15 -21
  5. data/lib/kontena/callbacks/master/deploy/50_authenticate_after_deploy.rb +5 -3
  6. data/lib/kontena/callbacks/master/deploy/55_create_initial_grid_after_deploy.rb +3 -1
  7. data/lib/kontena/callbacks/master/deploy/60_configure_auth_provider_after_deploy.rb +7 -18
  8. data/lib/kontena/callbacks/master/deploy/70_invite_self_after_deploy.rb +93 -0
  9. data/lib/kontena/callbacks/master/deploy/90_proptip_after_deploy.rb +33 -0
  10. data/lib/kontena/cli/apps/build_command.rb +2 -1
  11. data/lib/kontena/cli/apps/common.rb +3 -2
  12. data/lib/kontena/cli/apps/config_command.rb +3 -3
  13. data/lib/kontena/cli/apps/deploy_command.rb +1 -0
  14. data/lib/kontena/cli/apps/docker_helper.rb +7 -7
  15. data/lib/kontena/cli/apps/list_command.rb +1 -1
  16. data/lib/kontena/cli/apps/logs_command.rb +1 -1
  17. data/lib/kontena/cli/apps/monitor_command.rb +2 -2
  18. data/lib/kontena/cli/apps/remove_command.rb +1 -1
  19. data/lib/kontena/cli/apps/restart_command.rb +1 -1
  20. data/lib/kontena/cli/apps/scale_command.rb +1 -1
  21. data/lib/kontena/cli/apps/start_command.rb +1 -1
  22. data/lib/kontena/cli/apps/stop_command.rb +1 -1
  23. data/lib/kontena/cli/apps/yaml/custom_validators/affinities_validator.rb +19 -0
  24. data/lib/kontena/cli/apps/yaml/custom_validators/build_validator.rb +22 -0
  25. data/lib/kontena/cli/apps/yaml/custom_validators/extends_validator.rb +21 -0
  26. data/lib/kontena/cli/apps/yaml/custom_validators/hooks_validator.rb +54 -0
  27. data/lib/kontena/cli/apps/yaml/custom_validators/secrets_validator.rb +22 -0
  28. data/lib/kontena/cli/apps/yaml/validations.rb +60 -90
  29. data/lib/kontena/cli/apps/yaml/validator.rb +9 -31
  30. data/lib/kontena/cli/apps/yaml/validator_v2.rb +13 -40
  31. data/lib/kontena/cli/cloud/login_command.rb +2 -2
  32. data/lib/kontena/cli/cloud/master/add_command.rb +114 -34
  33. data/lib/kontena/cli/cloud/master/list_command.rb +5 -2
  34. data/lib/kontena/cli/cloud/master/remove_command.rb +69 -0
  35. data/lib/kontena/cli/cloud/master_command.rb +2 -2
  36. data/lib/kontena/cli/common.rb +10 -17
  37. data/lib/kontena/cli/config.rb +4 -3
  38. data/lib/kontena/cli/grids/env_command.rb +5 -5
  39. data/lib/kontena/cli/localhost_web_server.rb +1 -1
  40. data/lib/kontena/cli/master/init_cloud_command.rb +21 -0
  41. data/lib/kontena/cli/master/login_command.rb +28 -29
  42. data/lib/kontena/cli/master/remove_command.rb +58 -0
  43. data/lib/kontena/cli/master/token/create_command.rb +6 -0
  44. data/lib/kontena/cli/master/users/invite_command.rb +4 -1
  45. data/lib/kontena/cli/master/users/roles/add_command.rb +4 -3
  46. data/lib/kontena/cli/master_command.rb +8 -9
  47. data/lib/kontena/cli/services/list_command.rb +3 -2
  48. data/lib/kontena/cli/services/services_helper.rb +1 -1
  49. data/lib/kontena/client.rb +31 -47
  50. data/lib/kontena/presets/kontena_auth_provider.yml +2 -2
  51. data/lib/kontena_cli.rb +12 -0
  52. data/spec/kontena/cli/app/docker_helper_spec.rb +9 -4
  53. data/spec/kontena/cli/app/yaml/validator_spec.rb +66 -71
  54. data/spec/kontena/cli/app/yaml/validator_v2_spec.rb +51 -58
  55. metadata +25 -59
  56. data/lib/kontena/callbacks/master/deploy/90_suggest_inviting_yourself_after_deploy.rb +0 -24
  57. data/lib/kontena/cli/cloud/master/delete_command.rb +0 -20
@@ -79,7 +79,7 @@ module Kontena::Cli::Cloud
79
79
  any_key_to_continue(10)
80
80
 
81
81
  puts "If the browser does not open, try visiting this URL manually:"
82
- puts "<#{uri.to_s}>"
82
+ puts "#{uri.to_s}"
83
83
  puts
84
84
 
85
85
  server_thread = Thread.new { Thread.main['response'] = web_server.serve_one }
@@ -116,7 +116,7 @@ module Kontena::Cli::Cloud
116
116
 
117
117
  response = client.get(path) rescue nil
118
118
  if response && response.kind_of?(Hash)
119
- kontena_account.username = response['username']
119
+ kontena_account.username = response['data']['attributes']['username']
120
120
  config.write
121
121
  display_logo
122
122
  display_login_info(only: :account)
@@ -7,47 +7,127 @@ module Kontena::Cli::Cloud::Master
7
7
 
8
8
  requires_current_account_token
9
9
 
10
- parameter "NAME", "Master name"
10
+ parameter "[NAME]", "Master name"
11
11
 
12
- option ['--redirect-uri'], '[URL]', 'Se master redirect URL'
13
- option ['--url'], '[URL]', 'Se master URL'
14
- option ['--provider'], '[NAME]', 'Se master provider'
15
- option ['--name'], '[NAME]', 'Se master name', hidden: true
16
- option ['--version'], '[VERSION]', 'Se master version', hidden: true
17
- option ['--owner'], '[NAME]', 'Se master owner', hidden: true
12
+ option ['--redirect-uri'], '[URL]', 'Set master redirect URL'
13
+ option ['--url'], '[URL]', 'Set master URL'
14
+ option ['--provider'], '[NAME]', 'Set master provider'
15
+ option ['--name'], '[NAME]', 'Set master name', hidden: true
16
+ option ['--version'], '[VERSION]', 'Set master version', hidden: true
17
+ option ['--owner'], '[NAME]', 'Set master owner', hidden: true
18
18
 
19
- option ['--id'], :flag, 'Just output the ID'
20
- option ['--arg'], :flag, 'Output as command line arguments'
19
+ option ['--id'], :flag, 'Just output the ID'
20
+ option ['--return'], :flag, 'Return the ID', hidden: true
21
+ option ['--force'], :flag, "Don't ask questions"
21
22
 
22
- option ['--return'], :flag, 'Return the ID', hidden: true
23
+ option ['--cloud-master-id'], '[ID]', "Use existing cloud master ID", hidden: true
24
+ option ['--current'], :flag, 'Register and configure current master', hidden: true
23
25
 
24
- def execute
25
- attributes = { 'name' => self.name }
26
- attributes['url'] = self.url if self.url
27
- attributes['provider'] = self.provider if self.provider
28
- attributes['redirect-uri'] = self.redirect_uri if self.redirect_uri
29
- attributes['version'] = self.version if self.version
30
- attributes['owner'] = self.owner if self.owner
26
+ def register(name, url = nil, provider = nil, redirect_uri = nil, version = nil, owner = nil)
27
+ attributes = {}
28
+ attributes['name'] = name
29
+ attributes['url'] = url if url
30
+ attributes['provider'] = provider if provider
31
+ attributes['redirect-uri'] = redirect_uri if redirect_uri
32
+ attributes['version'] = version if version
33
+ attributes['owner'] = owner if owner
31
34
 
32
35
  response = cloud_client.post('user/masters', { data: { attributes: attributes } })
33
- if response.kind_of?(Hash)
34
- if response['error']
35
- puts "Failed: #{response['error']}"
36
- exit 1
37
- else
38
- if self.return?
39
- return response['data']['id']
40
- elsif self.id?
41
- puts response['data']['id']
42
- elsif self.arg?
43
- puts "--client-id #{response['data']['attributes']['client-id']} --client-secret #{response['data']['attributes']['client-secret']}"
44
- else
45
- puts "Created master.".colorize(:green)
46
- puts "ID: #{response['data']['id']}"
47
- puts "Client ID: #{response['data']['attributes']['client-id']}"
48
- puts "Client Secret: #{response['data']['attributes']['client-secret']}"
49
- end
36
+ exit_with_error "Failed (invalid response)" unless response.kind_of?(Hash)
37
+ exit_with_error "Failed (no data)" unless response['data']
38
+ exit_with_error "Failed: #{response['error']}" if response['error']
39
+ response
40
+ end
41
+
42
+ def get_existing(id)
43
+ cloud_client.get("user/masters/#{id}")
44
+ end
45
+
46
+ def cloud_masters
47
+ masters = []
48
+ spinner "Retrieving a list of your registered Kontena Masters in Kontena Cloud" do |spin|
49
+ begin
50
+ masters = Kontena.run("cloud master list --return", returning: :result)
51
+ rescue SystemExit
52
+ spin.fail
53
+ end
54
+ end
55
+ masters
56
+ end
57
+
58
+ def new_cloud_master_name(master_name)
59
+ masters = cloud_masters
60
+ return master_name if masters.empty?
61
+
62
+ existing_master = masters.find { |m| m['attributes']['name'] == master_name }
63
+ return master_name unless existing_master
64
+
65
+ new_name = "#{master_name}-2"
66
+ new_name.succ! until masters.find { |m| m['attributes']['name'] == new_name }.nil?
67
+ new_name
68
+ end
69
+
70
+ def register_current
71
+ require_api_url
72
+ require_token
73
+
74
+ unless self.force?
75
+ puts "Proceeding will:"
76
+ puts " * Register the Kontena Master #{current_master.name} to Kontena Cloud"
77
+ puts " * Configure the Kontena Master to use Kontena Cloud as the"
78
+ puts " authentication provider"
79
+ puts
80
+ puts "After this:"
81
+ puts " * Users will not be able to reauthenticate without authorizing the"
82
+ puts " Master to access their Kontena Cloud user information"
83
+ puts " * Users that have registered a different email address to Kontena"
84
+ puts " Cloud than the one they currently have as their username in the"
85
+ puts " master will not be able to authenticate before an administrator"
86
+ puts " of the Kontena Master creates an invitation code for them"
87
+ puts " (kontena master users invite old@email.example.com)"
88
+ exit_with_error "Aborted" unless prompt.yes?("Proceed?")
89
+ end
90
+
91
+ new_name = new_cloud_master_name(current_master.name)
92
+
93
+ if self.cloud_master_id
94
+ response = spinner "Retrieving Master information from Kontena Cloud using id" do
95
+ get_existing(self.cloud_master_id)
50
96
  end
97
+ else
98
+ response = spinner "Registering current Kontena Master '#{current_master.name}' #{" as '#{new_name}' " unless new_name == current_master.name}to Kontena Cloud" do
99
+ register(new_name, current_master.url)
100
+ end
101
+ end
102
+
103
+ spinner "Loading Kontena Cloud auth provider base configuration to Kontena Master" do
104
+ Kontena.run('master config import --force --preset kontena_auth_provider')
105
+ end
106
+
107
+ spinner "Updating OAuth2 client-id and client-secret to Kontena Master" do
108
+ Kontena.run("master config set oauth2.client_id=#{response['data']['attributes']['client-id'].shellescape} oauth2.client_secret=#{response['data']['attributes']['client-secret'].shellescape} server.root_url=#{current_master.url.shellescape} server.name=#{current_master.name.shellescape} cloud.provider_is_kontena=true")
109
+ end
110
+ end
111
+
112
+ def execute
113
+ unless cloud_client.authentication_ok?(kontena_account.userinfo_endpoint)
114
+ Kontena.run('cloud login')
115
+ end
116
+
117
+ return register_current if self.current?
118
+
119
+ exit_with_error 'Master name is required' unless self.name
120
+
121
+ response = register(self.name, self.url, self.provider, self.redirect_uri, self.version, self.owner)
122
+ if self.return?
123
+ return response['data']['id']
124
+ elsif self.id?
125
+ puts response['data']['id']
126
+ else
127
+ puts "Registered master.".colorize(:green)
128
+ puts "ID: #{response['data']['id']}"
129
+ puts "Client ID: #{response['data']['attributes']['client-id']}"
130
+ puts "Client Secret: #{response['data']['attributes']['client-secret']}"
51
131
  end
52
132
  end
53
133
  end
@@ -5,18 +5,21 @@ module Kontena::Cli::Cloud::Master
5
5
 
6
6
  callback_matcher 'cloud-master', 'list'
7
7
 
8
+ option '--return', :flag, 'Return the list', hidden: true
9
+
8
10
  requires_current_account_token
9
11
 
10
12
  def execute
11
13
  response = cloud_client.get('user/masters')
12
14
  unless response && response.kind_of?(Hash) && response['data'].kind_of?(Array)
13
- puts "Listing masters failed".colorize(:red)
14
- exit 1
15
+ abort "Listing masters failed".colorize(:red)
15
16
  end
16
17
 
17
18
  if response['data'].empty?
19
+ return [] if self.return?
18
20
  puts "No masters registered"
19
21
  else
22
+ return response['data'] if self.return?
20
23
  puts '%-26.26s %-24s %-12s %s' % ['ID', 'NAME', 'OWNER', 'URL']
21
24
  response['data'].each do |data|
22
25
  attr = data['attributes']
@@ -0,0 +1,69 @@
1
+ module Kontena::Cli::Cloud::Master
2
+ class RemoveCommand < Kontena::Command
3
+
4
+ include Kontena::Cli::Common
5
+
6
+ callback_matcher 'cloud-master', 'delete'
7
+
8
+ requires_current_account_token
9
+
10
+ parameter "[MASTER_ID]", "Master ID"
11
+
12
+ option ['-f', '--force'], :flag, "Don't ask for confirmation"
13
+
14
+ def delete_server(id)
15
+ spinner "Deleting server #{id} from Kontena Cloud" do |spin|
16
+ begin
17
+ cloud_client.delete("user/masters/#{id}")
18
+ rescue
19
+ spin.fail
20
+ end
21
+ end
22
+ end
23
+
24
+ def run_interactive
25
+ response = nil
26
+ spinner "Retrieving a list of registered masters on Kontena Cloud" do
27
+ response = cloud_client.get('user/masters')
28
+ unless response && response.kind_of?(Hash) && response['data'].kind_of?(Array)
29
+ abort 'Listing masters failed'.colorize(:red)
30
+ end
31
+ end
32
+
33
+ if response['data'].empty?
34
+ puts "No registered masters"
35
+ return
36
+ end
37
+
38
+ servers_to_delete = prompt.multi_select("Select registered master(s) to delete:") do |menu|
39
+ response['data'].each do |server|
40
+ menu.choice "#{server['attributes']['name']} (#{server['attributes']['url'] || "?"})", server['id']
41
+ end
42
+ end
43
+
44
+ if servers_to_delete.empty?
45
+ puts "No masters selected"
46
+ else
47
+ puts "About to delete servers from Kontena Cloud:"
48
+ servers_to_delete.each do |id|
49
+ puts " * #{id}"
50
+ end
51
+ confirm unless self.force?
52
+ servers_to_delete.each do |id|
53
+ delete_server(id)
54
+ end
55
+ end
56
+ end
57
+
58
+ def execute
59
+ if self.master_id.nil?
60
+ run_interactive
61
+ else
62
+ confirm unless self.force?
63
+ delete_server(self.master_id)
64
+ end
65
+ exit 0
66
+ end
67
+ end
68
+ end
69
+
@@ -1,6 +1,6 @@
1
1
  require_relative 'master/add_command'
2
2
  require_relative 'master/list_command'
3
- require_relative 'master/delete_command'
3
+ require_relative 'master/remove_command'
4
4
  require_relative 'master/update_command'
5
5
  require_relative 'master/show_command'
6
6
 
@@ -9,8 +9,8 @@ module Kontena::Cli::Cloud
9
9
  include Kontena::Cli::Common
10
10
 
11
11
  subcommand ['list', 'ls'], "List masters in Kontena Cloud", Kontena::Cli::Cloud::Master::ListCommand
12
+ subcommand ['remove', 'rm'], "Remove a master registration from Kontena Cloud", Kontena::Cli::Cloud::Master::RemoveCommand
12
13
  subcommand "add", "Register a master in Kontena Cloud", Kontena::Cli::Cloud::Master::AddCommand
13
- subcommand "delete", "Delete a master in Kontena Cloud", Kontena::Cli::Cloud::Master::DeleteCommand
14
14
  subcommand "show", "Show master settings in Kontena Cloud", Kontena::Cli::Cloud::Master::ShowCommand
15
15
  subcommand "update", "Update master settings in Kontena Cloud", Kontena::Cli::Cloud::Master::UpdateCommand
16
16
 
@@ -151,7 +151,7 @@ module Kontena
151
151
  @kontena_account ||= config.find_account(ENV['KONTENA_ACCOUNT'] || 'kontena')
152
152
  end
153
153
 
154
- def kontena_auth?
154
+ def cloud_auth?
155
155
  return false unless kontena_account
156
156
  return false unless kontena_account.token
157
157
  return false unless kontena_account.token.access_token
@@ -289,33 +289,26 @@ module Kontena
289
289
  return nil unless $stdout.tty?
290
290
  start_time = Time.now.to_i
291
291
  end_time = start_time + timeout
292
- Thread.main['any_key.stop_prompt'] = false
293
292
  Thread.main['any_key.timed_out'] = false
294
293
  msg = "Press any key to continue or ctrl-c to cancel.. (Automatically continuing in ? seconds)"
294
+
295
+ reader_thread = Thread.new do
296
+ Thread.main['any_key.char'] = STDIN.getch
297
+ end
298
+
295
299
  countdown_thread = Thread.new do
296
300
  time_left = timeout
297
- while time_left > 0 && !Thread.main['any_key.stop_prompt']
298
- print "\r#{pastel.bright_cyan("#{msg.sub("?", time_left.to_s)}")} "
301
+ while time_left > 0 && Thread.main['any_key.char'].nil?
302
+ print "\r#{pastel.bright_white("#{msg.sub("?", time_left.to_s)}")} "
299
303
  time_left = end_time - Time.now.to_i
300
304
  sleep 0.1
301
305
  end
302
306
  print "\r#{' ' * msg.length} \r"
303
- Thread.main['any_key.timed_out'] = true
304
- end
305
-
306
- reader_thread = Thread.new do
307
- Thread.main['any_key.char'] = STDIN.getch
308
- Thread.main['any_key.stop_prompt'] = true
307
+ reader_thread.kill if reader_thread.alive?
309
308
  end
310
309
 
311
310
  countdown_thread.join
312
311
 
313
- until Thread.main['any_key.char'] || Thread.main['any_key.timed_out']
314
- sleep 0.1
315
- end
316
-
317
- reader_thread.kill if reader_thread.alive?
318
-
319
312
  if Thread.main['any_key.char'] == "\u0003"
320
313
  error "Canceled"
321
314
  end
@@ -355,7 +348,7 @@ module Kontena
355
348
  def display_master_login_info
356
349
  server = config.current_master
357
350
  if server
358
- if server.token && server.access_token
351
+ if server.token && server.token.access_token
359
352
  puts [
360
353
  pastel.green('Authenticated to Kontena Master'),
361
354
  pastel.yellow(server.name),
@@ -25,6 +25,7 @@ module Kontena
25
25
  class TokenExpiredError < StandardError; end
26
26
 
27
27
  def initialize
28
+ super
28
29
  @logger = Logger.new(STDOUT)
29
30
  @logger.level = ENV["DEBUG"].nil? ? Logger::INFO : Logger::DEBUG
30
31
  @logger.progname = 'CONFIG'
@@ -116,9 +117,9 @@ module Kontena
116
117
  {
117
118
  name: 'kontena',
118
119
  url: 'https://cloud-api.kontena.io',
119
- token_endpoint: 'https://auth2.kontena.io/v1/oauth2/token',
120
- authorization_endpoint: 'https://cloud-beta.kontena.io/login/oauth/authorize',
121
- userinfo_endpoint: 'https://auth2.kontena.io/v1/user',
120
+ token_endpoint: 'https://cloud-api.kontena.io/oauth2/token',
121
+ authorization_endpoint: 'https://cloud.kontena.io/login/oauth/authorize',
122
+ userinfo_endpoint: 'https://cloud-api.kontena.io/user',
122
123
  token_post_content_type: 'application/x-www-form-urlencoded',
123
124
  code_requires_basic_auth: false,
124
125
  token_method: 'post',
@@ -19,13 +19,13 @@ module Kontena::Cli::Grids
19
19
  grid = find_grid_by_name(name_or_current)
20
20
  exit_with_error("Grid not found") unless grid
21
21
 
22
+ grid_uri = self.current_master['url'].sub('http', 'ws')
23
+
24
+
22
25
  prefix = export? ? 'export ' : ''
23
26
 
24
- server = settings['servers'].find{|s| s['name'] == settings['current_server']}
25
- if server
26
- puts "#{prefix}KONTENA_URI=#{server['url'].sub('http', 'ws')}"
27
- puts "#{prefix}KONTENA_TOKEN=#{server['token']}"
28
- end
27
+ puts "#{prefix}KONTENA_URI=#{grid_uri}"
28
+ puts "#{prefix}KONTENA_TOKEN=#{grid['token']}"
29
29
  end
30
30
  end
31
31
  end
@@ -17,7 +17,7 @@ module Kontena
17
17
  attr_accessor :server, :success_response, :error_response, :port
18
18
 
19
19
  DEFAULT_ERROR_MESSAGE = "Bad request"
20
- SUCCESS_URL = "https://cloud-beta.kontena.io/terminal-success"
20
+ SUCCESS_URL = "https://cloud.kontena.io/terminal-success"
21
21
 
22
22
  # Get new server instance
23
23
  #
@@ -0,0 +1,21 @@
1
+ module Kontena::Cli::Master
2
+ class InitCloudCommand < Kontena::Command
3
+
4
+ include Kontena::Cli::Common
5
+
6
+ banner "Configures the current Kontena Master to use Kontena Cloud services and authentication"
7
+
8
+ option '--force', :flag, "Don't ask questions"
9
+ option '--cloud-master-id', '[ID]', "Use existing cloud master ID"
10
+
11
+ requires_current_master
12
+ requires_current_account_token
13
+
14
+ def execute
15
+ args = ["--current"]
16
+ args << "--force" if self.force?
17
+ args << "--cloud-master-id #{self.cloud_master_id}" if self.cloud_master_id
18
+ Kontena.run("cloud master add #{args.map(&:shellescape).join(' ')}")
19
+ end
20
+ end
21
+ end
@@ -17,6 +17,8 @@ module Kontena::Cli::Master
17
17
  option ['-f', '--force'], :flag, 'Force reauthentication'
18
18
  option ['-s', '--silent'], :flag, 'Reduce output verbosity'
19
19
 
20
+ option ['--no-login-info'], :flag, "Don't show login info", hidden: true
21
+
20
22
  def execute
21
23
  # rewrites self.url
22
24
  use_current_master_if_available || use_master_by_name
@@ -28,14 +30,18 @@ module Kontena::Cli::Master
28
30
  set_server_token(server)
29
31
 
30
32
  # set server token by exchanging code if --code given
31
- use_authorization_code(server) if self.code
33
+ use_authorization_code(server, self.code) if self.code
32
34
 
33
35
  client = Kontena::Client.new(server.url, server.token)
34
36
 
35
37
  # Unless an invitation code was supplied, check auth and exit
36
38
  # if it works already.
37
39
  unless self.join || self.force?
38
- exit_if_auth_works(server)
40
+ if auth_works?(server)
41
+ config.write
42
+ display_login_info(only: :master) unless self.no_login_info?
43
+ exit 0
44
+ end
39
45
  end
40
46
 
41
47
  # no local browser? tell user to launch an external one
@@ -50,22 +56,14 @@ module Kontena::Cli::Master
50
56
 
51
57
  # If the master responds with a code, then exchange it to a token
52
58
  if response['code']
53
- vspinner "Exchanging authorization code for an access token from Kontena Master" do
54
- response = client.exchange_code(response['code'])
55
- unless response && response.kind_of?(Hash) && response['access_token']
56
- exit_with_error "Code exchange failed"
57
- end
58
- end
59
- end
60
-
61
- if response['access_token']
59
+ use_authorization_code(server, response['code'])
60
+ elsif response['access_token']
62
61
  update_server_token(server, response)
63
62
  update_server_name(server, response)
64
63
  config.current_server = server.name
65
- config.write
66
- display_login_info(only: :master) unless running_silent?
67
- exit 0
68
64
  end
65
+ config.write
66
+ display_login_info(only: :master) unless (running_silent? || self.no_login_info?)
69
67
  end
70
68
 
71
69
  def master_account
@@ -116,40 +114,41 @@ module Kontena::Cli::Master
116
114
  end
117
115
  end
118
116
 
119
- def use_authorization_code(server)
120
- vspinner "Exchanging authorization code for an access token from Master" do
117
+ def use_authorization_code(server, code)
118
+ vspinner "Exchanging authorization code for an access token from Kontena Master" do
121
119
  client = Kontena::Client.new(server.url, server.token)
122
- response = client.exchange_code(self.code)
120
+ response = client.exchange_code(code) rescue nil
123
121
 
124
122
  if response && response.kind_of?(Hash) && !response.has_key?('error')
125
- server.token.access_token = response['access_token']
126
- server.token.refresh_token = response['refresh_token']
127
- server.token.expires_at = response['expires_in'].to_i > 0 ? Time.now.utc.to_i + response['expires_in'].to_i : nil
128
- server.token.username = response['user']['name'] || response['user']['email']
129
- server.username = server.token.username
130
123
  if response['server'] && response['server']['name']
131
124
  server.name ||= response['server']['name']
125
+ server.username = response['user']['name'] || response['user']['email']
132
126
  config.current_server = server.name
133
127
  end
128
+
129
+ server.token = Kontena::Cli::Config::Token.new(
130
+ access_token: response['access_token'],
131
+ refresh_token: response['refresh_token'],
132
+ expires_at: response['expires_in'].to_i > 0 ? Time.now.utc.to_i + response['expires_in'].to_i : nil,
133
+ )
134
134
  else
135
135
  raise Kontena::Errors::StandardError.new(500, 'Code exchange failed')
136
136
  end
137
137
  end
138
+ true
138
139
  end
139
140
 
140
- def exit_if_auth_works(server)
141
+ def auth_works?(server)
141
142
  if server && server.token && server.token.access_token
142
143
  # See if the existing or supplied authentication works without reauthenticating
143
144
  auth_ok = false
144
145
  vspinner "Testing if authentication works using current access token" do
145
146
  auth_ok = Kontena::Client.new(server.url, server.token).authentication_ok?(master_account.userinfo_endpoint)
146
- end
147
- if auth_ok
148
147
  config.current_master = server.name
149
- config.write
150
- display_login_info(only: :master) unless running_silent?
151
- exit 0
152
148
  end
149
+ auth_ok
150
+ else
151
+ false
153
152
  end
154
153
  end
155
154
 
@@ -225,7 +224,7 @@ module Kontena::Cli::Master
225
224
  any_key_to_continue(10)
226
225
 
227
226
  puts "If the browser does not open, try visiting this URL manually:"
228
- puts "<#{uri.to_s}>"
227
+ puts "#{uri.to_s}"
229
228
  puts
230
229
 
231
230
  server_thread = Thread.new { Thread.main['response'] = web_server.serve_one }