kontena-cli 1.4.0.pre6 → 1.4.0.pre7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (181) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/VERSION +1 -1
  4. data/bin/kontena +1 -1
  5. data/kontena-cli.gemspec +3 -3
  6. data/lib/kontena/cli/certificate/authorize_command.rb +67 -6
  7. data/lib/kontena/cli/certificate/get_command.rb +7 -0
  8. data/lib/kontena/cli/certificate/list_command.rb +75 -0
  9. data/lib/kontena/cli/certificate/register_command.rb +13 -2
  10. data/lib/kontena/cli/certificate/request_command.rb +20 -0
  11. data/lib/kontena/cli/certificate/show_command.rb +19 -0
  12. data/lib/kontena/cli/certificate_command.rb +4 -1
  13. data/lib/kontena/cli/cloud/master/add_command.rb +1 -1
  14. data/lib/kontena/cli/common.rb +21 -33
  15. data/lib/kontena/cli/etcd/health_command.rb +21 -27
  16. data/lib/kontena/cli/helpers/exec_helper.rb +15 -6
  17. data/lib/kontena/cli/helpers/health_helper.rb +12 -0
  18. data/lib/kontena/cli/helpers/log_helper.rb +2 -2
  19. data/lib/kontena/cli/helpers/time_helper.rb +29 -0
  20. data/lib/kontena/cli/master/init_cloud_command.rb +19 -0
  21. data/lib/kontena/cli/master/list_command.rb +1 -1
  22. data/lib/kontena/cli/master/ssh_command.rb +3 -1
  23. data/lib/kontena/cli/master/use_command.rb +1 -2
  24. data/lib/kontena/cli/node_command.rb +1 -0
  25. data/lib/kontena/cli/nodes/health_command.rb +28 -13
  26. data/lib/kontena/cli/nodes/list_command.rb +19 -3
  27. data/lib/kontena/cli/nodes/show_command.rb +4 -2
  28. data/lib/kontena/cli/nodes/ssh_command.rb +5 -2
  29. data/lib/kontena/cli/nodes/update_command.rb +2 -0
  30. data/lib/kontena/cli/plugins/install_command.rb +11 -8
  31. data/lib/kontena/cli/plugins/list_command.rb +5 -3
  32. data/lib/kontena/cli/plugins/search_command.rb +4 -2
  33. data/lib/kontena/cli/plugins/show_command.rb +17 -0
  34. data/lib/kontena/cli/plugins/uninstall_command.rb +9 -13
  35. data/lib/kontena/cli/registry/create_command.rb +1 -1
  36. data/lib/kontena/cli/services/create_command.rb +6 -0
  37. data/lib/kontena/cli/services/services_helper.rb +33 -6
  38. data/lib/kontena/cli/services/update_command.rb +6 -0
  39. data/lib/kontena/cli/stacks/build_command.rb +3 -3
  40. data/lib/kontena/cli/stacks/common.rb +105 -90
  41. data/lib/kontena/cli/stacks/deploy_command.rb +7 -3
  42. data/lib/kontena/cli/stacks/install_command.rb +39 -6
  43. data/lib/kontena/cli/stacks/list_command.rb +36 -4
  44. data/lib/kontena/cli/stacks/logs_command.rb +9 -2
  45. data/lib/kontena/cli/stacks/registry/pull_command.rb +2 -2
  46. data/lib/kontena/cli/stacks/registry/push_command.rb +20 -9
  47. data/lib/kontena/cli/stacks/registry/remove_command.rb +4 -4
  48. data/lib/kontena/cli/stacks/registry/show_command.rb +4 -4
  49. data/lib/kontena/cli/stacks/remove_command.rb +27 -1
  50. data/lib/kontena/cli/stacks/service_generator.rb +12 -2
  51. data/lib/kontena/cli/stacks/show_command.rb +35 -5
  52. data/lib/kontena/cli/stacks/stack_name.rb +71 -0
  53. data/lib/kontena/cli/stacks/upgrade_command.rb +127 -14
  54. data/lib/kontena/cli/stacks/validate_command.rb +38 -10
  55. data/lib/kontena/cli/stacks/yaml/custom_validators/certificates_validator.rb +22 -0
  56. data/lib/kontena/cli/stacks/yaml/opto/prompt_resolver.rb +1 -2
  57. data/lib/kontena/cli/stacks/yaml/reader.rb +211 -185
  58. data/lib/kontena/cli/stacks/yaml/service_extender.rb +6 -12
  59. data/lib/kontena/cli/stacks/yaml/stack_file_loader.rb +97 -0
  60. data/lib/kontena/cli/stacks/yaml/stack_file_loader/file_loader.rb +41 -0
  61. data/lib/kontena/cli/stacks/yaml/stack_file_loader/registry_loader.rb +24 -0
  62. data/lib/kontena/cli/stacks/yaml/stack_file_loader/uri_loader.rb +23 -0
  63. data/lib/kontena/cli/stacks/yaml/validations.rb +16 -0
  64. data/lib/kontena/cli/stacks/yaml/validator_v3.rb +25 -8
  65. data/lib/kontena/client.rb +2 -2
  66. data/lib/kontena/command.rb +11 -0
  67. data/lib/kontena/main_command.rb +3 -1
  68. data/lib/kontena/plugin_manager.rb +11 -198
  69. data/lib/kontena/plugin_manager/cleaner.rb +33 -0
  70. data/lib/kontena/plugin_manager/common.rb +86 -0
  71. data/lib/kontena/plugin_manager/installer.rb +54 -0
  72. data/lib/kontena/plugin_manager/loader.rb +93 -0
  73. data/lib/kontena/plugin_manager/rubygems_client.rb +42 -23
  74. data/lib/kontena/plugin_manager/uninstaller.rb +34 -0
  75. data/lib/kontena/util.rb +24 -0
  76. data/lib/kontena_cli.rb +1 -0
  77. data/omnibus/config/projects/kontena.rb +7 -1
  78. data/omnibus/config/software/{kontena.rb → kontena-cli.rb} +2 -0
  79. data/spec/fixtures/api/node.json +2 -1
  80. data/spec/fixtures/stack-internal-extend.yml +6 -1
  81. data/spec/fixtures/stack-with-dependencies-dep-1-1.yml +8 -0
  82. data/spec/fixtures/stack-with-dependencies-dep-1.yml +17 -0
  83. data/spec/fixtures/stack-with-dependencies-dep-2.yml +8 -0
  84. data/spec/fixtures/stack-with-dependencies-dep-3.yml +5 -0
  85. data/spec/fixtures/stack-with-dependencies-dep_2-removed.yml +17 -0
  86. data/spec/fixtures/stack-with-dependencies-dep_3-added.yml +25 -0
  87. data/spec/fixtures/stack-with-dependencies.yml +22 -0
  88. data/spec/fixtures/stack-with-variables.yml +3 -0
  89. data/spec/kontena/cli/etcd/health_command_spec.rb +45 -33
  90. data/spec/kontena/cli/helpers/exec_helper_spec.rb +2 -1
  91. data/spec/kontena/cli/master/init_cloud_command_spec.rb +14 -0
  92. data/spec/kontena/cli/nodes/health_command_spec.rb +74 -10
  93. data/spec/kontena/cli/nodes/list_command_spec.rb +381 -232
  94. data/spec/kontena/cli/nodes/show_command_spec.rb +31 -0
  95. data/spec/kontena/cli/nodes/ssh_command_spec.rb +18 -3
  96. data/spec/kontena/cli/plugins/install_command_spec.rb +1 -1
  97. data/spec/kontena/cli/stacks/build_command_spec.rb +6 -12
  98. data/spec/kontena/cli/stacks/common_spec.rb +42 -69
  99. data/spec/kontena/cli/stacks/install_command_spec.rb +57 -31
  100. data/spec/kontena/cli/stacks/list_command_spec.rb +44 -0
  101. data/spec/kontena/cli/stacks/logs_command_spec.rb +12 -1
  102. data/spec/kontena/cli/stacks/remove_command_spec.rb +39 -0
  103. data/spec/kontena/cli/stacks/show_command_spec.rb +16 -0
  104. data/spec/kontena/cli/stacks/stack_name_spec.rb +21 -0
  105. data/spec/kontena/cli/stacks/upgrade_command_spec.rb +73 -56
  106. data/spec/kontena/cli/stacks/validate_command_spec.rb +81 -0
  107. data/spec/kontena/cli/stacks/yaml/custom_validators/affinities_validator_spec.rb +22 -0
  108. data/spec/kontena/cli/stacks/yaml/reader_spec.rb +173 -169
  109. data/spec/kontena/cli/stacks/yaml/service_extender_spec.rb +12 -3
  110. data/spec/kontena/cli/stacks/yaml/stack_file_loader/file_loader_spec.rb +47 -0
  111. data/spec/kontena/cli/stacks/yaml/stack_file_loader/registry_loader_spec.rb +53 -0
  112. data/spec/kontena/cli/stacks/yaml/stack_file_loader/uri_loader_spec.rb +53 -0
  113. data/spec/kontena/cli/stacks/yaml/stack_file_loader_spec.rb +104 -0
  114. data/spec/kontena/cli/stacks/yaml/validator_v3_spec.rb +19 -0
  115. data/spec/kontena/plugin_manager/cleaner_spec.rb +20 -0
  116. data/spec/kontena/plugin_manager/common_spec.rb +39 -0
  117. data/spec/kontena/plugin_manager/installer_spec.rb +50 -0
  118. data/spec/kontena/plugin_manager/loader_spec.rb +5 -0
  119. data/spec/kontena/plugin_manager/rubygems_client_spec.rb +11 -25
  120. data/spec/kontena/plugin_manager/uninstaller_spec.rb +19 -0
  121. data/spec/kontena/plugin_manager_spec.rb +7 -7
  122. metadata +64 -97
  123. data/lib/kontena/cli/app_command.rb +0 -22
  124. data/lib/kontena/cli/apps/build_command.rb +0 -28
  125. data/lib/kontena/cli/apps/common.rb +0 -172
  126. data/lib/kontena/cli/apps/config_command.rb +0 -25
  127. data/lib/kontena/cli/apps/deploy_command.rb +0 -137
  128. data/lib/kontena/cli/apps/docker_compose_generator.rb +0 -61
  129. data/lib/kontena/cli/apps/docker_helper.rb +0 -80
  130. data/lib/kontena/cli/apps/dockerfile_generator.rb +0 -16
  131. data/lib/kontena/cli/apps/init_command.rb +0 -89
  132. data/lib/kontena/cli/apps/kontena_yml_generator.rb +0 -105
  133. data/lib/kontena/cli/apps/list_command.rb +0 -59
  134. data/lib/kontena/cli/apps/logs_command.rb +0 -37
  135. data/lib/kontena/cli/apps/monitor_command.rb +0 -93
  136. data/lib/kontena/cli/apps/remove_command.rb +0 -74
  137. data/lib/kontena/cli/apps/restart_command.rb +0 -39
  138. data/lib/kontena/cli/apps/scale_command.rb +0 -33
  139. data/lib/kontena/cli/apps/service_generator.rb +0 -114
  140. data/lib/kontena/cli/apps/service_generator_v2.rb +0 -27
  141. data/lib/kontena/cli/apps/show_command.rb +0 -23
  142. data/lib/kontena/cli/apps/start_command.rb +0 -40
  143. data/lib/kontena/cli/apps/stop_command.rb +0 -40
  144. data/lib/kontena/cli/apps/yaml/custom_validators/affinities_validator.rb +0 -19
  145. data/lib/kontena/cli/apps/yaml/custom_validators/build_validator.rb +0 -22
  146. data/lib/kontena/cli/apps/yaml/custom_validators/extends_validator.rb +0 -20
  147. data/lib/kontena/cli/apps/yaml/custom_validators/hooks_validator.rb +0 -54
  148. data/lib/kontena/cli/apps/yaml/custom_validators/secrets_validator.rb +0 -22
  149. data/lib/kontena/cli/apps/yaml/reader.rb +0 -213
  150. data/lib/kontena/cli/apps/yaml/service_extender.rb +0 -77
  151. data/lib/kontena/cli/apps/yaml/validations.rb +0 -71
  152. data/lib/kontena/cli/apps/yaml/validator.rb +0 -38
  153. data/lib/kontena/cli/apps/yaml/validator_v2.rb +0 -53
  154. data/spec/fixtures/app.json +0 -42
  155. data/spec/fixtures/health.yml +0 -26
  156. data/spec/fixtures/kontena-build.yml +0 -16
  157. data/spec/fixtures/kontena-internal-extend.yml +0 -8
  158. data/spec/fixtures/kontena-invalid.yml +0 -4
  159. data/spec/fixtures/kontena-with-env-file.yml +0 -18
  160. data/spec/fixtures/kontena-with-variables.yml +0 -19
  161. data/spec/fixtures/kontena.yml +0 -17
  162. data/spec/fixtures/kontena_build_v2.yml +0 -26
  163. data/spec/fixtures/kontena_numeric_version.yml +0 -9
  164. data/spec/fixtures/kontena_v2.yml +0 -35
  165. data/spec/fixtures/mysql.yml +0 -3
  166. data/spec/fixtures/wordpress-scaled.yml +0 -3
  167. data/spec/fixtures/wordpress.yml +0 -2
  168. data/spec/kontena/cli/app/build_command_spec.rb +0 -55
  169. data/spec/kontena/cli/app/common_spec.rb +0 -110
  170. data/spec/kontena/cli/app/config_command_spec.rb +0 -78
  171. data/spec/kontena/cli/app/deploy_command_spec.rb +0 -217
  172. data/spec/kontena/cli/app/docker_helper_spec.rb +0 -155
  173. data/spec/kontena/cli/app/init_command_spec.rb +0 -109
  174. data/spec/kontena/cli/app/logs_command_spec.rb +0 -131
  175. data/spec/kontena/cli/app/scale_spec.rb +0 -51
  176. data/spec/kontena/cli/app/service_generator_spec.rb +0 -384
  177. data/spec/kontena/cli/app/service_generator_v2_spec.rb +0 -73
  178. data/spec/kontena/cli/app/yaml/reader_spec.rb +0 -457
  179. data/spec/kontena/cli/app/yaml/service_extender_spec.rb +0 -127
  180. data/spec/kontena/cli/app/yaml/validator_spec.rb +0 -380
  181. data/spec/kontena/cli/app/yaml/validator_v2_spec.rb +0 -301
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 750f17967025517060b46f32a63528d34aa6c578
4
- data.tar.gz: bd34c1c6c26e981984e15ce74cf0a03f9e96425e
3
+ metadata.gz: dd17b046ef3c5df923edb5330692544a30c68f31
4
+ data.tar.gz: 86ab9db88b8bffe961692ad0c7716aacc450e556
5
5
  SHA512:
