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
@@ -0,0 +1,58 @@
1
+ module Kontena::Cli::Master
2
+ class RemoveCommand < Kontena::Command
3
+ include Kontena::Cli::Common
4
+
5
+ parameter '[NAME]', "Master name"
6
+
7
+ banner "Note: This command only removes the master from your local configuration file"
8
+
9
+ option '--force', :flag, "Don't ask questions"
10
+
11
+ def run_interactive
12
+ selections = prompt.multi_select("Select masters to remove from configuration file:") do |menu|
13
+ config.servers.each do |server|
14
+ menu.choice " #{pastel.green("* ") if config.current_server == server.name}#{server.name} (#{server.username || 'unknown'} @ #{server.url})", server
15
+ end
16
+ end
17
+ if selections.empty?
18
+ puts "No masters selected"
19
+ exit 0
20
+ end
21
+ delete_servers(selections)
22
+ end
23
+
24
+ def delete_servers(servers)
25
+ case servers.size
26
+ when 0
27
+ abort "Master not found in configuration"
28
+ when 1
29
+ config.servers.delete(config.servers.delete(servers.first))
30
+ puts "Removed Master '#{servers.first.name}'"
31
+ else
32
+ unless self.force?
33
+ abort("Aborted") unless prompt.yes?("Remove #{servers.size} masters from configuration?")
34
+ end
35
+ config.servers.delete_if {|s| servers.include?(s) }
36
+ puts "Removed #{servers.size} masters from configuration"
37
+ end
38
+ unless config.find_server(config.current_server)
39
+ puts
40
+ puts "Current master was removed, to select a new current master use:"
41
+ puts " " + pastel.green.on_black(" kontena master use <master_name> ")
42
+ puts "Or log into another master by using:"
43
+ puts " " + pastel.green.on_black(" kontena master login <master_url> ")
44
+ config.current_server = nil
45
+ end
46
+ config.write
47
+ end
48
+
49
+ def execute
50
+ if self.name.nil?
51
+ run_interactive
52
+ else
53
+ delete_servers(config.servers.select {|s| s.name == self.name})
54
+ end
55
+ end
56
+ end
57
+ end
58
+
@@ -12,17 +12,23 @@ module Kontena::Cli::Master::Token
12
12
  option ['-s', '--scopes'], '[SCOPES]', "Comma separated list of access scopes for the generated token", default: 'user'
13
13
  option ['-e', '--expires-in'], '[SECONDS]', "Access token expiration time. Use 0 for never.", default: '7200'
14
14
  option ['-c', '--code'], :flag, "Generate an authorization code"
15
+ option ['-u', '--user'], '[EMAIL]', 'Generate a token for another user'
15
16
  option ['--id'], :flag, "Only output the token ID"
16
17
  option ['--token'], :flag, "Only output the access_token (or authorization code)"
17
18
 
19
+ option ['--return'], :flag, "Return the response hash", hidden: true
20
+
18
21
  def execute
19
22
  params = {
20
23
  response_type: self.code? ? 'code' : 'token',
21
24
  scope: self.scopes,
22
25
  expires_in: self.expires_in
23
26
  }
27
+ params[:user] = self.user if self.user
24
28
  data = token_data_to_hash(client.post("/oauth2/authorize", params))
25
29
 
30
+ return data if self.return?
31
+
26
32
  if self.id?
27
33
  puts data[:id]
28
34
  exit 0
@@ -9,6 +9,7 @@ module Kontena::Cli::Master::Users
9
9
 
10
10
  option ['-r', '--roles'], '[ROLES]', 'Comma separated list of roles to assign to the invited users'
11
11
  option ['-c', '--code'], :flag, 'Only output the invite code'
12
+ option '--return', :flag, 'Return the code', hidden: true
12
13
 
13
14
  requires_current_master
14
15
  requires_current_master_token
@@ -26,6 +27,8 @@ module Kontena::Cli::Master::Users
26
27
  response = client.post('/oauth2/authorize', data)
27
28
  if self.code?
28
29
  puts response['invite_code']
30
+ elsif self.return?
31
+ return response
29
32
  else
30
33
  puts "Invitation created for #{response['email']}".colorize(:green)
31
34
  puts " * code: #{response['invite_code']}"
@@ -35,7 +38,7 @@ module Kontena::Cli::Master::Users
35
38
  Kontena.run("master users role add #{role.shellescape} #{email.shellescape}")
36
39
  end
37
40
  rescue
38
- puts "Failed to invite #{email}".colorize(:red)
41
+ STDERR.puts "Failed to invite #{email}".colorize(:red)
39
42
  ENV["DEBUG"] && puts("#{$!} - #{$!.message} -- #{$!.backtrace}")
