kontena-cli 0.16.0.pre7 → 0.16.0.pre8

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 (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 }