6
- metadata.gz: 7e3574f15562be1bb53e0fa6c8c0f7db14a7925760174b9d794d411c976cbe08f49aa0f80d0a106de24c8b9495110811b4e611bc4d6ad521009b5a0f71a74fc3
7
- data.tar.gz: 77e86e97a2691c16e210589d3d60ef41dfcd07087f9743b215a03628a65f2b804f9390e815fa2d179d9d74be3596ab8dec732d842d8a49694941996b3280696e
6
+ metadata.gz: 9ce3ee493ee6919a392b71e4218bc301849caf3d8a0f25a4aa831c81aaeab1a6e57e3d88927cee4e0c9a50bac10ec195476eb5d6b88cb934234d6fc1c09119e2
7
+ data.tar.gz: 1a257b2cb1d8f72f4c9d69dd4ca1b5530fd1ecf51dac56a7e3b787b3d579e574ba85e625e7e0350d9512d34875778aa02961e0b45623efc2b4bbc8b57b7f5556
data/Gemfile CHANGED
@@ -8,5 +8,5 @@ group :development, :test do
8
8
  gem "kontena-plugin-hello", path: "./examples/kontena-plugin-hello"
9
9
  gem 'pry', require: false
10
10
  gem 'pry-byebug', require: false
11
- gem 'webmock', require: false
11
+ gem 'webmock', '~> 3.0', require: false
12
12
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.4.0.pre6
1
+ 1.4.0.pre7
@@ -14,6 +14,6 @@ if ARGV[0] == 'complete'
14
14
  else
