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,26 @@
1
+ require_relative '../services_helper'
2
+
3
+ module Kontena::Cli::Services::Secrets
4
+ class LinkCommand < Kontena::Command
5
+ include Kontena::Cli::Common
6
+ include Kontena::Cli::GridOptions
7
+ include Kontena::Cli::Services::ServicesHelper
8
+
9
+ parameter "NAME", "Service name"
10
+ parameter "SECRET", "Secret to be added from Vault (format: secret:name:type)"
11
+
12
+ def execute
13
+ require_api_url
14
+ token = require_token
15
+ spinner "Linking #{pastel.cyan(secret)} from Vault to #{pastel.cyan(name)} " do
16
+ result = client(token).get("services/#{parse_service_id(name)}")
17
+ secrets = result['secrets']
18
+ secrets << parse_secrets([secret])[0]
19
+ data = {
20
+ secrets: secrets
21
+ }
22
+ client(token).put("services/#{parse_service_id(name)}", data)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,28 @@
1
+ require_relative '../services_helper'
2
+
3
+ module Kontena::Cli::Services::Secrets
4
+ class UnlinkCommand < Kontena::Command
5
+ include Kontena::Cli::Common
6
+ include Kontena::Cli::GridOptions
7
+ include Kontena::Cli::Services::ServicesHelper
8
+
9
+ parameter "NAME", "Service name"
10
+ parameter "SECRET", "Secret to be removed (format: secret:name:type)"
11
+
12
+ def execute
13
+ require_api_url
14
+ token = require_token
15
+ result = client(token).get("services/#{parse_service_id(name)}")
16
+ secrets = result['secrets']
17
+ remove_secret = parse_secrets([secret])[0]
18
+ if secrets.delete_if{|s| s['name'] == remove_secret[:name] && s['secret'] == remove_secret[:secret]}
19
+ data = {
20
+ secrets: secrets
21
+ }
22
+ client(token).put("services/#{parse_service_id(name)}", data)
23
+ else
24
+ exit_with_error("Secret not found")
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,579 @@
1
+ require 'kontena/client'
2
+ require_relative '../common'
3
+
4
+ module Kontena
5
+ module Cli
6
+ module Services
7
+ module ServicesHelper
8
+ include Kontena::Cli::Common
9
+
10
+ # @param [String] token
11
+ # @param [String] grid_id
12
+ # @param [Hash] data
13
+ def create_service(token, grid_id, data)
14
+ client(token).post("grids/#{grid_id}/services", data)
15
+ end
16
+
17
+ # @param [String] token
18
+ # @param [String] service_id
19
+ # @param [Hash] data
20
+ def update_service(token, service_id, data)
21
+ param = parse_service_id(service_id)
22
+ client(token).put("services/#{param}", data)
23
+ end
24
+
25
+ # @param [String] token
26
+ # @param [String] service_id
27
+ # @param [Integer] instances
28
+ def scale_service(token, service_id, instances)
29
+ param = parse_service_id(service_id)
30
+ client(token).post("services/#{param}/scale", {instances: instances})
31
+ end
32
+
33
+ # @param [String] token
34
+ # @param [String] service_id
35
+ def get_service(token, service_id)
36
+ param = parse_service_id(service_id)
37
+ client(token).get("services/#{param}")
38
+ end
39
+
40
+ # @param [String] token
41
+ # @param [String] service_id
42
+ def show_service(token, service_id)
43
+ service = get_service(token, service_id)
44
+ puts "#{service['id']}:"
45
+ puts " created: #{service['created_at']}"
46
+ puts " updated: #{service['updated_at']}"
47
+ puts " stack: #{service['stack']['id'] }"
48
+ puts " desired_state: #{service['state'] }"
49
+ puts " image: #{service['image']}"
50
+ puts " revision: #{service['revision']}"
51
+ puts " stack_revision: #{service['stack_revision']}" if service['stack_revision']
52
+ puts " stateful: #{service['stateful'] == true ? 'yes' : 'no' }"
53
+ puts " scaling: #{service['instances'] }"
54
+ puts " strategy: #{service['strategy']}"
55
+ puts " read_only: #{service['read_only'] == true ? 'yes' : 'no'}"
56
+ unless service['stop_signal'].to_s.empty?
57
+ puts " stop_signal: #{service['stop_signal']}"
58
+ end
59
+ puts " stop_grace_period: #{service['stop_grace_period']}s"
60
+ puts " deploy_opts:"
61
+ if service['deploy_opts']['min_health']
62
+ puts " min_health: #{service['deploy_opts']['min_health']}"
63
+ end
64
+ if service['deploy_opts']['wait_for_port']
65
+ puts " wait_for_port: #{service['deploy_opts']['wait_for_port']}"
66
+ end
67
+ if service['deploy_opts']['interval']
68
+ puts " interval: #{service['deploy_opts']['interval']}"
69
+ end
70
+ puts " dns: #{service['dns']}"
71
+
72
+ if service['affinity'].to_a.size > 0
73
+ puts " affinity: "
74
+ service['affinity'].to_a.each do |a|
75
+ puts " - #{a}"
76
+ end
77
+ end
78
+
79
+ unless service['cmd'].to_s.empty?
80
+ if service['cmd']
81
+ puts " cmd: #{service['cmd'].join(' ')}"
82
+ else
83
+ puts " cmd: "
84
+ end
85
+ end
86
+
87
+ if service['hooks'].to_a.size > 0
88
+ puts " hooks: "
89
+ service['hooks'].to_a.each do |hook|
90
+ puts " - name: #{hook['name']}"
91
+ puts " type: #{hook['type']}"
92
+ puts " cmd: #{hook['cmd']}"
93
+ puts " oneshot: #{hook['oneshot']}"
94
+ end
95
+ end
96
+
97
+ if service['secrets'].to_a.size > 0
98
+ puts " secrets: "
99
+ service['secrets'].to_a.each do |s|
100
+ puts " - secret: #{s['secret']}"
101
+ puts " name: #{s['name']}"
102
+ puts " type: #{s['type']}"
103
+ end
104
+ end
105
+
106
+ if service['certificates'].to_a.size > 0
107
+ puts " certificates: "
108
+ service['certificates'].to_a.each do |c|
109
+ puts " - subject: #{c['subject']}"
110
+ puts " name: #{c['name']}"
111
+ puts " type: #{c['type']}"
112
+ end
113
+ end
114
+
115
+ if service['env'].to_a.size > 0
116
+ puts " env: "
117
+ service['env'].to_a.each do |e|
118
+ puts " - #{e}"
119
+ end
120
+ end
121
+
122
+ if service['net'].to_s != 'bridge'
123
+ puts " net: #{service['net']}"
124
+ end
125
+
126
+ if service['ports'].to_a.size > 0
127
+ puts " ports:"
128
+ service['ports'].to_a.each do |p|
129
+ puts " - #{p['node_port']}:#{p['container_port']}/#{p['protocol']}"
130
+ end
131
+ end
132
+
133
+ if service['volumes'].to_a.size > 0
134
+ puts " volumes:"
135
+ service['volumes'].to_a.each do |v|
136
+ puts " - #{v}"
137
+ end
138
+ end
139
+
140
+ if service['volumes_from'].to_a.size > 0
141
+ puts " volumes_from:"
142
+ service['volumes_from'].to_a.each do |v|
143
+ puts " - #{v}"
144
+ end
145
+ end
146
+
147
+ if service['links'].to_a.size > 0
148
+ puts " links: "
149
+ service['links'].to_a.each do |l|
150
+ puts " - #{l['alias']}"
151
+ end
152
+ end
153
+
154
+ if service['cap_add'].to_a.size > 0
155
+ puts " cap_add:"
156
+ service['cap_add'].to_a.each do |c|
157
+ puts " - #{c}"
158
+ end
159
+ end
160
+
161
+ if service['cap_drop'].to_a.size > 0
162
+ puts " cap_drop:"
163
+ service['cap_drop'].to_a.each do |c|
164
+ puts " - #{c}"
165
+ end
166
+ end
167
+
168
+ unless service['log_driver'].to_s.empty?
169
+ puts " log_driver: #{service['log_driver']}"
170
+ puts " log_opts:"
171
+ service['log_opts'].each do |opt, value|
172
+ puts " #{opt}: #{value}"
173
+ end
174
+ end
175
+
176
+ unless service['cpus'].to_s.empty?
177
+ puts " cpus: #{service['cpus']}"
178
+ end
179
+
180
+ unless service['cpu_shares'].to_s.empty?
181
+ puts " cpu_shares: #{service['cpu_shares']}"
182
+ end
183
+
184
+ unless service['memory'].to_s.empty?
185
+ puts " memory: #{int_to_filesize(service['memory'])}"
186
+ end
187
+
188
+ unless service['memory_swap'].to_s.empty?
189
+ puts " memory_swap: #{int_to_filesize(service['memory_swap'])}"
190
+ end
191
+
192
+ unless service['shm_size'].to_s.empty?
193
+ puts " shm_size: #{int_to_filesize(service['shm_size'])}"
194
+ end
195
+
196
+ unless service['pid'].to_s.empty?
197
+ puts " pid: #{service['pid']}"
198
+ end
199
+
200
+ if service['health_check']
201
+ puts " health check:"
202
+ puts " protocol: #{service['health_check']['protocol']}"
203
+ puts " uri: #{service['health_check']['uri']}" if service['health_check']['protocol'] == 'http'
204
+ puts " port: #{service['health_check']['port']}"
205
+ puts " timeout: #{service['health_check']['timeout']}"
206
+ puts " interval: #{service['health_check']['interval']}"
207
+ puts " initial_delay: #{service['health_check']['initial_delay']}"
208
+ end
209
+
210
+ if service['health_status']
211
+ puts " health status:"
212
+ puts " healthy: #{service['health_status']['healthy']}"
213
+ puts " total: #{service['health_status']['total']}"
214
+ end
215
+ end
216
+
217
+ def show_service_instances(token, service_id)
218
+ puts " instances:"
219
+ instances = client(token).get("services/#{parse_service_id(service_id)}/instances")['instances']
220
+ containers = client(token).get("services/#{parse_service_id(service_id)}/containers")['containers']
221
+ instances.each do |i|
222
+ puts " #{name}/#{i['instance_number']}:"
223
+ puts " scheduled_to: #{i.dig('node', 'name') || '-'}"
224
+ puts " deploy_rev: #{i['deploy_rev']}"
225
+ puts " rev: #{i['rev']}"
226
+ puts " state: #{i['state']}"
227
+ puts " error: #{i['error'] || '-'}" if i['error']
228
+ puts " containers:"
229
+ containers.select { |c|
230
+ c['instance_number'] == i['instance_number']
231
+ }.each do |container|
232
+ puts " #{container['name']} (on #{container.dig('node', 'name')}):"
233
+ puts " dns: #{container['hostname']}.#{container['domainname']}"
234
+ puts " ip: #{container['ip_address']}"
235
+ puts " public ip: #{container['node']['public_ip'] rescue 'unknown'}"
236
+ if container['health_status']
237
+ health_time = Time.now - Time.parse(container.dig('health_status', 'updated_at'))
238
+ puts " health: #{container.dig('health_status', 'status')} (#{health_time.to_i}s ago)"
239
+ end
240
+ puts " status: #{container['status']}"
241
+ if container.dig('state', 'error') != ''
242
+ puts " reason: #{container['state']['error']}"
243
+ end
244
+ if container.dig('state', 'exit_code').to_i != 0
245
+ puts " exit code: #{container['state']['exit_code']}"
246
+ end
247
+ end
248
+ end
249
+ end
250
+
251
+ def show_service_containers(token, service_id)
252
+ puts " instances:"
253
+ result = client(token).get("services/#{parse_service_id(service_id)}/containers")
254
+ result['containers'].each do |container|
255
+ puts " #{container['name']}:"
256
+ puts " rev: #{container['deploy_rev']}"
257
+ puts " service_rev: #{container['service_rev']}"
258
+ puts " node: #{container['node']['name'] rescue 'unknown'}"
259
+ puts " dns: #{container['hostname']}.#{container['domainname']}"
260
+ puts " ip: #{container['ip_address']}"
261
+ puts " public ip: #{container['node']['public_ip'] rescue 'unknown'}"
262
+ if container['health_status']
263
+ health_time = Time.now - Time.parse(container.dig('health_status', 'updated_at'))
264
+ puts " health: #{container.dig('health_status', 'status')} (#{health_time.to_i}s ago)"
265
+ end
266
+ if container['status'] == 'unknown'
267
+ puts " status: #{pastel.yellow(container['status'])}"
268
+ else
269
+ puts " status: #{container['status']}"
270
+ end
271
+ if container['state']['error'] && container['state']['error'] != ''
272
+ puts " reason: #{container['state']['error']}"
273
+ end
274
+ if container['state']['exit_code'] && container['state']['exit_code'] != ''
275
+ puts " exit code: #{container['state']['exit_code']}"
276
+ end
277
+ end
278
+ end
279
+
280
+ # @param [String] token
281
+ # @param [String] service_id
282
+ # @param [Hash] data
283
+ def deploy_service(token, service_id, data)
284
+ param = parse_service_id(service_id)
285
+ client(token).post("services/#{param}/deploy", data)
286
+ end
287
+
288
+ # @param [Hash] deployment
289
+ # @return [String] multi-line
290
+ def render_service_deploy_instances(deployment)
291
+ deployment['instance_deploys'].map{ |instance_deploy|
292
+ description = "instance #{deployment['service_id']}-#{instance_deploy['instance_number']} to node #{instance_deploy['node']}"
293
+
294
+ case instance_deploy['state']
295
+ when 'created'
296
+ "#{pastel.dark('⊝')} Deploy #{description}"
297
+ when 'ongoing'
298
+ "#{pastel.cyan('⊙')} Deploying #{description}..."
299
+ when 'success'
300
+ "#{pastel.green('⊛')} Deployed #{description}"
301
+ when 'error'
302
+ "#{pastel.red('⊗')} Failed to deploy #{description}: #{instance_deploy['error']}"
303
+ else
304
+ "#{pastel.dark('⊗')} Deploy #{description}?"
305
+ end
306
+ }
307
+ end
308
+
309
+ # @param [String] token
310
+ # @param [Hash] deployment
311
+ # @param [Fixnum] timeout
312
+ # @param [Boo lean] verbose
313
+ # @raise [Kontena::Errors::StandardError]
314
+ def wait_for_deploy_to_finish(token, deployment, timeout: 600)
315
+ Timeout::timeout(timeout) do
316
+ until deployment['finished_at']
317
+ sleep 1
318
+ deployment = client(token).get("services/#{deployment['service_id']}/deploys/#{deployment['id']}")
319
+ end
320
+
321
+ if deployment['state'] == 'error'
322
+ raise Kontena::Errors::StandardErrorArray.new(500, deployment['reason'], render_service_deploy_instances(deployment))
323
+ else
324
+ puts render_service_deploy_instances(deployment).join("\n")
325
+ end
326
+ end
327
+ rescue Timeout::Error
328
+ raise Kontena::Errors::StandardError.new(500, 'deploy timed out')
329
+ end
330
+
331
+ # @param [String] token
332
+ # @param [String] service_id
333
+ def start_service(token, service_id)
334
+ param = parse_service_id(service_id)
335
+ client(token).post("services/#{param}/start", {})
336
+ end
337
+
338
+ # @param [String] token
339
+ # @param [String] service_id
340
+ def stop_service(token, service_id)
341
+ param = parse_service_id(service_id)
342
+ client(token).post("services/#{param}/stop", {})
343
+ end
344
+
345
+ # @param [String] token
346
+ # @param [String] service_id
347
+ def restart_service(token, service_id)
348
+ param = parse_service_id(service_id)
349
+ client(token).post("services/#{param}/restart", {})
350
+ end
351
+
352
+ # @param [String] token
353
+ # @param [String] service_id
354
+ def delete_service(token, service_id)
355
+ param = parse_service_id(service_id)
356
+ client(token).delete("services/#{param}")
357
+ end
358
+
359
+ # @param [String] service_id
360
+ # @return [String]
361
+ def parse_service_id(service_id)
362
+ count = service_id.to_s.count('/')
363
+ if count == 2
364
+ param = service_id
365
+ elsif count == 1
366
+ param = "#{current_grid}/#{service_id}"
367
+ else
368
+ param = "#{current_grid}/null/#{service_id}"
369
+ end
370
+ end
371
+
372
+ # Parses container name based on service name and instance number
373
+ # @param [String] service_name
374
+ # @param [Integer] instance_number
375
+ def parse_container_name(service_name, instance_number)
376
+ base = service_name.gsub('/', '-')
377
+ unless service_name.include?('/')
378
+ base = "null-#{base}"
379
+ end
380
+ "#{base}-#{instance_number}"
381
+ end
382
+
383
+ # @param [Array<String>] port_options
384
+ # @return [Array<Hash>]
385
+ def parse_ports(port_options)
386
+ port_regex = Regexp.new(/\A(?<ip>\d+\.\d+\.\d+\.\d+)?:?(?<node_port>\d+)\:(?<container_port>\d+)\/?(?<protocol>\w+)?\z/)
387
+ port_options.map do |p|
388
+ if p.kind_of?(Hash)
389
+ raise ArgumentError, "Missing or invalid node port" unless p['node_port'].to_i > 0
390
+ raise ArgumentError, "Missing or invalid container port" unless p['container_port'].to_i > 0
391
+ { ip: p['ip'] || '0.0.0.0', protocol: p['protocol'] || 'tcp', node_port: p['node_port'].to_i, container_port: p['container_port'].to_i }
392
+ else
393
+ match_data = port_regex.match(p.to_s)
394
+ raise ArgumentError, "Invalid port value #{p}" unless match_data
395
+
396
+ {
397
+ ip: '0.0.0.0',
398
+ protocol: 'tcp'
399
+ }.merge(match_data.names.map { |name| [name.to_sym, match_data[name]] }.to_h.reject { |_,v| v.nil? })
400
+ end
401
+ end
402
+ end
403
+
404
+ # @param [Array<String>] link_options
405
+ # @return [Array<Hash>]
406
+ def parse_links(link_options)
407
+ link_options.map{|l|
408
+ service_name, alias_name = l.split(':')
409
+ if service_name.nil?
410
+ raise ArgumentError.new("Invalid link value #{l}")
411
+ end
412
+ alias_name = service_name if alias_name.nil?
413
+ {
414
+ name: service_name,
415
+ alias: alias_name
416
+ }
417
+ }
418
+ end
419
+
420
+ # @param [String] memory
421
+ # @return [Integer]
422
+ def parse_memory(memory)
423
+ case memory
424
+ when /^\d+(k|K)$/
425
+ memory.to_i * 1024
426
+ when /^\d+(m|M)$/
427
+ memory.to_i * 1024 * 1024
428
+ when /^\d+(g|G)$/
429
+ memory.to_i * 1024 * 1024 * 1024
430
+ when /^\d+$/
431
+ memory.to_i
432
+ else
433
+ raise ArgumentError.new("Invalid memory value: #{memory}")
434
+ end
435
+ end
436
+
437
+ # @param [String] image
438
+ # @return [String]
439
+ def parse_image(image = nil)
440
+ return if image.nil?
441
+ unless image.include?(":")
442
+ image = "#{image}:latest"
443
+ end
444
+ image
445
+ end
446
+
447
+ ##
448
+ # @param [Array] log_opts
449
+ # @return [Hash]
450
+ def parse_log_opts(log_opts)
451
+ opts = {}
452
+ log_opts.each do |opt|
453
+ key, value = opt.split('=')
454
+ opts[key] = value
455
+ end
456
+ opts
457
+ end
458
+
459
+ # @param [Array<String>] secret_opts
460
+ # @return [Array<Hash>]
461
+ def parse_secrets(secret_opts)
462
+ secrets = []
463
+ secret_opts.each do |s|
464
+ secret, name, type = s.split(':')
465
+ secrets << {secret: secret, name: name, type: type}
466
+ end
467
+ secrets
468
+ end
469
+
470
+ # @param [String] time
471
+ # @return [Integer, NilClass]
472
+ def parse_relative_time(time)
473
+ if time.end_with?('min')
474
+ time.to_i * 60
475
+ elsif time.end_with?('h')
476
+ time.to_i * 60 * 60
477
+ elsif time.end_with?('d')
478
+ time.to_i * 60 * 60 * 24
479
+ else
480
+ time = time.to_i
481
+ if time == 0
482
+ nil
483
+ else
484
+ time
485
+ end
486
+ end
487
+ end
488
+
489
+ def int_to_filesize(int)
490
+ {
491
+ 'B' => 1000,
492
+ 'KB' => 1000 * 1000,
493
+ 'MB' => 1000 * 1000 * 1000,
494
+ 'GB' => 1000 * 1000 * 1000 * 1000,
495
+ 'TB' => 1000 * 1000 * 1000 * 1000 * 1000
496
+ }.each_pair { |e, s| return "#{(int.to_i / (s / 1000))}#{e}" if int < s }
497
+ end
498
+
499
+ def parse_build_args(args)
500
+ build_args = {}
501
+ if args.kind_of?(Array)
502
+ args.each do |arg|
503
+ key, val = arg.split('=')
504
+ build_args[key] = val
505
+ end
506
+ elsif args.kind_of?(Hash)
507
+ build_args = build_args.merge(args)
508
+ build_args.each do |k, v|
509
+ if v.nil?
510
+ build_args[k] = ENV[k.to_s] # follow docker compose functionality here
511
+ end
512
+ end
513
+ end
514
+
515
+ build_args
516
+ end
517
+
518
+ # @return [Hash]
519
+ def parse_deploy_opts
520
+ deploy_opts = {}
521
+ deploy_opts[:min_health] = deploy_min_health.to_f if deploy_min_health
522
+ deploy_opts[:wait_for_port] = deploy_wait_for_port.to_i if deploy_wait_for_port
523
+ if deploy_interval
524
+ deploy_opts[:interval] = parse_relative_time(deploy_interval)
525
+ end
526
+
527
+ deploy_opts
528
+ end
529
+
530
+ # @return [Hash]
531
+ def parse_health_check
532
+ health_check = {}
533
+ if health_check_port
534
+ health_check[:port] = health_check_port == 'none' ? nil : health_check_port
535
+ end
536
+ if health_check_protocol
537
+ health_check[:protocol] = health_check_protocol == 'none' ? nil : health_check_protocol
538
+ end
539
+ health_check[:uri] = health_check_uri if health_check_uri
540
+ health_check[:timeout] = health_check_timeout if health_check_timeout
541
+ health_check[:interval] = health_check_interval if health_check_interval
542
+ health_check[:initial_delay] = health_check_initial_delay if health_check_initial_delay
543
+
544
+ health_check
545
+ end
546
+
547
+ # @param [Symbol] health
548
+ # @return [String]
549
+ def health_status_icon(health)
550
+ case health
551
+ when :unhealthy then pastel.red('⊗')
552
+ when :partial then pastel.yellow('⊙')
553
+ when :healthy then pastel.green('⊛')
554
+ else
555
+ pastel.dim('⊝')
556
+ end
557
+ end
558
+
559
+ # @param [Hash] service
560
+ # @return [Symbol]
561
+ def health_status(service)
562
+ if service['health_status']
563
+ healthy = service.dig('health_status', 'healthy')
564
+ total = service.dig('health_status', 'total')
565
+ if healthy == 0
566
+ :unhealthy
567
+ elsif healthy > 0 && healthy < total
568
+ :partial
569
+ else
570
+ :healthy
571
+ end
572
+ else
573
+ :unknown
574
+ end
575
+ end
576
+ end
577
+ end
578
+ end
579
+ end
@@ -0,0 +1,26 @@
1
+ require_relative 'services_helper'
2
+
3
+ module Kontena::Cli::Services
4
+ class ShowCommand < Kontena::Command
5
+ include Kontena::Cli::Common
6
+ include Kontena::Cli::GridOptions
7
+ include ServicesHelper
8
+
9
+ parameter "NAME", "Service name"
10
+
11
+ def execute
12
+ require_api_url
13
+ token = require_token
14
+
15
+ show_service(token, name)
16
+ begin
17
+ show_service_instances(token, name)
18
+ rescue Kontena::Errors::StandardError => exc
19
+ if exc.status == 404
20
+ # fallback to old behaviour
21
+ show_service_containers(token, name)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,21 @@
1
+ require_relative 'services_helper'
2
+
3
+ module Kontena::Cli::Services
4
+ class StartCommand < Kontena::Command
5
+ include Kontena::Cli::Common
6
+ include Kontena::Cli::GridOptions
7
+ include ServicesHelper
8
+
9
+ parameter "NAME ...", "Service name", attribute_name: :names
10
+
11
+ def execute
12
+ require_api_url
13
+ token = require_token
14
+ names.each do |name|
15
+ spinner "Sending start signal to #{pastel.cyan(name)} service " do
16
+ start_service(token, name)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end