krates 1.6.0

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 (293) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +212 -0
  3. data/LOGO +10 -0
  4. data/VERSION +1 -0
  5. data/bin/krates +23 -0
  6. data/lib/kontena/autoload_core.rb +19 -0
  7. data/lib/kontena/callback.rb +60 -0
  8. data/lib/kontena/callbacks/.gitkeep +0 -0
  9. data/lib/kontena/callbacks/auth/01_list_and_select_grid_after_master_auth.rb +26 -0
  10. data/lib/kontena/callbacks/master/01_clear_current_master_after_terminate.rb +19 -0
  11. data/lib/kontena/callbacks/master/deploy/01_show_logo_before_deploy.rb +14 -0
  12. data/lib/kontena/callbacks/master/deploy/04_default_master_version.rb +18 -0
  13. data/lib/kontena/callbacks/master/deploy/05_before_deploy_configuration_wizard.rb +105 -0
  14. data/lib/kontena/callbacks/master/deploy/40_install_ssl_certificate_after_deploy.rb +32 -0
  15. data/lib/kontena/callbacks/master/deploy/50_authenticate_after_deploy.rb +66 -0
  16. data/lib/kontena/callbacks/master/deploy/55_create_initial_grid_after_deploy.rb +21 -0
  17. data/lib/kontena/callbacks/master/deploy/56_set_server_provider_after_deploy.rb +24 -0
  18. data/lib/kontena/callbacks/master/deploy/60_configure_auth_provider_after_deploy.rb +31 -0
  19. data/lib/kontena/callbacks/master/deploy/70_invite_self_after_deploy.rb +95 -0
  20. data/lib/kontena/callbacks/master/deploy/90_proptip_after_deploy.rb +33 -0
  21. data/lib/kontena/cli/browser_launcher.rb +61 -0
  22. data/lib/kontena/cli/bytes_helper.rb +40 -0
  23. data/lib/kontena/cli/certificate/authorize_command.rb +107 -0
  24. data/lib/kontena/cli/certificate/common.rb +16 -0
  25. data/lib/kontena/cli/certificate/domain_authorization/list_command.rb +24 -0
  26. data/lib/kontena/cli/certificate/domain_authorization/remove_authorization_command.rb +25 -0
  27. data/lib/kontena/cli/certificate/domain_authorize_command.rb +7 -0
  28. data/lib/kontena/cli/certificate/export_command.rb +28 -0
  29. data/lib/kontena/cli/certificate/get_command.rb +33 -0
  30. data/lib/kontena/cli/certificate/import_command.rb +61 -0
  31. data/lib/kontena/cli/certificate/list_command.rb +75 -0
  32. data/lib/kontena/cli/certificate/register_command.rb +30 -0
  33. data/lib/kontena/cli/certificate/remove_command.rb +23 -0
  34. data/lib/kontena/cli/certificate/request_command.rb +20 -0
  35. data/lib/kontena/cli/certificate/show_command.rb +22 -0
  36. data/lib/kontena/cli/certificate_command.rb +18 -0
  37. data/lib/kontena/cli/cloud/login_command.rb +186 -0
  38. data/lib/kontena/cli/cloud/logout_command.rb +14 -0
  39. data/lib/kontena/cli/cloud/master/add_command.rb +156 -0
  40. data/lib/kontena/cli/cloud/master/list_command.rb +35 -0
  41. data/lib/kontena/cli/cloud/master/remove_command.rb +68 -0
  42. data/lib/kontena/cli/cloud/master/show_command.rb +21 -0
  43. data/lib/kontena/cli/cloud/master/update_command.rb +52 -0
  44. data/lib/kontena/cli/cloud/master_command.rb +14 -0
  45. data/lib/kontena/cli/cloud_command.rb +13 -0
  46. data/lib/kontena/cli/common.rb +360 -0
  47. data/lib/kontena/cli/config.rb +662 -0
  48. data/lib/kontena/cli/container_command.rb +10 -0
  49. data/lib/kontena/cli/containers/exec_command.rb +31 -0
  50. data/lib/kontena/cli/containers/inspect_command.rb +16 -0
  51. data/lib/kontena/cli/containers/list_command.rb +51 -0
  52. data/lib/kontena/cli/containers/logs_command.rb +19 -0
  53. data/lib/kontena/cli/etcd/common.rb +8 -0
  54. data/lib/kontena/cli/etcd/get_command.rb +26 -0
  55. data/lib/kontena/cli/etcd/health_command.rb +53 -0
  56. data/lib/kontena/cli/etcd/list_command.rb +36 -0
  57. data/lib/kontena/cli/etcd/mkdir_command.rb +23 -0
  58. data/lib/kontena/cli/etcd/remove_command.rb +29 -0
  59. data/lib/kontena/cli/etcd/set_command.rb +24 -0
  60. data/lib/kontena/cli/etcd_command.rb +12 -0
  61. data/lib/kontena/cli/external_registries/add_command.rb +25 -0
  62. data/lib/kontena/cli/external_registries/list_command.rb +23 -0
  63. data/lib/kontena/cli/external_registries/remove_command.rb +17 -0
  64. data/lib/kontena/cli/external_registry_command.rb +9 -0
  65. data/lib/kontena/cli/grid_command.rb +21 -0
  66. data/lib/kontena/cli/grid_options.rb +12 -0
  67. data/lib/kontena/cli/grids/audit_log_command.rb +22 -0
  68. data/lib/kontena/cli/grids/cloud_config_command.rb +53 -0
  69. data/lib/kontena/cli/grids/common.rb +182 -0
  70. data/lib/kontena/cli/grids/create_command.rb +48 -0
  71. data/lib/kontena/cli/grids/current_command.rb +25 -0
  72. data/lib/kontena/cli/grids/env_command.rb +32 -0
  73. data/lib/kontena/cli/grids/events_command.rb +50 -0
  74. data/lib/kontena/cli/grids/health_command.rb +69 -0
  75. data/lib/kontena/cli/grids/list_command.rb +59 -0
  76. data/lib/kontena/cli/grids/logs_command.rb +35 -0
  77. data/lib/kontena/cli/grids/remove_command.rb +31 -0
  78. data/lib/kontena/cli/grids/show_command.rb +25 -0
  79. data/lib/kontena/cli/grids/trusted_subnet_command.rb +10 -0
  80. data/lib/kontena/cli/grids/trusted_subnets/add_command.rb +18 -0
  81. data/lib/kontena/cli/grids/trusted_subnets/list_command.rb +18 -0
  82. data/lib/kontena/cli/grids/trusted_subnets/remove_command.rb +26 -0
  83. data/lib/kontena/cli/grids/update_command.rb +35 -0
  84. data/lib/kontena/cli/grids/use_command.rb +26 -0
  85. data/lib/kontena/cli/grids/user_command.rb +9 -0
  86. data/lib/kontena/cli/grids/users/add_command.rb +18 -0
  87. data/lib/kontena/cli/grids/users/list_command.rb +20 -0
  88. data/lib/kontena/cli/grids/users/remove_command.rb +20 -0
  89. data/lib/kontena/cli/helpers/exec_helper.rb +209 -0
  90. data/lib/kontena/cli/helpers/health_helper.rb +65 -0
  91. data/lib/kontena/cli/helpers/log_helper.rb +113 -0
  92. data/lib/kontena/cli/helpers/time_helper.rb +29 -0
  93. data/lib/kontena/cli/localhost_web_server.rb +113 -0
  94. data/lib/kontena/cli/log_formatters/compact.rb +65 -0
  95. data/lib/kontena/cli/log_formatters/strip_color.rb +13 -0
  96. data/lib/kontena/cli/logout_command.rb +10 -0
  97. data/lib/kontena/cli/master/audit_log_command.rb +19 -0
  98. data/lib/kontena/cli/master/config/export_command.rb +46 -0
  99. data/lib/kontena/cli/master/config/get_command.rb +26 -0
  100. data/lib/kontena/cli/master/config/import_command.rb +67 -0
  101. data/lib/kontena/cli/master/config/set_command.rb +19 -0
  102. data/lib/kontena/cli/master/config/unset_command.rb +20 -0
  103. data/lib/kontena/cli/master/config_command.rb +17 -0
  104. data/lib/kontena/cli/master/create_command.rb +74 -0
  105. data/lib/kontena/cli/master/current_command.rb +25 -0
  106. data/lib/kontena/cli/master/init_cloud_command.rb +45 -0
  107. data/lib/kontena/cli/master/join_command.rb +22 -0
  108. data/lib/kontena/cli/master/list_command.rb +24 -0
  109. data/lib/kontena/cli/master/login_command.rb +331 -0
  110. data/lib/kontena/cli/master/logout_command.rb +25 -0
  111. data/lib/kontena/cli/master/remove_command.rb +55 -0
  112. data/lib/kontena/cli/master/ssh_command.rb +72 -0
  113. data/lib/kontena/cli/master/token/common.rb +29 -0
  114. data/lib/kontena/cli/master/token/create_command.rb +50 -0
  115. data/lib/kontena/cli/master/token/current_command.rb +45 -0
  116. data/lib/kontena/cli/master/token/list_command.rb +39 -0
  117. data/lib/kontena/cli/master/token/remove_command.rb +19 -0
  118. data/lib/kontena/cli/master/token/show_command.rb +34 -0
  119. data/lib/kontena/cli/master/token_command.rb +13 -0
  120. data/lib/kontena/cli/master/use_command.rb +31 -0
  121. data/lib/kontena/cli/master/user/invite_command.rb +51 -0
  122. data/lib/kontena/cli/master/user/list_command.rb +29 -0
  123. data/lib/kontena/cli/master/user/remove_command.rb +24 -0
  124. data/lib/kontena/cli/master/user/role/add_command.rb +29 -0
  125. data/lib/kontena/cli/master/user/role/remove_command.rb +27 -0
  126. data/lib/kontena/cli/master/user/role_command.rb +6 -0
  127. data/lib/kontena/cli/master/user_command.rb +9 -0
  128. data/lib/kontena/cli/master_command.rb +21 -0
  129. data/lib/kontena/cli/node_command.rb +17 -0
  130. data/lib/kontena/cli/nodes/create_command.rb +25 -0
  131. data/lib/kontena/cli/nodes/env_command.rb +37 -0
  132. data/lib/kontena/cli/nodes/health_command.rb +47 -0
  133. data/lib/kontena/cli/nodes/label_command.rb +10 -0
  134. data/lib/kontena/cli/nodes/labels/add_command.rb +18 -0
  135. data/lib/kontena/cli/nodes/labels/list_command.rb +19 -0
  136. data/lib/kontena/cli/nodes/labels/remove_command.rb +32 -0
  137. data/lib/kontena/cli/nodes/list_command.rb +97 -0
  138. data/lib/kontena/cli/nodes/remove_command.rb +34 -0
  139. data/lib/kontena/cli/nodes/reset_token_command.rb +34 -0
  140. data/lib/kontena/cli/nodes/show_command.rb +56 -0
  141. data/lib/kontena/cli/nodes/ssh_command.rb +63 -0
  142. data/lib/kontena/cli/nodes/update_command.rb +31 -0
  143. data/lib/kontena/cli/plugin_command.rb +12 -0
  144. data/lib/kontena/cli/plugins/common.rb +8 -0
  145. data/lib/kontena/cli/plugins/install_command.rb +42 -0
  146. data/lib/kontena/cli/plugins/list_command.rb +31 -0
  147. data/lib/kontena/cli/plugins/search_command.rb +25 -0
  148. data/lib/kontena/cli/plugins/show_command.rb +17 -0
  149. data/lib/kontena/cli/plugins/uninstall_command.rb +31 -0
  150. data/lib/kontena/cli/plugins/upgrade_command.rb +60 -0
  151. data/lib/kontena/cli/registry/create_command.rb +151 -0
  152. data/lib/kontena/cli/registry/remove_command.rb +21 -0
  153. data/lib/kontena/cli/registry_command.rb +8 -0
  154. data/lib/kontena/cli/service_command.rb +28 -0
  155. data/lib/kontena/cli/services/container_command.rb +8 -0
  156. data/lib/kontena/cli/services/containers_command.rb +39 -0
  157. data/lib/kontena/cli/services/create_command.rb +105 -0
  158. data/lib/kontena/cli/services/deploy_command.rb +25 -0
  159. data/lib/kontena/cli/services/env_command.rb +9 -0
  160. data/lib/kontena/cli/services/envs/add_command.rb +21 -0
  161. data/lib/kontena/cli/services/envs/list_command.rb +22 -0
  162. data/lib/kontena/cli/services/envs/remove_command.rb +22 -0
  163. data/lib/kontena/cli/services/events_command.rb +36 -0
  164. data/lib/kontena/cli/services/exec_command.rb +107 -0
  165. data/lib/kontena/cli/services/link_command.rb +35 -0
  166. data/lib/kontena/cli/services/list_command.rb +66 -0
  167. data/lib/kontena/cli/services/logs_command.rb +33 -0
  168. data/lib/kontena/cli/services/monitor_command.rb +58 -0
  169. data/lib/kontena/cli/services/remove_command.rb +60 -0
  170. data/lib/kontena/cli/services/restart_command.rb +19 -0
  171. data/lib/kontena/cli/services/scale_command.rb +21 -0
  172. data/lib/kontena/cli/services/secret_command.rb +8 -0
  173. data/lib/kontena/cli/services/secrets/link_command.rb +26 -0
  174. data/lib/kontena/cli/services/secrets/unlink_command.rb +28 -0
  175. data/lib/kontena/cli/services/services_helper.rb +579 -0
  176. data/lib/kontena/cli/services/show_command.rb +26 -0
  177. data/lib/kontena/cli/services/start_command.rb +21 -0
  178. data/lib/kontena/cli/services/stats_command.rb +87 -0
  179. data/lib/kontena/cli/services/stop_command.rb +21 -0
  180. data/lib/kontena/cli/services/unlink_command.rb +30 -0
  181. data/lib/kontena/cli/services/update_command.rb +94 -0
  182. data/lib/kontena/cli/spinner.rb +205 -0
  183. data/lib/kontena/cli/stack_command.rb +21 -0
  184. data/lib/kontena/cli/stacks/build_command.rb +125 -0
  185. data/lib/kontena/cli/stacks/common.rb +209 -0
  186. data/lib/kontena/cli/stacks/deploy_command.rb +37 -0
  187. data/lib/kontena/cli/stacks/events_command.rb +33 -0
  188. data/lib/kontena/cli/stacks/inspect_command.rb +17 -0
  189. data/lib/kontena/cli/stacks/install_command.rb +95 -0
  190. data/lib/kontena/cli/stacks/label_command.rb +10 -0
  191. data/lib/kontena/cli/stacks/labels/add_command.rb +21 -0
  192. data/lib/kontena/cli/stacks/labels/common.rb +19 -0
  193. data/lib/kontena/cli/stacks/labels/list_command.rb +21 -0
  194. data/lib/kontena/cli/stacks/labels/remove_command.rb +21 -0
  195. data/lib/kontena/cli/stacks/list_command.rb +154 -0
  196. data/lib/kontena/cli/stacks/logs_command.rb +35 -0
  197. data/lib/kontena/cli/stacks/monitor_command.rb +93 -0
  198. data/lib/kontena/cli/stacks/registry/create_command.rb +24 -0
  199. data/lib/kontena/cli/stacks/registry/make_private_command.rb +24 -0
  200. data/lib/kontena/cli/stacks/registry/make_public_command.rb +24 -0
  201. data/lib/kontena/cli/stacks/registry/pull_command.rb +28 -0
  202. data/lib/kontena/cli/stacks/registry/push_command.rb +40 -0
  203. data/lib/kontena/cli/stacks/registry/remove_command.rb +30 -0
  204. data/lib/kontena/cli/stacks/registry/search_command.rb +42 -0
  205. data/lib/kontena/cli/stacks/registry/show_command.rb +65 -0
  206. data/lib/kontena/cli/stacks/registry_command.rb +12 -0
  207. data/lib/kontena/cli/stacks/remove_command.rb +80 -0
  208. data/lib/kontena/cli/stacks/restart_command.rb +24 -0
  209. data/lib/kontena/cli/stacks/service_generator.rb +131 -0
  210. data/lib/kontena/cli/stacks/service_generator_v2.rb +27 -0
  211. data/lib/kontena/cli/stacks/show_command.rb +168 -0
  212. data/lib/kontena/cli/stacks/stack_name.rb +71 -0
  213. data/lib/kontena/cli/stacks/stacks_helper.rb +83 -0
  214. data/lib/kontena/cli/stacks/stop_command.rb +24 -0
  215. data/lib/kontena/cli/stacks/upgrade_command.rb +264 -0
  216. data/lib/kontena/cli/stacks/validate_command.rb +75 -0
  217. data/lib/kontena/cli/stacks/yaml/custom_validators/affinities_validator.rb +19 -0
  218. data/lib/kontena/cli/stacks/yaml/custom_validators/build_validator.rb +22 -0
  219. data/lib/kontena/cli/stacks/yaml/custom_validators/certificates_validator.rb +22 -0
  220. data/lib/kontena/cli/stacks/yaml/custom_validators/extends_validator.rb +22 -0
  221. data/lib/kontena/cli/stacks/yaml/custom_validators/hooks_validator.rb +102 -0
  222. data/lib/kontena/cli/stacks/yaml/custom_validators/secrets_validator.rb +22 -0
  223. data/lib/kontena/cli/stacks/yaml/opto/certificates_resolver.rb +37 -0
  224. data/lib/kontena/cli/stacks/yaml/opto/prompt_resolver.rb +78 -0
  225. data/lib/kontena/cli/stacks/yaml/opto/service_instances_resolver.rb +25 -0
  226. data/lib/kontena/cli/stacks/yaml/opto/service_link_resolver.rb +80 -0
  227. data/lib/kontena/cli/stacks/yaml/opto/vault_cert_prompt_resolver.rb +39 -0
  228. data/lib/kontena/cli/stacks/yaml/opto/vault_resolver.rb +13 -0
  229. data/lib/kontena/cli/stacks/yaml/opto/vault_setter.rb +12 -0
  230. data/lib/kontena/cli/stacks/yaml/opto.rb +16 -0
  231. data/lib/kontena/cli/stacks/yaml/reader.rb +525 -0
  232. data/lib/kontena/cli/stacks/yaml/service_extender.rb +65 -0
  233. data/lib/kontena/cli/stacks/yaml/stack_file_loader/file_loader.rb +41 -0
  234. data/lib/kontena/cli/stacks/yaml/stack_file_loader/registry_loader.rb +24 -0
  235. data/lib/kontena/cli/stacks/yaml/stack_file_loader/uri_loader.rb +23 -0
  236. data/lib/kontena/cli/stacks/yaml/stack_file_loader.rb +152 -0
  237. data/lib/kontena/cli/stacks/yaml/validations.rb +119 -0
  238. data/lib/kontena/cli/stacks/yaml/validator_v3.rb +164 -0
  239. data/lib/kontena/cli/subcommand_loader.rb +83 -0
  240. data/lib/kontena/cli/table_generator.rb +128 -0
  241. data/lib/kontena/cli/vault/export_command.rb +24 -0
  242. data/lib/kontena/cli/vault/import_command.rb +75 -0
  243. data/lib/kontena/cli/vault/list_command.rb +37 -0
  244. data/lib/kontena/cli/vault/read_command.rb +27 -0
  245. data/lib/kontena/cli/vault/remove_command.rb +23 -0
  246. data/lib/kontena/cli/vault/update_command.rb +24 -0
  247. data/lib/kontena/cli/vault/write_command.rb +23 -0
  248. data/lib/kontena/cli/vault_command.rb +13 -0
  249. data/lib/kontena/cli/version.rb +10 -0
  250. data/lib/kontena/cli/version_command.rb +20 -0
  251. data/lib/kontena/cli/volume_command.rb +9 -0
  252. data/lib/kontena/cli/volumes/create_command.rb +42 -0
  253. data/lib/kontena/cli/volumes/list_command.rb +29 -0
  254. data/lib/kontena/cli/volumes/remove_command.rb +29 -0
  255. data/lib/kontena/cli/volumes/show_command.rb +38 -0
  256. data/lib/kontena/cli/vpn/config_command.rb +27 -0
  257. data/lib/kontena/cli/vpn/create_command.rb +99 -0
  258. data/lib/kontena/cli/vpn/remove_command.rb +22 -0
  259. data/lib/kontena/cli/vpn_command.rb +9 -0
  260. data/lib/kontena/cli/whoami_command.rb +38 -0
  261. data/lib/kontena/client.rb +574 -0
  262. data/lib/kontena/command.rb +251 -0
  263. data/lib/kontena/debug_instrumentor.rb +80 -0
  264. data/lib/kontena/errors.rb +50 -0
  265. data/lib/kontena/light_prompt.rb +103 -0
  266. data/lib/kontena/machine/cert_helper.rb +43 -0
  267. data/lib/kontena/machine/cloud_config/cloudinit.yml +82 -0
  268. data/lib/kontena/machine/cloud_config/node_generator.rb +28 -0
  269. data/lib/kontena/machine/common.rb +17 -0
  270. data/lib/kontena/machine/random_name.rb +42 -0
  271. data/lib/kontena/main_command.rb +66 -0
  272. data/lib/kontena/plugin_manager/cleaner.rb +33 -0
  273. data/lib/kontena/plugin_manager/common.rb +89 -0
  274. data/lib/kontena/plugin_manager/installer.rb +78 -0
  275. data/lib/kontena/plugin_manager/loader.rb +93 -0
  276. data/lib/kontena/plugin_manager/rubygems_client.rb +59 -0
  277. data/lib/kontena/plugin_manager/uninstaller.rb +34 -0
  278. data/lib/kontena/plugin_manager.rb +26 -0
  279. data/lib/kontena/presets/github_auth_provider.yml +11 -0
  280. data/lib/kontena/presets/kontena_auth_provider.yml +11 -0
  281. data/lib/kontena/scripts/completer +9 -0
  282. data/lib/kontena/scripts/completer.rb +334 -0
  283. data/lib/kontena/scripts/init +18 -0
  284. data/lib/kontena/scripts/kontena.zsh +11 -0
  285. data/lib/kontena/scripts/krates.bash +8 -0
  286. data/lib/kontena/stacks/change_resolver.rb +118 -0
  287. data/lib/kontena/stacks/stack_data.rb +58 -0
  288. data/lib/kontena/stacks/stack_data_set.rb +51 -0
  289. data/lib/kontena/stacks_cache.rb +110 -0
  290. data/lib/kontena/stacks_client.rb +177 -0
  291. data/lib/kontena/util.rb +116 -0
  292. data/lib/kontena_cli.rb +190 -0
  293. metadata +518 -0