15
15
  ENV['DEBUG'] ||= "true" if ARGV.any? { |arg| arg == '-D' || arg == '--debug'}
16
16
  require 'kontena_cli'
17
- Kontena::PluginManager.instance.init unless ENV['NO_PLUGINS']
17
+ Kontena::PluginManager.init unless ENV['NO_PLUGINS']
18
18
  Kontena::MainCommand.run
19
19
  end
@@ -23,15 +23,15 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "bundler", "~> 1.7"
24
24
  spec.add_development_dependency "rake", "~> 10.0"
25
25
  spec.add_runtime_dependency "excon", "~> 0.49.0"
26
- spec.add_runtime_dependency "tty-prompt", "0.12.0"
26
+ spec.add_runtime_dependency "tty-prompt", "0.13.1"
27
27
  spec.add_runtime_dependency "clamp", "~> 1.1.0"
28
28
  spec.add_runtime_dependency "ruby_dig", "~> 0.0.2"
29
29
  spec.add_runtime_dependency "launchy", "~> 2.4.3"
30
30
  spec.add_runtime_dependency "hash_validator", "~> 0.7.1"
31
31
  spec.add_runtime_dependency "retriable", "~> 2.1.0"
32
- spec.add_runtime_dependency "opto", "1.8.5"
32
+ spec.add_runtime_dependency "opto", "1.8.7"
33
33
  spec.add_runtime_dependency "semantic", "~> 1.5"