40
43
  end
41
44
  end
@@ -8,6 +8,8 @@ module Kontena::Cli::Master::Users
8
8
  parameter "ROLE", "Role name"
9
9
  parameter "USER ...", "List of users"
10
10
 
11
+ option '--silent', :flag, 'Reduce output verbosity'
12
+
11
13
  def execute
12
14
  require_api_url
13
15
  token = require_token
@@ -16,10 +18,9 @@ module Kontena::Cli::Master::Users
16
18
  user_list.each do |email|
17
19
  begin
18
20
  response = client(token).post("users/#{email}/roles", data)
19
- puts "Added role #{role} to #{email}"
21
+ puts "Added role #{role} to #{email}" unless running_silent?
20
22
  rescue => exc
21
- puts "Failed to add role #{role} to #{email}".colorize(:red)
22
- puts exc.message
23
+ abort "Failed to add role #{role} to #{email} : #{exc.message}".colorize(:red)
23
24
  end
24
25
  end
25
26
  end
@@ -1,5 +1,6 @@
1
1
  require_relative '../main_command'
2
2
  require_relative 'master/use_command'
3
+ require_relative 'master/remove_command'
3
4
  require_relative 'master/list_command'
4
5
  require_relative 'master/users_command'
5
6
  require_relative 'master/current_command'
@@ -9,16 +10,13 @@ require_relative 'master/logout_command'
9
10
  require_relative 'master/join_command'
10
11
  require_relative 'master/audit_log_command'
11
12
  require_relative 'master/token_command'
12
-
13
- if ENV["DEV"]
14
- begin
15
- require_relative 'master/create_command'
16
- rescue LoadError
17
- end
18
- end
13
+ require_relative 'master/init_cloud_command'
19
14
 
20
15
  class Kontena::Cli::MasterCommand < Kontena::Command
16
+ include Kontena::Util
17
+
21
18
  subcommand ["list", "ls"], "List masters where client has logged in", Kontena::Cli::Master::ListCommand
19
+ subcommand ["remove", "rm"], "Remove a master from configuration file", Kontena::Cli::Master::RemoveCommand
22
20
  subcommand ["config", "cfg"], "Configure master settings", Kontena::Cli::Master::ConfigCommand
23
21
  subcommand "use", "Switch to use selected master", Kontena::Cli::Master::UseCommand
24
22
  subcommand "users", "Users specific commands", Kontena::Cli::Master::UsersCommand
@@ -28,8 +26,9 @@ class Kontena::Cli::MasterCommand < Kontena::Command
28
26
  subcommand "token", "Manage Kontena Master access tokens", Kontena::Cli::Master::TokenCommand
29
27
  subcommand "join", "Join Kontena Master using an invitation code", Kontena::Cli::Master::JoinCommand
30
28
  subcommand "audit-log", "Show master audit logs", Kontena::Cli::Master::AuditLogCommand
31
-
32
- if ENV["DEV"]
29
+ subcommand "init-cloud", "Configure current master to use Kontena Cloud services", Kontena::Cli::Master::InitCloudCommand
30
+ if experimental?
31
+ require_relative 'master/create_command'
33
32
  subcommand "create", "Install a new Kontena Master", Kontena::Cli::Master::CreateCommand
34
33
  end
35
34
 
@@ -24,13 +24,14 @@ module Kontena::Cli::Services
24
24
  }.join(", ")
25
25
  health = health_status(service)
26
26
  vars = [
27
- "#{health_status_icon(health)} #{service['name']}",
27
+ health_status_icon(health),
28
+ "#{service['name']}",
28
29
  instances,
29
30
  stateful,
30
31
  service['state'],
31
32
  ports
32
33
  ]
33
- puts "%-74s %-10.10s %-8s %-10s %-50s" % vars
34
+ puts "%s %-58s %-10.10s %-8s %-10s %-50s" % vars
34
35
  end
35
36
  end
36
37
  end
@@ -424,7 +424,7 @@ module Kontena
424
424
  icon.colorize(:green)
425
425
  else
426
426
  icon = '⊝'.freeze
427
- icon.colorize(:clear)
427
+ icon.colorize(:dim)
428
428
  end
429
429
  end
430
430
 
@@ -130,22 +130,12 @@ module Kontena
130
130
  return false unless token['access_token']
131
131
  return false unless token_verify_path
132
132
 
