kontena-cli 1.4.0.pre6 → 1.4.0.pre7

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