34
34
  spec.add_runtime_dependency "liquid", "~> 4.0.0"
35
35
  spec.add_runtime_dependency "tty-table", "~> 0.8.0"
36
- spec.add_runtime_dependency "kontena-websocket-client", "~> 0.1.0"
36
+ spec.add_runtime_dependency "kontena-websocket-client", "~> 0.1.1"
37
37
  end
@@ -1,22 +1,83 @@
1
+ require_relative '../services/services_helper'
1
2
 
2
3
  module Kontena::Cli::Certificate
3
4
  class AuthorizeCommand < Kontena::Command
4
5
  include Kontena::Cli::Common
5
6
  include Kontena::Cli::GridOptions
7
+ include Kontena::Cli::Services::ServicesHelper
6
8
 
9
+ class DeployFailedError < StandardError; end
7
10
 
8
11
  parameter "DOMAIN", "Domain to authorize"
9
12
 
13
+ option '--type', 'AUTHORIZATION_TYPE', 'Authorization type, either tls-sni-01 or dns-01', default: 'dns-01'
14
+ option '--linked-service', "LINKED_SERVICE", 'A service (usually LB) where the tls-sni-01 challenge certificate is bundled to'
15
+
10
16
  def execute
11
17
  require_api_url
12
18
  token = require_token