133
- uri = URI.parse(token_verify_path)
134
- host_options = {}
135
- host_options[:host] = uri.host if uri.host
136
- host_options[:port] = uri.port if uri.port
137
-
138
- if uri.host
139
- client = Kontena::Client.new("#{uri.scheme}://#{uri.host}:#{uri.port}", token)
140
- else
141
- client = self
142
- end
143
-
144
- final_path = uri.path.gsub(/\:access\_token/, token['access_token'])
145
- logger.debug "Requesting user info from #{final_path} - #{host_options}"
146
- client.request(path: final_path)
133
+ final_path = token_verify_path.gsub(/\:access\_token/, token['access_token'])
134
+ logger.debug "Requesting user info from #{final_path}"
135
+ request(path: final_path)
147
136
  true
148
137
  rescue
138
+ ENV["DEBUG"] && puts("Authentication verification exception: #{$!} #{$!.message} #{$!.backtrace}")
149
139
  false
150
140
  end
151
141
 
@@ -154,35 +144,20 @@ module Kontena
154
144
  def exchange_code(code)
155
145
  return nil unless token_account
156
146
  return nil unless token_account['token_endpoint']
157
- uri = URI.parse(token_account['token_endpoint'])
158
- host_options = {}
159
- host_options[:host] = uri.host if uri.host
160
- host_options[:port] = uri.port if uri.port
161
147
 
162
- if uri.host
163
- client = Kontena::Client.new("#{uri.scheme}://#{uri.host}:#{uri.port}")
164
- else
165
- client = self
166
- end
167
-
168
- client.request(
169
- {
170
- http_method: token_account['token_method'].downcase.to_sym,
171
- path: uri.path,
172
- headers: { CONTENT_TYPE => token_account['token_post_content_type'] },
173
- body: {
174
- 'grant_type' => 'authorization_code',
175
- 'code' => code,
176
- 'client_id' => Kontena::Client::CLIENT_ID,
177
- 'client_secret' => Kontena::Client::CLIENT_SECRET
178
- },
179
- expects: [200,201],
180
- auth: false
181
- }
148
+ request(
149
+ http_method: token_account['token_method'].downcase.to_sym,
150
+ path: token_account['token_endpoint'],
151
+ headers: { CONTENT_TYPE => token_account['token_post_content_type'] },
152
+ body: {
153
+ 'grant_type' => 'authorization_code',
154
+ 'code' => code,
155
+ 'client_id' => Kontena::Client::CLIENT_ID,
156
+ 'client_secret' => Kontena::Client::CLIENT_SECRET
157
+ },
158
+ expects: [200,201],
159
+ auth: false
182
160
  )
183
- rescue
184
- logger.debug "Code exchange exception: #{$!} #{$!.message}\n#{$!.backtrace}"
185
- nil
186
161
  end
187
162
 
188
163
  # Return server version from a Kontena master by requesting '/'
@@ -317,14 +292,23 @@ module Kontena
317
292
  end
318
293
  request_headers.merge!('Content-Length' => body_content.bytesize)
319
294
 
295
+ uri = URI.parse(path)
320
296
  host_options = {}
321
- host_options[:host] = host if host
322
- host_options[:port] = port if port
297
+
298
+ if uri.host
299
+ host_options[:host] = uri.host
300
+ host_options[:port] = uri.port
301
+ host_options[:scheme] = uri.scheme
302
+ path = uri.request_uri
303
+ else
304
+ host_options[:host] = host if host
305
+ host_options[:port] = port if port
306
+ end
323
307
 
324
308
  request_options = {
325
309
  method: http_method,
326
310
  expects: Array(expects),
327
- path: path.start_with?('/') ? path : request_uri(path),
311
+ path: path_with_prefix(path),
328
312
  headers: request_headers,
329
313
  body: body_content,
330
314
  query: query
@@ -443,12 +427,12 @@ module Kontena
443
427
  end
444
428
 
445
429
 
446
- # Get full request uri
430
+ # Get prefixed request path unless path starts with /
447
431
  #
448
432
  # @param [String] path
449
433
  # @return [String]
450
- def request_uri(path)
451
- "#{path_prefix}#{path}"
434
+ def path_with_prefix(path)
435
+ path.to_s.start_with?('/') ? path : "#{path_prefix}#{path}"
452
436
  end
453
437
 
454
438
 
@@ -1,7 +1,7 @@
1
1
  ---
2
- oauth2.authorize_endpoint: https://cloud-beta.kontena.io/login/oauth/authorize
2
+ oauth2.authorize_endpoint: https://cloud.kontena.io/login/oauth/authorize
3
3
  oauth2.code_requires_basic_auth: false
4
- oauth2.token_endpoint: https://auth2.kontena.io/v1/oauth2/token
4
+ oauth2.token_endpoint: https://cloud-api.kontena.io/oauth2/token
5
5
  oauth2.token_method: post
6
6
  oauth2.token_post_content_type: application/x-www-form-urlencoded
7
7
  oauth2.userinfo_endpoint: https://cloud-api.kontena.io/user
data/lib/kontena_cli.rb CHANGED
@@ -15,7 +15,11 @@ module Kontena
15
15
  rescue SystemExit
16
16
  ENV["DEBUG"] && puts("Command completed with failure, result: #{result.inspect} status: #{$!.status}")
17
17
  returning == :status ? $!.status : nil
18
+ rescue
19
+ ENV["DEBUG"] && puts("Command raised #{$!} with message: #{$!.message}\n #{$!.backtrace.join(" \n")}")
20
+ returning == :status ? 1 : nil
18
21
  end
22
+
19
23
 
20
24
  def self.version
21
25
  "kontena-cli/#{Kontena::Cli::VERSION}"
@@ -47,6 +51,14 @@ class String
47
51
  end
48
52
  end
49
53
 
54
+ require 'retriable'
55
+ Retriable.configure do |c|
56
+ c.on_retry = Proc.new do |exception, try, elapsed_time, next_interval|
57
+ return true unless ENV["DEBUG"]
58
+ puts "Retriable retry: #{try} - Exception: #{exception} - #{exception.message}. Elapsed: #{elapsed_time} Next interval: #{next_interval}"
59
+ end
60
+ end
61
+
50
62
  require 'ruby_dig'
51
63
  require 'shellwords'
52
64
  require_relative 'kontena/cli/version'
@@ -46,6 +46,11 @@ describe Kontena::Cli::Apps::DockerHelper do
46
46
  }
47
47
  end
48
48
 
49
+ before :each do
50
+ # image does not exist
51
+ allow(subject).to receive(:image_exist?).with('test_service').and_return(false)
52
+ end
53
+
49
54
  describe '#validate_image_name' do
50
55
  context 'when image name is valid' do
51
56
  it 'returns true' do
@@ -109,7 +114,7 @@ describe Kontena::Cli::Apps::DockerHelper do
109
114
  'build' => { 'context' => '.' },
110
115
  'image' => 'test_service'
111
116
  }