@@ -0,0 +1,209 @@
1
+ require_relative 'yaml/reader'
2
+ require_relative '../services/services_helper'
3
+ require_relative 'service_generator_v2'
4
+ require_relative '../../stacks_client'
5
+ require_relative 'yaml/stack_file_loader'
6
+ require 'yaml'
7
+
8
+ module Kontena::Cli::Stacks
9
+ module Common
10
+ include Kontena::Cli::Services::ServicesHelper
11
+
12
+ # @return [StackFileLoader] a loader for the stack origin defined through command-line options
13
+ def loader
14
+ @loader ||= loader_class.for(source)
15
+ end
16
+
17
+ # @return [YAML::Reader] a YAML reader for the target file
18
+ def reader
19
+ @reader ||= loader.reader
20
+ end
21
+
22
+ # Stack name read from -n parameter or the stack file
23
+ # @return [String]
24
+ def stack_name
25
+ @stack_name ||= (self.respond_to?(:name) && self.name) ? self.name : loader.stack_name.stack
26
+ end
27
+
28
+ # An accessor to the YAML Reader outcome. Passes parent name, values from command line and
29
+ # the stackname to the reader.
30
+ #
31
+ # @return [Hash]
32
+ def stack
33
+ @stack ||= reader.execute(
34
+ name: stack_name,
35
+ parent_name: self.respond_to?(:parent_name) ? self.parent_name : nil,
36
+ values: (self.respond_to?(:values_from_options) ? self.values_from_options : {})
37
+ )
38
+ end
39
+
40
+ # @return [Class] an accessor to StackFileLoader constant, for testing purposes
41
+ def loader_class
42
+ ::Kontena::Cli::Stacks::YAML::StackFileLoader
43
+ end
44
+
45
+ module RegistryNameParam
46
+ def stack_name
47
+ @stack_name ||= Kontena::Cli::Stacks::StackName.new(source)
48
+ end
49
+
50
+ def self.included(where)
51
+ where.parameter "STACK_NAME", "Stack name, for example user/stackname or user/stackname:version", attribute_name: :source
52
+ end
53
+ end
54
+
55
+ module StackNameParam
56
+ # Include to add a STACK_NAME parameter
57
+ def self.included(where)
58
+ where.parameter "STACK_NAME", "Stack name, for example user/stackname or user/stackname:version", attribute_name: :source
59
+ end
60
+ end
61
+
62
+ module StackFileOrNameParam
63
+ # Include to add a stack file parameter
64
+ def self.included(where)
65
+ where.parameter "[FILE]", "Kontena stack file, registry stack name (user/stack or user/stack:version) or URL", default: "kontena.yml", attribute_name: :source
66
+ end
67
+ end
68
+
69
+ module StackNameOption
70
+ # Include to add a stack name parameter
71
+ def self.included(where)
72
+ where.option ['-n', '--name'], 'NAME', 'Define stack name (by default comes from stack file)'
73
+ end
74
+ end
75
+
76
+ module StackValuesToOption
77
+ attr_accessor :values
78
+ # Include to add --values-to variable value dumping feature
79
+ def self.included(where)
80
+ where.option '--values-to', '[FILE]', 'Output variable values as YAML to file'
81
+ end
82
+
83
+ # Writes a YAML file from the values received from YAML::Reader to a file defined through
84
+ # the --values-to option
85
+ def dump_variables
86
+ File.write(values_to, ::YAML.dump(reader.variable_values, without_defaults: true, without_vault: true))
87
+ end
88
+ end
89
+
90
+ module StackValuesFromOption
91
+ # Include to add --values-from option to read variable values from a YAML file
92
+ # and the -v variable=value option that can be used to pass variable values
93
+ # directly from command line
94
+ def self.included(where)
95
+ where.prepend InstanceMethods
96
+
97
+ where.option '--values-from', '[FILE]', 'Read variable values from a YAML file', multivalued: true do |filename|
98
+ values_from_file.merge!(::YAML.safe_load(File.read(filename), [], [], true, filename))
99
+ filename
100
+ end
101
+
102
+ where.option '--values-from-stack', '[STACK_NAME]', 'Read variable values from an installed stack', multivalued: true do |stackname|
103
+ variables = read_values_from_stacks(stackname)
104
+ Kontena.logger.debug { "Received variables from stack #{stackname} on Master: #{variables.inspect}" }
105
+ warn "Stack #{stackname} does not have any values for variables" if variables.empty?
106
+ values_from_installed_stacks.merge!(variables)
107
+ stackname
108
+ end
109
+
110
+ where.option '-v', "VARIABLE=VALUE", "Set stack variable values, example: -v domain=example.com. Can be used multiple times.", multivalued: true, attribute_name: :var_option do |var_pair|
111
+ var_name, var_value = var_pair.split('=', 2)
112
+ values_from_value_options.merge!(::YAML.safe_load(::YAML.dump(var_name => var_value)))
113
+ var_pair
114
+ end
115
+ end
116
+
117
+ module InstanceMethods
118
+ def read_values_from_stacks(stackname)
119
+ result = {}
120
+ response = client.get("stacks/#{current_grid}/#{stackname}")
121
+ result.merge!(response['variables']) if response['variables']
122
+ if response['children']
123
+ response['children'].each do |child_info|
124
+ result.merge!(
125
+ read_values_from_stacks(child_info['name']).tap do |child_result|
126
+ child_result.keys.each do |key|
127
+ new_key = child_info['name'].dup # foofoo-redis-monitor
128
+ new_key.sub!("#{stackname}-", '') # monitor
129
+ new_key.concat ".#{key}" # monitor.foovariable
130
+ child_result[new_key] = child_result.delete(key)
131
+ end
132
+ end
133
+ )
134
+ end
135
+ end
136
+ result
137
+ end
138
+
139
+ def values_from_file
140
+ @values_from_file ||= {}
141
+ end
142
+
143
+ def values_from_value_options
144
+ @values_from_value_options ||= {}
145
+ end
146
+
147
+ def values_from_installed_stacks
148
+ @values_from_installed_stacks ||= {}
149
+ end
150
+
151
+ def values_from_options
152
+ @values_from_options ||= values_from_installed_stacks.merge(values_from_file).merge(values_from_value_options)
153
+ end
154
+
155
+ # Transforms a hash
156
+ # dependency_values_from_options('foo.bar' => 1, 'foo')
157
+ # => { 'bar' => 1 }
158
+ # Used for dependency variable injection
159
+ def dependency_values_from_options(name)
160
+ name_with_dot = name.to_s + '.'
161
+ values_from_options.each_with_object({}) do |kv_pair, obj|
162
+ key = kv_pair.first.to_s
163
+ value = kv_pair.last
164
+ next unless key.start_with?(name_with_dot)
165
+ obj[key.sub(name_with_dot, '')] = value
166
+ end
167
+ end
168
+ end
169
+ end
170
+
171
+ # Sets environment variables from parameters
172
+ # @param stack [String] current stack name
173
+ # @param grid [String] current grid name
174
+ # @param platform [String] current platform name, defaults to param grid value
175
+ def set_env_variables(stack, grid, platform = grid)
176
+ ENV['STACK'] = stack
177
+ ENV['GRID'] = grid
178
+ ENV['PLATFORM'] = platform
179
+ end
180
+
181
+ # @return [String]
182
+ def current_dir
183
+ File.basename(Dir.getwd)
184
+ end
185
+
186
+ def display_notifications(messages, color = :yellow)
187
+ $stderr.puts(pastel.send(color, messages.to_yaml.gsub(/^---$/, '')))
188
+ end
189
+
190
+ def hint_on_validation_notifications(notifications, filename = nil)
191
+ return if notifications.nil? || notifications.empty?
192
+ $stderr.puts pastel.yellow("#{"(#{filename}) " if filename}YAML contains the following unsupported options and they were rejected:")
193
+ display_notifications(notifications)
194
+ end
195
+
196
+ def abort_on_validation_errors(errors, filename = nil)
197
+ return if errors.nil? || errors.empty?
198
+ $stderr.puts pastel.red("#{"(#{filename}) " if filename} YAML validation failed! Aborting.")
199
+ display_notifications(errors, :red)
200
+ abort
201
+ end
202
+
203
+ # An accessor to stack registry client
204
+ # @return [Kontena::StacksClient]
205
+ def stacks_client
206
+ @stacks_client ||= Kontena::StacksClient.new(current_account.stacks_url, current_account.token, read_requires_token: current_account.stacks_read_authentication)
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,37 @@
1
+ require_relative 'stacks_helper'
2
+
3
+ module Kontena::Cli::Stacks
4
+ class DeployCommand < Kontena::Command
5
+ include Kontena::Cli::Common
6
+ include Kontena::Cli::GridOptions
7
+ include StacksHelper
8
+
9
+ banner "Deploys all services of a stack"
10
+
11
+ parameter "NAME ...", "Stack name", attribute_name: :names
12
+
13
+ option '--[no-]wait', :flag, 'Wait for deployment to finish', default: true
14
+
15
+ requires_current_master
16
+ requires_current_master_token
17
+
18
+ def execute
19
+ names.each do |name|
20
+ deployment = nil
21
+ spinner "Triggering deployment of stack #{pastel.cyan(name)}" do
22
+ deployment = deploy_stack(name)
23
+ end
24
+ if wait?
25
+ spinner "Waiting for deployment to start" do
26
+ wait_for_deployment_to_start(deployment)
27
+ end
28
+ wait_for_deploy_to_finish(deployment)
29
+ end
30
+ end
31
+ end
32
+
33
+ def deploy_stack(name)
34
+ client.post("stacks/#{current_grid}/#{name}/deploy", {})
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,33 @@
1
+ require_relative '../helpers/log_helper'
2
+
3
+ module Kontena::Cli::Stacks
4
+ class EventsCommand < Kontena::Command
5
+ include Kontena::Cli::Common
6
+ include Kontena::Cli::GridOptions
7
+ include Kontena::Cli::Helpers::LogHelper
8
+
9
+ parameter "NAME", "Service name"
10
+
11
+ def execute
12
+ require_api_url
13
+
14
+ query_params = {}
15
+ titles = ['TIME', 'TYPE', 'MESSAGE']
16
+ puts "%-25s %-25s %s" % titles
17
+ show_logs("stacks/#{current_grid}/#{name}/event_logs", query_params) do |log|
18
+ show_log(log)
19
+ end
20
+ end
21
+
22
+ def show_log(log)
23
+ msg = log['message']
24
+ node = log['relationships'].find { |r| r['type'] == 'node' }
25
+ if node
26
+ msg = "#{msg} (#{node['id'].split('/')[-1]})"
27
+ end
28
+ puts '%-25s %-25s %s' % [
29
+ log['created_at'], log['type'], msg
30
+ ]
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,17 @@
1
+ module Kontena::Cli::Stacks
2
+ class InspectCommand < Kontena::Command
3
+ include Kontena::Cli::Common
4
+ include Kontena::Cli::GridOptions
5
+
6
+ banner "Shows the Stack YAML used to install the stack"
7
+
8
+ parameter "NAME", "Stack name"
9
+
10
+ requires_current_master
11
+ requires_current_master_token
12
+
13
+ def execute
14
+ puts client.get("stacks/#{current_grid}/#{name}")['source']
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,95 @@
1
+ require_relative 'common'
2
+ require_relative 'yaml/stack_file_loader'
3
+
4
+ module Kontena::Cli::Stacks
5
+ class InstallCommand < Kontena::Command
6
+ include Kontena::Cli::Common
7
+ include Kontena::Cli::GridOptions
8
+ include Common
9
+
10
+ banner "Installs a stack to a grid on Kontena Master"
11
+
12
+ include Common::StackFileOrNameParam
13
+
14
+ include Common::StackNameOption
15
+ option '--[no-]deploy', :flag, 'Trigger deploy after installation', default: true
16
+
17
+ include Common::StackValuesToOption
18
+ include Common::StackValuesFromOption
19
+
20
+ option '--parent-name', '[PARENT_NAME]', "Set parent stack name", hidden: true
21
+ option '--skip-dependencies', :flag, "Do not install any stack dependencies"
22
+
23
+ option "--force", :flag, "Force install", default: false, attribute_name: :forced
24
+
25
+ requires_current_master
26
+ requires_current_master_token
27
+
28
+ def execute
29
+ install_dependencies unless skip_dependencies?
30
+
31
+ set_env_variables(stack_name, current_grid)
32
+
33
+ stack # runs validations
34
+
35
+ kontena_requirement = stack.dig('metadata', 'required_kontena_version')
36
+ unless kontena_requirement.nil?
37
+ master_version = Gem::Version.new(client.server_version)
38
+ unless Gem::Requirement.new(kontena_requirement).satisfied_by?(master_version)
39
+ puts "#{pastel.red("Warning: ")} Stack requires kontena version #{kontena_requirement} but Master version is #{master_version}"
40
+ confirm("Are you sure? You can skip this prompt by running this command with --force option") unless forced?
41
+ end
42
+ end
43
+
44
+ hint_on_validation_notifications(reader.notifications)
45
+ abort_on_validation_errors(reader.errors)
46
+
47
+ dump_variables if values_to
48
+
49
+ create_stack
50
+
51
+ if deploy?
52
+ deploy_dependencies
53
+ deploy_stack
54
+ end
55
+ end
56
+
57
+ def install_dependencies
58
+ dependencies = loader.dependencies
59
+ return if dependencies.nil?
60
+
61
+ dependencies.each do |dependency|
62
+ target_name = "#{stack_name}-#{dependency['name']}"
63
+ caret "Installing dependency #{pastel.cyan(dependency['stack'])} as #{pastel.cyan(target_name)}"
64
+ cmd = ['stack', 'install', '-n', target_name, '--parent-name', stack_name, '--no-deploy']
65
+
66
+ dependency['variables'].merge(dependency_values_from_options(dependency['name'])).each do |key, value|
67
+ cmd.concat ['-v', "#{key}=#{value}"]
68
+ end
69
+
70
+ cmd << dependency['stack']
71
+ Kontena.run!(cmd)
72
+ end
73
+ end
74
+
75
+ def deploy_dependencies
76
+ dependencies = loader.dependencies
77
+ return if dependencies.nil?
78
+
79
+ dependencies.each do |dependency|
80
+ target_name = "#{stack_name}-#{dependency['name']}"
81
+ Kontena.run!(['stack', 'deploy', target_name])
82
+ end
83
+ end
84
+
85
+ def create_stack
86
+ spinner "Creating stack #{pastel.cyan(stack['name'])} " do
87
+ client.post("grids/#{current_grid}/stacks", stack)
88
+ end
89
+ end
90
+
91
+ def deploy_stack
92
+ Kontena.run!(['stack', 'deploy', stack['name']])
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,10 @@
1
+ module Kontena::Cli::Stacks
2
+ class LabelCommand < Kontena::Command
3
+ subcommand "add", "Add label to stack", load_subcommand('stacks/labels/add_command')
4
+ subcommand ["remove", "rm"], "Remove label from stack", load_subcommand('stacks/labels/remove_command')
5
+ subcommand ["list", "ls"], "List stack labels", load_subcommand('stacks/labels/list_command')
6
+
7
+ def execute
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,21 @@
1
+ require_relative '../common'
2
+ require_relative 'common'
3
+
4
+ module Kontena::Cli::Stacks::Labels
5
+ class AddCommand < Kontena::Command
6
+ include Kontena::Cli::Common
7
+ include Kontena::Cli::GridOptions
8
+ include Common
9
+
10
+ parameter "NAME", "Stack name"
11
+ parameter "LABEL ...", "Labels"
12
+
13
+ requires_current_master
14
+ requires_current_master_token
15
+
16
+ def execute
17
+ original_labels = fetch_master_data(name)
18
+ update_stack(name, { 'labels' => original_labels | label_list })
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ module Kontena::Cli::Stacks::Labels
2
+ module Common
3
+ private
4
+
5
+ def update_stack(name, data)
6
+ client.patch(stack_url(name), data)
7
+ end
8
+
9
+ def stack_url(name)
10
+ "stacks/#{current_grid}/#{name}"
11
+ end
12
+
13
+ def fetch_master_data(stackname)
14
+ original_data = client.get(stack_url(stackname))
15
+ # ensure we always return either labels or an empty array
16
+ original_data['labels'] || []
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ require_relative '../common'
2
+ require_relative 'common'
3
+
4
+ module Kontena::Cli::Stacks::Labels
5
+ class ListCommand < Kontena::Command
6
+ include Kontena::Cli::Common
7
+ include Kontena::Cli::GridOptions
8
+ include Common
9
+
10
+ parameter "NAME", "Stack name"
11
+
12
+ requires_current_master
13
+ requires_current_master_token
14
+
15
+ def execute
16
+ stack = client.get(stack_url(name))
17
+ # safeguard from nil, since 'labels' field is optional
18
+ puts Array(stack['labels'] || []).join("\n")
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ require_relative '../common'
2
+ require_relative 'common'
3
+
4
+ module Kontena::Cli::Stacks::Labels
5
+ class RemoveCommand < Kontena::Command
6
+ include Kontena::Cli::Common
7
+ include Kontena::Cli::GridOptions
8
+ include Common
9
+
10
+ parameter "NAME", "Stack name"
11
+ parameter "LABEL ...", "Labels"
12
+
13
+ requires_current_master
14
+ requires_current_master_token
15
+
16
+ def execute
17
+ original_labels = fetch_master_data(name)
18
+ update_stack(name, { 'labels' => (original_labels - label_list) })
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,154 @@
1
+ require_relative 'common'
2
+
3
+ module Kontena::Cli::Stacks
4
+ class ListCommand < Kontena::Command
5
+ include Kontena::Cli::Common
6
+ include Kontena::Cli::GridOptions
7
+ include Kontena::Cli::TableGenerator::Helper
8
+ include Common
9
+
10
+ banner "Lists all installed stacks on a grid in Kontena Master"
11
+
12
+ requires_current_master
13
+ requires_current_master_token
14
+
15
+ HEALTH_ICONS = {
16
+ unhealthy: Kontena.pastel.red('⊗').freeze,
17
+ partial: Kontena.pastel.yellow('⊙').freeze,
18
+ healthy: Kontena.pastel.green('⊛').freeze,
19
+ default: Kontena.pastel.dim('⊝').freeze
20
+ }
21
+
22
+ def stacks_by_names(stacks, name_list)
23
+ name_list.map { |name| stacks.find { |stack| stack['name'] == name } }.compact
24
+ end
25
+
26
+ def build_depths(stacks)
27
+ stacks.sort_by { |s| s['name'] }.each do |stack|
28
+ stack['depth'] += 1
29
+ stacks_by_names(stacks, stack['children'].map { |n| n['name'] }).each do |child_stack|
30
+ child_stack['depth'] += stack['depth']
31
+ end
32
+ end
33
+ stacks
34
+ end
35
+
36
+ def get_stacks
37
+ client.get("grids/#{current_grid}/stacks")['stacks'].tap { |stacks| stacks.map { |stack| stack['depth'] = 0 } }
38
+ end
39
+
40
+ # Defines a set of columns for the command.
41
+ def fields
42
+ return ['name'] if quiet?
43
+ {
44
+ name: 'name',
45
+ stack: 'stack',
46
+ services: 'services_count',
47
+ state: 'state',
48
+ 'exposed ports' => 'ports',
49
+ labels: 'labels'
50
+ }
51
+ end
52
+
53
+ def execute
54
+ stacks = build_depths(get_stacks)
55
+
56
+ print_table(stacks) do |row|
57
+ next if quiet?
58
+ row['name'] = health_icon(stack_health(row)) + " " + tree_icon(row) + " " + row['name']
59
+ row['stack'] = "#{row['stack']}:#{row['version']}"
60
+ row['services_count'] = row['services'].size
61
+ row['ports'] = stack_ports(row).join(',')
62
+ row['state'] = pastel.send(state_color(row['state']), row['state'])
63
+ row['labels'] = stack_labels(row)
64
+ end
65
+ end
66
+
67
+ def state_color(state)
68
+ case state
69
+ when 'running' then :green
70
+ when 'deploying', 'initialized' then :blue
71
+ when 'stopped' then :red
72
+ when 'partially_running' then :yellow
73
+ else :clear
74
+ end
75
+ end
76
+
77
+ def health_icon(health)
78
+ HEALTH_ICONS.fetch(health) { HEALTH_ICONS[:default] }
79
+ end
80
+
81
+ def tree_icon(row)
82
+ return '' unless $stdout.tty?
83
+ parent = row['parent']
84
+ children = row['children'] || []
85
+ if parent.nil? && children.empty?
86
+ # solo
87
+ char = ''
88
+ elsif parent.nil? && !children.empty?
89
+ char = ''
90
+ elsif !parent.nil?
91
+ char = '┗━'
92
+ end
93
+ left_pad = ' ' * (2 * (row['depth'] - 1))
94
+ left_pad + char
95
+ end
96
+
97
+ # Converts an array of stack labels into a comma-separated string
98
+ # or '-' when labels field is not defined.
99
+ #
100
+ # @param [Hash] stack
101
+ # @return [<String>]
102
+ def stack_labels(stack)
103
+ labels = (stack['labels'] || ['-']).join(',')
104
+ # trim labels to fit viewport when exceed 43 chars
105
+ labels.length > 43 && $stdout.isatty ? "#{labels[0..40]}..." : labels
106
+ end
107
+
108
+ # @param [Hash] stack
109
+ # @return [Array<String>]
110
+ def stack_ports(stack)
111
+ ports = []
112
+ stack['services'].each{|s|
113
+ service_ports = s['ports'].map{|p|
114
+ p['ip'] = '*' if p['ip'] == '0.0.0.0'
115
+ "#{p['ip']}:#{p['node_port']}->#{p['container_port']}/#{p['protocol']}"
116
+ }
117
+ ports = ports + service_ports unless service_ports.empty?
118
+ }
119
+ ports
120
+ end
121
+
122
+ # @param [Hash] stack
123
+ # @return [Symbol]
124
+ def stack_health(stack)
125
+ services_count = stack['services'].size
126
+ return :unknown if services_count == 0
127
+
128
+ fully_healthy_count = 0
129
+ partial_healthy_count = 0
130
+ unhealthy_count = 0
131
+ unknown_count = 0
132
+ stack['services'].each { |s|
133
+ total = s.dig('health_status', 'total').to_i
134
+ healthy = s.dig('health_status', 'healthy').to_i
135
+ if total > 0 && healthy == total
136
+ fully_healthy_count += 1
137
+ elsif healthy < total && healthy > 0
138
+ partial_healthy_count += 1
139
+ elsif healthy == 0 && total > 0
140
+ unhealthy_count += 1
141
+ else
142
+ unknown_count += 1
143
+ end
144
+ }
145
+ return :partial if partial_healthy_count > 0
146
+ return :partial if unhealthy_count > 0 && fully_healthy_count > 0
147
+ return :unhealthy if unhealthy_count == services_count
148
+ return :healthy if fully_healthy_count == services_count
149
+ return :healthy if fully_healthy_count > 0 && unknown_count > 0
150
+
151
+ :unknown
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,35 @@
1
+ require_relative '../helpers/log_helper'
2
+
3
+ module Kontena::Cli::Stacks
4
+ class LogsCommand < Kontena::Command
5
+ include Kontena::Cli::Common
6
+ include Kontena::Cli::GridOptions
7
+ include Kontena::Cli::Helpers::LogHelper
8
+
9
+ banner "Shows logs from services in a stack"
10
+
11
+ parameter "NAME", "Stack name"
12
+ parameter "[SERVICE] ...", "Service names"
13
+
14
+ requires_current_master
15
+ requires_current_master_token
16
+
17
+ def execute
18
+ if service_list.empty?
19
+ show_logs("stacks/#{current_grid}/#{name}/container_logs") do |log|
20
+ show_log(log)
21
+ end
22
+ else
23
+ show_logs("grids/#{current_grid}/container_logs", services: service_list.map {|s| [name, s].join('/')}.join(',')) do |log|
24
+ show_log(log)
25
+ end
26
+ end
27
+ end
28
+
29
+ def show_log(log)
30
+ color = color_for_container(log['name'])
31
+ prefix = pastel.send(color, "#{log['created_at']} [#{log['name']}]:")
32
+ puts "#{prefix} #{log['data']}"
33
+ end
34
+ end
35
+ end