13
19
 
14
- data = {domain: domain}
15
- response = client(token).post("certificates/#{current_grid}/authorize", data)
16
- puts "Authorization successfully created. Use the following details to create necessary validations:"
17
- puts "Record name: #{response['record_name']}.#{domain}"
18
- puts "Record type: #{response['record_type']}"
19
- puts "Record content: #{response['record_content']}"
20
+ exit_with_error "Service link needs to be given with tls-sni-01 auth type" if self.type == 'tls-sni-01' && self.linked_service.nil?
21
+
22
+ data = {
23
+ domain: domain,
24
+ authorization_type: self.type
25
+ }
26
+ data['linked_service'] = service_path(self.linked_service) if self.type == 'tls-sni-01'
27
+ retried = false
28
+
29
+ response = nil
30
+ retry_on_le_registration do
31
+ response = client(token).post("grids/#{current_grid}/domain_authorizations", data)
32
+ end
33
+
34
+ case self.type
35
+ when 'dns-01'
36
+ puts "Authorization successfully created. Use the following details to create necessary validations:"
37
+ puts "Record name: #{response.dig('challenge_opts', 'record_name')}.#{domain}"
38
+ puts "Record type: #{response.dig('challenge_opts', 'record_type')}"
39
+ puts "Record content: #{response.dig('challenge_opts', 'record_content')}"
40
+ when 'tls-sni-01'
41
+ state = nil
42
+ spinner "Waiting for tls-sni-01 certificate to be deployed into #{response.dig('linked_service', 'id').colorize(:cyan)} " do
43
+ state = wait_for_domain_auth_deployed(token, response['id'])
44
+ end
45
+ if state == 'deploy_error'
46
+ puts "Linked services deploy failed. Check service events for details"
47
+ else
48
+ puts "TLS-SNI challenge certificate is deployed, you can now request the actual certificate"
49
+ end
50
+ else
51
+ exit_with_error "Unknown authorization type: #{self.type}"
52
+ end
53
+
54
+ end
55
+
56
+ def wait_for_domain_auth_deployed(token, domain_auth_id)
57
+ state = nil
58
+ Timeout.timeout(300) {
59
+ sleep 1 until (state = client(token).get("domain_authorizations/#{domain_auth_id}")['status']) != 'deploying'
60
+ }
61
+ state
62
+ end
63
+
64
+ def service_path(linked_service)
65
+ unless linked_service.include?('/')
66
+ "null/#{linked_service}"
67
+ else
68
+ linked_service
69
+ end
70
+ end
71
+
72
+ def retry_on_le_registration
73
+ yield
74
+ rescue Kontena::Errors::StandardErrorHash => exc
75
+ raise unless exc.errors.has_key?('le_registration')
76
+ # Run through registration
77
+ puts "Let's Encrypt registration missing, creating one."
78
+ email = prompt.ask("Email for Let's Encrypt:")
79
+ Kontena.run!(['certificate', 'register', email])
80
+ yield
20
81
  end
21
82
  end
22
83
  end
@@ -4,6 +4,9 @@ module Kontena::Cli::Certificate
4
4
  include Kontena::Cli::Common
5
5
  include Kontena::Cli::GridOptions
6
6
 