112
- expect(subject).to receive(:system).with("docker build -t test_service ."). and_return(true)
117
+ expect(subject).to receive(:system).with('docker', 'build', '-t', 'test_service', '.'). and_return(true)
113
118
  subject.build_docker_image(service)
114
119
  end
115
120
 
@@ -118,7 +123,7 @@ describe Kontena::Cli::Apps::DockerHelper do
118
123
  'build' => { 'context' => '.' },
119
124
  'image' => 'test_service'
120
125
  }
121
- expect(subject).to receive(:system).with("docker build -t test_service --no-cache ."). and_return(true)
126
+ expect(subject).to receive(:system).with('docker', 'build', '-t', 'test_service', '--no-cache', '.'). and_return(true)
122
127
  subject.build_docker_image(service, true)
123
128
  end
124
129
 
@@ -128,7 +133,7 @@ describe Kontena::Cli::Apps::DockerHelper do
128
133
  'image' => 'test_service'
129
134
  }
130
135
  expected_path = File.join(File.expand_path('.'), 'other_dockerfile')
131
- expect(subject).to receive(:system).with("docker build -t test_service -f #{expected_path} ."). and_return(true)
136
+ expect(subject).to receive(:system).with('docker', 'build', '-t', 'test_service', '-f', expected_path, '.'). and_return(true)
132
137
  subject.build_docker_image(service)
133
138
  end
134
139
 
@@ -143,7 +148,7 @@ describe Kontena::Cli::Apps::DockerHelper do
143
148
  },
144
149
  'image' => 'test_service'
145
150
  }
146
- expect(subject).to receive(:system).with("docker build -t test_service --build-arg FOO=bar --build-arg BAR=foo ."). and_return(true)
151
+ expect(subject).to receive(:system).with('docker', 'build', '-t', 'test_service', '--build-arg=FOO=bar', '--build-arg=BAR=foo', '.'). and_return(true)
147
152
  subject.build_docker_image(service)
148
153
  end
149
154
  end
@@ -2,134 +2,129 @@ require_relative '../../../../spec_helper'
2
2
  require 'kontena/cli/apps/yaml/validator'
3
3
 
4
4
  describe Kontena::Cli::Apps::YAML::Validator do
5
- describe '#validate_keys' do
6
- it 'returns error on invalid key' do
7
- result = subject.validate_keys('name' => 'wordpress')
8
- expect(result['name'].size).to eq(1)
9
- end
10
- end
11
5
 
12
6
  describe '#validate_options' do
13
7
  context 'build' do
14
8
  it 'is optional' do
15
9
  result = subject.validate_options({})
16
- expect(result.success?).to be_truthy
17
- expect(result.messages.key?('build')).to be_falsey
10
+ expect(result.valid?).to be_truthy
11
+
12
+ expect(result.errors.key?('build')).to be_falsey
18
13
  end
19
14
 
20
15
  it 'must be string' do
21
16
  result = subject.validate_options('build' => 12345)
22
- expect(result.messages.key?('build')).to be_truthy
17
+ expect(result.errors.key?('build')).to be_truthy
23
18
 
24
19
  result = subject.validate_options('build' => '.')
25
- expect(result.messages.key?('build')).to be_falsey
20
+ expect(result.errors.key?('build')).to be_falsey
26
21
  end
27
22
  end
28
23
 
29
24
  context 'image' do
30
25
  it 'is optional' do
31
26
  result = subject.validate_options('build' => '.')
32
- expect(result.success?).to be_truthy
33
- expect(result.messages.key?('image')).to be_falsey
27
+ expect(result.valid?).to be_truthy
28
+ expect(result.errors.key?('image')).to be_falsey
34
29
  end
35
30
 
36
31
  it 'must be string' do
37
32
  result = subject.validate_options('image' => 10)
38
- expect(result.success?).to be_falsey
39
- expect(result.messages.key?('image')).to be_truthy
33
+ expect(result.valid?).to be_falsey
34
+ expect(result.errors.key?('image')).to be_truthy
40
35
  end
41
36
  end
42
37
 
43
38
  it 'validates stateful is boolean' do
44
39
  result = subject.validate_options('stateful' => 'bool')
45
- expect(result.messages.key?('stateful')).to be_truthy
40
+ expect(result.errors.key?('stateful')).to be_truthy
46
41
  end
47
42
 
48
43
  it 'validates net is host or bridge' do
49
44
  result = subject.validate_options('net' => 'invalid')
50
- expect(result.messages.key?('net')).to be_truthy
45
+ expect(result.errors.key?('net')).to be_truthy
51
46
 
52
47
  result = subject.validate_options('net' => 'bridge')
53
- expect(result.messages.key?('net')).to be_falsey
48
+ expect(result.errors.key?('net')).to be_falsey
54
49
 
55
50
  result = subject.validate_options('net' => 'host')
56
- expect(result.messages.key?('net')).to be_falsey
51
+ expect(result.errors.key?('net')).to be_falsey
57
52
  end
58
53
 
59
54
  context 'affinity' do
60
55
  it 'is optional' do
61
56
  result = subject.validate_options({})
62
- expect(result.messages.key?('affinity')).to be_falsey
57
+ expect(result.errors.key?('affinity')).to be_falsey
63
58
  end
64
59
 
65
60
  it 'must be array' do
66
61
  result = subject.validate_options('affinity' => 'node==node1')
67
- expect(result.messages.key?('affinity')).to be_truthy
62
+ expect(result.errors.key?('affinity')).to be_truthy
68
63
  result = subject.validate_options('affinity' => ['node==node1'])
69
- expect(result.messages.key?('affinity')).to be_falsey
64
+ expect(result.errors.key?('affinity')).to be_falsey
70
65
  end
71
66
 
72
67
  it 'validates format' do
73
68
  result = subject.validate_options('affinity' => ['node=node1'])
74
- expect(result.messages.key?('affinity')).to be_truthy
69
+ expect(result.errors.key?('affinity')).to be_truthy
75
70
 
76
71
  result = subject.validate_options('affinity' => ['node==node1', 'service!=mariadb'])
77
- expect(result.messages.key?('affinity')).to be_falsey
72
+ expect(result.errors.key?('affinity')).to be_falsey
78
73
  end
79
74
  end
80
75
 
81
76
  context 'deploy' do
82
77
  it 'is optional' do
83
78
  result = subject.validate_options({})
84
- expect(result.messages.key?('deploy')).to be_falsey
79
+ expect(result.errors.key?('deploy')).to be_falsey
85
80
  end
86
81
 
87
82
  context 'strategy' do
88
83
  it 'accepts daemon' do
89
84
  result = subject.validate_options('deploy' => {'strategy' => 'daemon'})
90
- expect(result.messages.key?('deploy')).to be_falsey
85
+ expect(result.errors.key?('deploy')).to be_falsey
91
86
  end
92
87
 
93
88
  it 'accepts random' do
94
89
  result = subject.validate_options('deploy' => {'strategy' => 'random'})
95
- expect(result.messages.key?('deploy')).to be_falsey
90
+ expect(result.errors.key?('deploy')).to be_falsey
96
91
  end
97
92
 
98
93
  it 'accepts ha' do
99
94
  result = subject.validate_options('deploy' => {'strategy' => 'ha'})