7
+ BANNER = "This command is now deprecated in favor of 'kontena certificate request' command".colorize(:red)
8
+
9
+ banner BANNER
7
10
 
8
11
  option '--secret-name', 'SECRET_NAME', 'The name for the secret to store the certificate in'
9
12
  option '--cert-type', 'CERT_TYPE', 'The type of certificate to get: fullchain, chain or cert', default: 'fullchain'
@@ -11,16 +14,20 @@ module Kontena::Cli::Certificate
11
14
 
12
15
 
13
16
  def execute
17
+ puts BANNER
18
+
14
19
  require_api_url
15
20
  token = require_token
16
21
  secret = secret_name || "LE_CERTIFICATE_#{domain_list[0].gsub('.', '_')}"
17
22
  data = {domains: domain_list, secret_name: secret}
23
+
18
24
  response = client(token).post("certificates/#{current_grid}/certificate", data)
19
25
  puts "Certificate successfully received and stored into vault with keys:"
20
26
  response.each do |secret|
21
27
  puts secret.colorize(:green)
22
28
  end
23
29
  puts "Use the #{secret}_BUNDLE with Kontena loadbalancer!"
30
+
24
31
  end
25
32
  end
26
33
  end
@@ -0,0 +1,75 @@
1
+ require_relative '../services/services_helper'
2
+
3
+ module Kontena::Cli::Certificate
4
+ class ListCommand < Kontena::Command
5
+ include Kontena::Cli::Common
6
+ include Kontena::Cli::GridOptions
7
+ include Kontena::Cli::TableGenerator::Helper
8
+ include Kontena::Util
9
+
10
+ requires_current_master
11
+ requires_current_master_token
12
+ requires_current_grid
13
+
14
+ SEVEN_DAYS = 7 * 24 * 60 * 60
15
+ THREE_DAYS = 3 * 24 * 60 * 60
16
+
17
+ def fields
18
+ quiet? ? ['subject'] : {subject: 'subject', "expiration" => 'expires_in'}
19
+ end
20
+
21
+ def certificates
22
+ client.get("grids/#{current_grid}/certificates")['certificates']
23
+ end
24
+
25
+ def status_icon(expires_in)
26
+ icon = '⊛'.freeze
27
+
28
+ if expires_in < 0
29
+ icon.colorize(:red)
30
+ else
31
+ icon.colorize(:green)
32
+ end
33
+
34
+ end
35
+
36
+ def status_color(expires_in)
37
+
38
+ if expires_in < 0
39
+ :red
40
+ elsif expires_in < THREE_DAYS
41
+ :bright_yellow
42
+ elsif expires_in < SEVEN_DAYS
43
+ :yellow
44
+ else
45
+ :green
46
+ end
47
+
48
+ end
49
+
50
+ def expires_in(certificate)
51
+ valid_until = Time.parse(certificate['valid_until'])
52
+ (valid_until - Time.now).to_i
53
+ end
54
+
55
+ def expires_in_human(expires_in)
56
+ if expires_in > 0
57
+ text = seconds_to_human(expires_in)
58
+ else
59
+ text = seconds_to_human(-1 * expires_in) + ' ago'
60
+ end
61
+
62
+ text.colorize(status_color(expires_in))
63
+ end
64
+
65
+ def execute
66
+ print_table(certificates) do |certificate|
67
+ expires_in = expires_in(certificate)
68
+ certificate['subject'] = status_icon(expires_in) + " " + certificate['subject'] unless quiet?
69
+ next if quiet? # No need to fiddle with colors when they will not get printed
70
+ certificate['expires_in'] = expires_in_human(expires_in)
71
+ end
72
+ end
73
+
74
+ end
75
+ end
@@ -7,13 +7,24 @@ module Kontena::Cli::Certificate
7
7
 
8
8
  parameter "EMAIL", "Email to register"
9
9
 
10
+ option '--agree-tos', :flag, "Automatically agree on Let's Encrypt Terms of Service"
11
+
10
12
  def execute
11
13
  require_api_url
12
14
  token = require_token
13
15
 
14
16
  data = {email: email}
15
- response = client(token).post("certificates/#{current_grid}/register", data)
16
- puts 'Email registered to LetsEncrypt'
17
+
18
+ if self.agree_tos? || ask_continue
19
+ response = client(token).post("certificates/#{current_grid}/register", data)
20
+ puts 'Email registered to LetsEncrypt'
21
+ end
22
+ end
23
+
24
+ def ask_continue
25
+ puts "By registering, you agree on Let's Encrypt Terms of Service: https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf"
26
+ exit_with_error "Registration canceled!" unless prompt.yes?("Continue?")
27
+ true
17
28
  end