100
- expect(result.messages.key?('deploy')).to be_falsey
95
+ expect(result.errors.key?('deploy')).to be_falsey
101
96
  end
102
97
 
103
98
  it 'rejects invalid values' do
104
99
  result = subject.validate_options('deploy' => {'strategy' => 'global'})
105
- expect(result.messages.key?('deploy')).to be_truthy
100
+ expect(result.errors.key?('deploy')).to be_truthy
106
101
  end
107
102
  end
108
103
 
109
104
  context 'interval' do
110
105
  it 'rejects wrong format' do
111
106
  result = subject.validate_options('deploy' => {'interval' => '1xyz'})
112
- expect(result.messages.key?('deploy')).to be_truthy
107
+ expect(result.errors.key?('deploy')).to be_truthy
113
108
  end
114
109
 
115
110
  it 'accepts 1min as value' do
116
111
  result = subject.validate_options('deploy' => {'interval' => '1min'})
117
- expect(result.messages.key?('deploy')).to be_falsey
112
+ expect(result.errors.key?('deploy')).to be_falsey
118
113
  end
119
114
 
120
115
  it 'accepts 1h as value' do
121
116
  result = subject.validate_options('deploy' => {'interval' => '1h'})
122
- expect(result.messages.key?('deploy')).to be_falsey
117
+ expect(result.errors.key?('deploy')).to be_falsey
123
118
  end
124
119
 
125
120
  it 'accepts 1d as value' do
126
121
  result = subject.validate_options('deploy' => {'interval' => '1d'})
127
- expect(result.messages.key?('deploy')).to be_falsey
122
+ expect(result.errors.key?('deploy')).to be_falsey
128
123
  end
129
124
 
130
125
  it 'accepts integer as value' do
131
126
  result = subject.validate_options('deploy' => {'interval' => '100'})
132
- expect(result.messages.key?('deploy')).to be_falsey
127
+ expect(result.errors.key?('deploy')).to be_falsey
133
128
  end
134
129
  end
135
130
  end
@@ -137,59 +132,59 @@ describe Kontena::Cli::Apps::YAML::Validator do
137
132
  context 'command' do
138
133
  it 'is optional' do
139
134
  result = subject.validate_options({})
140
- expect(result.messages.key?('command')).to be_falsey
135
+ expect(result.errors.key?('command')).to be_falsey
141
136
  end
142
137
 
143
138
  it 'must be string or empty' do
144
139
  result = subject.validate_options('command' => 1234)
145
- expect(result.messages.key?('command')).to be_truthy
140
+ expect(result.errors.key?('command')).to be_truthy
146
141
 
147
142
  result = subject.validate_options('command' => nil)
148
- expect(result.messages.key?('command')).to be_falsey
143
+ expect(result.errors.key?('command')).to be_falsey
149
144
 
150
145
  result = subject.validate_options('command' => 'bundle exec rails s')
151
- expect(result.messages.key?('command')).to be_falsey
146
+ expect(result.errors.key?('command')).to be_falsey
152
147
  end
153
148
  end
154
149
 
155
150
  it 'validates cpu_shares is integer' do
156
151
  result = subject.validate_options('cpu_shares' => '1m')
157
- expect(result.messages.key?('cpu_shares')).to be_truthy
152
+ expect(result.errors.key?('cpu_shares')).to be_truthy
158
153
  result = subject.validate_options('cpu_shares' => 1024)
159
- expect(result.messages.key?('cpu_shares')).to be_falsey
154
+ expect(result.errors.key?('cpu_shares')).to be_falsey
160
155
  result = subject.validate_options({})
161
- expect(result.messages.key?('cpu_shares')).to be_falsey
156
+ expect(result.errors.key?('cpu_shares')).to be_falsey
162
157
  end
163
158
 
164
159
  it 'validates environment is array or hash' do
165
160
  result = subject.validate_options('environment' => 'KEY=VALUE')
166
- expect(result.messages.key?('environment')).to be_truthy
161
+ expect(result.errors.key?('environment')).to be_truthy
167
162
  result = subject.validate_options('environment' => ['KEY=VALUE'])
168
- expect(result.messages.key?('environment')).to be_falsey
163
+ expect(result.errors.key?('environment')).to be_falsey
169
164
  result = subject.validate_options('environment' => { 'KEY' => 'VALUE' })
170
- expect(result.messages.key?('environment')).to be_falsey
165
+ expect(result.errors.key?('environment')).to be_falsey
171
166
  end
172
167
 
173
168
  context 'validates secrets' do
174
169
  it 'must be array' do
175
170
  result = subject.validate_options('secrets' => {})
176
- expect(result.messages.key?('secrets')).to be_truthy
171
+ expect(result.errors.key?('secrets')).to be_truthy
177
172
  end
178
173
 
179
174
  context 'item' do
180
175
  it 'must contain secret' do
181
176
  result = subject.validate_options('secrets' => [{ 'name' => 'test', 'type' => 'env' }])
182
- expect(result.messages.key?('secrets')).to be_truthy
177
+ expect(result.errors.key?('secrets')).to be_truthy
183
178
  end
184
179
 
185
180
  it 'must contain name' do
186
181
  result = subject.validate_options('secrets' => [{ 'secret' => 'test', 'type' => 'env' }])
187
- expect(result.messages.key?('secrets')).to be_truthy
182
+ expect(result.errors.key?('secrets')).to be_truthy
188
183
  end
189
184
 
190
185
  it 'must contain type' do
191
186
  result = subject.validate_options('secrets' => [{ 'secret' => 'test', 'name' => 'test' }])
192
- expect(result.messages.key?('secrets')).to be_truthy
187
+ expect(result.errors.key?('secrets')).to be_truthy
193
188
  end
194
189
 
195
190
  it 'accepts valid input' do
@@ -201,7 +196,7 @@ describe Kontena::Cli::Apps::YAML::Validator do
201
196
  'type' => 'env'
202
197
  }
203
198
  ])
204
- expect(result.messages.key?('secrets')).to be_falsey
199
+ expect(result.errors.key?('secrets')).to be_falsey
205
200
  end
206
201
  end
207
202
  end
@@ -209,20 +204,20 @@ describe Kontena::Cli::Apps::YAML::Validator do
209
204
  context 'validates extends' do
210
205
  it 'accepts string value' do
211
206
  result = subject.validate_options('extends' => 'web')
212
- expect(result.messages.key?('extends')).to be_falsey
207
+ expect(result.errors.key?('extends')).to be_falsey
213
208
  end
214
209
 
215
210
  context 'when value is hash' do
216
211
  it 'must contain service' do
217
212
  result = subject.validate_options('extends' => { 'file' => 'docker_compose.yml'})
218
- expect(result.messages.key?('extends')).to be_truthy
213
+ expect(result.errors.key?('extends')).to be_truthy
219
214
  end
220
215
  end
221
216
 
222
217
  context 'when value is not string or hash' do
223
218
  it 'returns error' do
224
219
  result = subject.validate_options('extends' => ['array is invalid'])
225
- expect(result.messages.key?('extends')).to be_truthy
220
+ expect(result.errors.key?('extends')).to be_truthy
226
221
  end
227
222
  end
228
223
  end
@@ -230,7 +225,7 @@ describe Kontena::Cli::Apps::YAML::Validator do
230
225
  context 'validates pre_build' do
231
226
  it 'must be array' do
232
227
  result = subject.validate_options('hooks' => { 'pre_build' => {} })
233
- expect(result.messages.key?('hooks')).to be_truthy
228
+ expect(result.errors.key?('hooks')).to be_truthy
234
229
  data = {
235
230
  'hooks' => {
236
231
  'pre_build' => [
@@ -241,13 +236,13 @@ describe Kontena::Cli::Apps::YAML::Validator do
241
236
  }
242
237
  }
243
238
  result = subject.validate_options(data)
244
- expect(result.messages.key?('hooks')).to be_falsey
239
+ expect(result.errors.key?('hooks')).to be_falsey
245
240
  end
246
241
  end
247
242
  context 'validates post_start' do
248
243
  it 'must be array' do
249
244
  result = subject.validate_options('hooks' => { 'post_start' => {} })
250
- expect(result.messages.key?('hooks')).to be_truthy
245
+ expect(result.errors.key?('hooks')).to be_truthy
251
246
  data = {
252
247
  'hooks' => {
253
248
  'post_start' => [
@@ -260,7 +255,7 @@ describe Kontena::Cli::Apps::YAML::Validator do
260
255
  }
261
256
  }
262
257
  result = subject.validate_options(data)
263
- expect(result.messages.key?('hooks')).to be_falsey
258
+ expect(result.errors.key?('hooks')).to be_falsey
264
259
  end
265
260
 
266
261
  context 'item' do
@@ -274,7 +269,7 @@ describe Kontena::Cli::Apps::YAML::Validator do
274
269
  }
275
270
  ]
276
271
  })
277
- expect(result.messages.key?('hooks')).to be_truthy
272
+ expect(result.errors.key?('hooks.post_start')).to be_truthy
278
273
  end
279
274
 
280
275
  it 'must contain cmd' do
@@ -287,7 +282,7 @@ describe Kontena::Cli::Apps::YAML::Validator do
287
282
  }
288
283
  ]
289
284
  })