18
29
  end
19
30
  end
@@ -0,0 +1,20 @@
1
+
2
+ module Kontena::Cli::Certificate
3
+ class RequestCommand < Kontena::Command
4
+ include Kontena::Cli::Common
5
+ include Kontena::Cli::GridOptions
6
+
7
+ parameter "DOMAIN ...", "Domain(s) to get certificate for"
8
+
9
+ def execute
10
+ require_api_url
11
+ token = require_token
12
+ data = {domains: domain_list}
13
+
14
+ spinner "Requesting certificate for #{domain_list.join(',').colorize(:cyan)} " do
15
+ response = client(token).post("grids/#{current_grid}/certificates", data)
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ require_relative '../services/services_helper'
2
+
3
+ module Kontena::Cli::Certificate
4
+ class ShowCommand < Kontena::Command
5
+ include Kontena::Cli::Common
6
+ include Kontena::Cli::GridOptions
7
+
8
+ parameter "SUBJECT", "Certificate subject"
9
+
10
+ requires_current_master
11
+ requires_current_master_token
12
+ requires_current_grid
13
+
14
+ def execute
15
+ certificate = client.get("certificates/#{current_grid}/#{self.subject}")
16
+ puts YAML.dump(certificate)
17
+ end
18
+ end
19
+ end
@@ -1,11 +1,14 @@
1
1
 
2
2
  class Kontena::Cli::CertificateCommand < Kontena::Command
3
3
 
4
-
4
+ subcommand ["list", "ls"], "List certificates", load_subcommand('certificate/list_command')
5
+ subcommand "show", "Show certificate details", load_subcommand('certificate/show_command')
5
6
  subcommand "register", "Register to LetsEncrypt", load_subcommand('certificate/register_command')
6
7
  subcommand "authorize", "Create DNS authorization for domain", load_subcommand('certificate/authorize_command')
8
+ subcommand "request", "Request certificate for domain", load_subcommand('certificate/request_command')
7
9
  subcommand "get", "Get certificate for domain", load_subcommand('certificate/get_command')
8
10
 
11
+
9
12
  def execute
10
13
  end
11
14
  end
@@ -47,7 +47,7 @@ module Kontena::Cli::Cloud::Master
47
47
  masters = []
48
48
  spinner "Retrieving a list of your registered Kontena Masters in Kontena Cloud" do |spin|
49
49
  begin
50
- masters = Kontena.run!(%w(cloud master list --return))
50
+ masters = Kontena.run!(%w(cloud master list --return --quiet))
51
51
  rescue SystemExit
52
52
  spin.fail
53
53
  end
@@ -117,6 +117,24 @@ module Kontena
117
117
  end
118
118
  end
119
119
 
120
+ # Output a message like: "> Reading foofoo .."
121
+ # @param message [String] the message to display
122
+ # @param dots [TrueClass,FalseClass] set to false if you don't want to add ".." after the message
123
+ def caret(msg, dots: true)
124
+ puts "#{pastel.green('>')} #{msg}#{" #{pastel.green('..')}" if dots}"
125
+ end
126
+
127
+ # Run a spinner with a message for the block if a truthy value or a proc returns true.
128
+ # @example
129
+ # spin_if(proc { prompt.yes?("for real?") }, "Doing as requested") do
130
+ # # doing stuff
131
+ # end
132
+ # spin_if(a == 1, "Value of 'a' is 1, so let's do this") do
133
+ # # doing stuff
134
+ # end
135
+ # @param obj_or_proc [Object,Proc] something that responds to .call or is truthy/falsey
136
+ # @param message [String] the message to display
137
+ # @return anything the block returns
120
138
  def spin_if(obj_or_proc, message, &block)
121
139
  if (obj_or_proc.respond_to?(:call) && obj_or_proc.call) || obj_or_proc
122
140
  spinner(message, &block)
@@ -244,8 +262,8 @@ module Kontena
244
262
  if self.respond_to?(:force?) && self.force?
245
263
  return
246
264
  end
247
- exit_with_error 'Command requires --force' unless $stdout.tty? && $stdin.tty?
248
265
  puts message if message
266
+ exit_with_error 'Command requires --force' unless $stdout.tty? && $stdin.tty?
249
267
  puts "Destructive command. To proceed, type \"#{name}\" or re-run this command with --force option."
250
268
 
251
269
  ask("Enter '#{name}' to confirm: ") == name || error("Confirmation did not match #{name}. Aborted command.")