290
- expect(result.messages.key?('hooks')).to be_truthy
285
+ expect(result.errors.key?('hooks.post_start')).to be_truthy
291
286
  end
292
287
 
293
288
  it 'must contain instance number or *' do
@@ -299,7 +294,7 @@ describe Kontena::Cli::Apps::YAML::Validator do
299
294
  }
300
295
  ]
301
296
  })
302
- expect(result.messages.key?('hooks')).to be_truthy
297
+ expect(result.errors.key?('hooks.post_start')).to be_truthy
303
298
  data = {
304
299
  'hooks' => {
305
300
  'post_start' => [
@@ -313,7 +308,7 @@ describe Kontena::Cli::Apps::YAML::Validator do
313
308
  }
314
309
  }
315
310
  result = subject.validate_options(data)
316
- expect(result.messages.key?('hooks')).to be_truthy
311
+ expect(result.errors.key?('hooks.post_start')).to be_truthy
317
312
  end
318
313
 
319
314
  it 'may contain boolean oneshot' do
@@ -330,24 +325,24 @@ describe Kontena::Cli::Apps::YAML::Validator do
330
325
  }
331
326
  }
332
327
  result = subject.validate_options(data)
333
- expect(result.messages.key?('hooks')).to be_truthy
328
+ expect(result.errors.key?('hooks.post_start')).to be_truthy
334
329
  end
335
330
  end
336
331
 
337
332
  it 'validates volumes is array' do
338
333
  result = subject.validate_options('volumes' => '/app')
339
- expect(result.messages.key?('volumes')).to be_truthy
334
+ expect(result.errors.key?('volumes')).to be_truthy
340
335
 
341
336
  result = subject.validate_options('volumes' => ['/app'])
342
- expect(result.messages.key?('volumes')).to be_falsey
337
+ expect(result.errors.key?('volumes')).to be_falsey
343
338
  end
344
339
 
345
340
  it 'validates volumes_from is array' do
346
341
  result = subject.validate_options('volumes_from' => 'mysql_data')
347
- expect(result.messages.key?('volumes_from')).to be_truthy
342
+ expect(result.errors.key?('volumes_from')).to be_truthy
348
343
 
349
344
  result = subject.validate_options('volumes_from' => ['mysql_data'])
350
- expect(result.messages.key?('volumes_from')).to be_falsey
345
+ expect(result.errors.key?('volumes_from')).to be_falsey
351
346
  end
352
347
  end
353
348
  end
@@ -355,31 +350,31 @@ describe Kontena::Cli::Apps::YAML::Validator do
355
350
  context 'validates health_check' do
356
351
  it 'validates health_check' do
357
352
  result = subject.validate_options('health_check' => {})
358
- expect(result.messages.key?('health_check')).to be_truthy
353
+ expect(result.errors.key?('health_check')).to be_truthy
359
354
  end
360
355
 
361
356
  it 'validates health_check port ' do
362
357
  result = subject.validate_options('health_check' => { 'protocol' => 'http', 'port' => 'abc'})
363
- expect(result.messages.key?('health_check')).to be_truthy
358
+ expect(result.errors.key?('health_check')).to be_truthy
364
359
 
365
360
  result = subject.validate_options('health_check' => { 'protocol' => 'http', 'port' => 8080})
366
- expect(result.messages.key?('health_check')).to be_falsey
361
+ expect(result.errors.key?('health_check')).to be_falsey
367
362
  end
368
363
 
369
364
  it 'validates health_check uri' do
370
365
  result = subject.validate_options('health_check' => { 'protocol' => 'http', 'port' => 8080, 'uri' => 'foobar'})
371
- expect(result.messages.key?('health_check')).to be_truthy
366
+ expect(result.errors.key?('health_check')).to be_truthy
372
367
 
373
368
  result = subject.validate_options('health_check' => { 'protocol' => 'http', 'port' => 8080, 'uri' => '/health/foo/bar'})
374
- expect(result.messages.key?('health_check')).to be_falsey
369
+ expect(result.errors.key?('health_check')).to be_falsey
375
370
  end
376
371
 
377
372
  it 'validates health_check protocol' do
378
373
  result = subject.validate_options('health_check' => { 'protocol' => 'foo', 'port' => 8080, 'uri' => 'foobar'})
379
- expect(result.messages.key?('health_check')).to be_truthy
374
+ expect(result.errors.key?('health_check')).to be_truthy
380
375
 
381
376
  result = subject.validate_options('health_check' => { 'protocol' => 'tcp', 'port' => 3306 })
382
- expect(result.messages.key?('health_check')).to be_falsey
377
+ expect(result.errors.key?('health_check')).to be_falsey
383
378
  end
384
379
  end
385
380
  end