@@ -276,44 +294,14 @@ module Kontena
276
294
  def any_key_to_continue_with_timeout(timeout=9)
277
295
  return nil if running_silent?
278
296
  return nil unless $stdout.tty?
279
- start_time = Time.now.to_i
280
- end_time = start_time + timeout
281
- Thread.main['any_key.timed_out'] = false
282
- msg = "Press any key to continue or ctrl-c to cancel.. (Automatically continuing in ? seconds)"
283
-
284
- reader_thread = Thread.new do
285
- Thread.main['any_key.char'] = $stdin.getch
286
- end
287
-
288
- countdown_thread = Thread.new do
289
- time_left = timeout
290
- while time_left > 0 && Thread.main['any_key.char'].nil?
291
- print "\r#{pastel.bright_white("#{msg.sub("?", time_left.to_s)}")} "
292
- time_left = end_time - Time.now.to_i
293
- sleep 0.1
294
- end
295
- print "\r#{' ' * msg.length} \r"
296
- reader_thread.kill if reader_thread.alive?
297
- end
298
-
299
- countdown_thread.join
300
-
301
- if Thread.main['any_key.char'] == "\u0003"
302
- error "Canceled"
303
- end
297
+ prompt.keypress("Press any key to continue or ctrl-c to cancel (Automatically continuing in :countdown seconds) ...", timeout: timeout)
304
298
  end
305
299
 
306
300
  def any_key_to_continue(timeout = nil)
307
301
  return nil if running_silent?
308
302
  return nil unless $stdout.tty?
309
303
  return any_key_to_continue_with_timeout(timeout) if timeout
310
- msg = "Press any key to continue or ctrl-c to cancel.. "
311
- print pastel.bright_cyan("#{msg}")
312
- char = $stdin.getch
313
- print "\r#{' ' * msg.length}\r"
314
- if char == "\u0003"
315
- error "Canceled"
316
- end
304
+ prompt.keypress("Press any key to continue or ctrl-c to cancel.. ")
317
305
  end
318
306
 
319
307
  def display_account_login_info
@@ -13,47 +13,41 @@ module Kontena::Cli::Etcd
13
13
  requires_current_grid
14
14
 
15
15
  def execute
16
- require_api_url
17
- token = require_token
18
-
19
- health = true
16
+ ret = true
20
17
 
21
18
  if self.node
22
- node_health = client.get("nodes/#{current_grid}/#{self.node}/health")
23
-
24
- health = show_node_health(node_health)
19
+ ret = show_etcd_health("#{current_grid}/#{self.node}")
25
20
  else
26
21
  nodes = client.get("grids/#{current_grid}/nodes")['nodes']
27
22
 
28
23
  nodes.each do |node|
29
- node_health = client.get("nodes/#{node['id']}/health")
30
-
31
- if !show_node_health(node_health)
32
- health = false
24
+ if !show_etcd_health(node['id'])
25
+ ret = false
33
26
  end
34
27
  end
35
28
  end
36
29
 
37
- return health
30
+ return ret
38
31
  end
39
32
 
33
+ # @param id [String] :grid/:node
40
34
  # @return [Boolean]
41
- def show_node_health(node_health)
42
- etcd_health = node_health['etcd_health']
43
-
44
- if !node_health['connected']
45
- puts "#{health_icon :offline} Node #{node_health['name']} is offline"
46
- return false
47
- elsif etcd_health['health']
48
- puts "#{health_icon :ok} Node #{node_health['name']} is healthy"
49
- return true
50
- elsif etcd_health['error']
51
- puts "#{health_icon :error} Node #{node_health['name']} is unhealthy: #{etcd_health['error']}"
52
- return false
53
- else
54
- puts "#{health_icon :error} Node #{node_health['name']} is unhealthy"
55
- return false
35
+ def show_etcd_health(id)
36
+ node_health = client.get("nodes/#{id}/health")
37
+ etcd_health, status = node_etcd_health(node_health['etcd_health'])
38
+
39
+ puts "#{health_icon etcd_health} Node #{node_health['name']} etcd is #{status}"
40
+
41
+ return etcd_health == :ok
42
+
43
+ rescue Kontena::Errors::StandardErrorHash => exc
44
+ raise unless exc.status == 422
45
+
46
+ exc.errors.each do |what, error|
47
+ puts "#{health_icon :offline} Node #{id} #{what} error: #{error}"
56
48
  end
49
+
50
+ return false
57
51
  end
58
52
  end
59
53
  end