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 'common'
2
+
3
+ module Kontena::Cli::Grids
4
+ class UseCommand < Kontena::Command
5
+ include Kontena::Cli::Common
6
+ include Common
7
+
8
+ requires_current_master
9
+
10
+ parameter "NAME", "Grid name to use"
11
+
12
+ option ['--silent'], :flag, 'Reduce output verbosity'
13
+
14
+ def execute
15
+ grid = find_grid_by_name(name)
16
+ unless grid
17
+ exit_with_error pastel.red("Could not resolve grid by name [#{name}]. For a list of existing grids please run: kontena grid list")
18
+ end
19
+ config.current_master.grid = grid['name']
20
+ config.write
21
+ unless self.silent?
22
+ puts "Using grid: #{pastel.cyan(grid['name'])}"
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,9 @@
1
+ module Kontena::Cli::Grids
2
+
3
+
4
+ class UserCommand < Kontena::Command
5
+ subcommand ["list", "ls"], "List grid users", load_subcommand('grids/users/list_command')
6
+ subcommand "add", "Add user to grid", load_subcommand('grids/users/add_command')
7
+ subcommand ["remove", "rm"], "Remove user from grid", load_subcommand('grids/users/remove_command')
8
+ end
9
+ end
@@ -0,0 +1,18 @@
1
+ require_relative '../common'
2
+
3
+ module Kontena::Cli::Grids::Users
4
+ class AddCommand < Kontena::Command
5
+ include Kontena::Cli::Common
6
+ include Kontena::Cli::GridOptions
7
+ include Kontena::Cli::Grids::Common
8
+
9
+ parameter "EMAIL", "Email address"
10
+
11
+ def execute
12
+ require_api_url
13
+ token = require_token
14
+ data = { email: email }
15
+ client(token).post("grids/#{current_grid}/users", data)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ require_relative '../common'
2
+
3
+ module Kontena::Cli::Grids::Users
4
+ class ListCommand < Kontena::Command
5
+ include Kontena::Cli::Common
6
+ include Kontena::Cli::Grids::Common
7
+ include Kontena::Cli::TableGenerator::Helper
8
+ include Kontena::Cli::GridOptions
9
+
10
+ requires_current_master
11
+
12
+ def fields
13
+ quiet? ? %w(email) : %w(email name)
14
+ end
15
+
16
+ def execute
17
+ print_table(client.get("grids/#{current_grid}/users")['users'])
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ require_relative '../common'
2
+
3
+ module Kontena::Cli::Grids::Users
4
+ class RemoveCommand < Kontena::Command
5
+ include Kontena::Cli::Common
6
+ include Kontena::Cli::GridOptions
7
+ include Kontena::Cli::Grids::Common
8
+
9
+ parameter "EMAIL", "Email address"
10
+ option "--force", :flag, "Force remove", default: false, attribute_name: :forced
11
+
12
+ def execute
13
+ require_api_url
14
+ token = require_token
15
+ confirm_command(email) unless forced?
16
+
17
+ result = client(token).delete("grids/#{current_grid}/users/#{email}")
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,209 @@
1
+ require 'io/console'
2
+ require 'tty-screen'
3
+ require 'kontena-websocket-client'
4
+
5
+ module Kontena::Cli::Helpers
6
+ module ExecHelper
7
+
8
+ websocket_log_level = if ENV["DEBUG"] == 'websocket'
9
+ Logger::DEBUG
10
+ elsif Kontena.debug?
11
+ Logger::INFO
12
+ else
13
+ Logger::WARN
14
+ end
15
+
16
+ Kontena::Websocket::Logging.initialize_logger(STDERR, websocket_log_level)
17
+
18
+ WEBSOCKET_CLIENT_OPTIONS = {
19
+ connect_timeout: ENV["EXCON_CONNECT_TIMEOUT"] ? ENV["EXCON_CONNECT_TIMEOUT"].to_f : 10.0,
20
+ open_timeout: ENV["EXCON_CONNECT_TIMEOUT"] ? ENV["EXCON_CONNECT_TIMEOUT"].to_f : 10.0,
21
+ ping_interval: ENV["EXCON_READ_TIMEOUT"] ? ENV["EXCON_READ_TIMEOUT"].to_f : 30.0,
22
+ ping_timeout: ENV["EXCON_CONNECT_TIMEOUT"] ? ENV["EXCON_CONNECT_TIMEOUT"].to_f : 10.0,
23
+ close_timeout: ENV["EXCON_CONNECT_TIMEOUT"] ? ENV["EXCON_CONNECT_TIMEOUT"].to_f : 10.0,
24
+ write_timeout: ENV["EXCON_WRITE_TIMEOUT"] ? ENV["EXCON_WRITE_TIMEOUT"].to_f : 10.0,
25
+ }
26
+
27
+ # @param ws [Kontena::Websocket::Client]
28
+ # @param tty [Boolean] read stdin in raw mode, sending tty escapes for remote pty
29
+ # @raise [ArgumentError] not a tty
30
+ # @yield [data]
31
+ # @yieldparam data [String] unicode data from stdin
32
+ # @raise [ArgumentError] not a tty
33
+ # @return EOF on stdin (!tty)
34
+ def read_stdin(tty: nil)
35
+ if tty
36
+ # NOTE: This check has been disabled since tests in Jenkins are run without TTY allocation
37
+ # raise ArgumentError, "the input device is not a TTY" unless STDIN.tty?
38
+
39
+ STDIN.raw { |io|
40
+ # we do not expect EOF on a TTY, ^D sends a tty escape to close the pty instead
41
+ loop do
42
+ # raises EOFError, SyscallError or IOError
43
+ chunk = io.readpartial(1024)
44
+
45
+ # STDIN.raw does not use the ruby external_encoding, it returns binary strings (ASCII-8BIT encoding)
46
+ # however, we use websocket text frames with JSON, which expects unicode strings encodable as UTF-8, and does not handle arbitrary binary data
47
+ # assume all stdin input is using ruby's external_encoding... the JSON.dump will fail if not.
48
+ chunk.force_encoding(Encoding.default_external)
49
+
50
+ yield chunk
51
+ end
52
+ }
53
+ else
54
+ # line-buffered, using the default external_encoding (probably UTF-8)
55
+ while line = STDIN.gets
56
+ yield line
57
+ end
58
+ end
59
+ end
60
+
61
+ # @return [String]
62
+ def websocket_url(path, query = nil)
63
+ url = URI.parse(require_current_master.url)
64
+ url.scheme = url.scheme.sub('http', 'ws')
65
+ url.path = '/v1/' + path
66
+ url.query = (query && !query.empty?) ? URI.encode_www_form(query) : nil
67
+ url.to_s
68
+ end
69
+
70
+ # @param ws [Kontena::Websocket::Client]
71
+ # @raise [RuntimeError] exec error
72
+ # @return [Integer] exit code
73
+ def websocket_exec_read(ws)
74
+ ws.read do |msg|
75
+ msg = JSON.parse(msg)
76
+
77
+ logger.debug "websocket exec read: #{msg.inspect}"
78
+
79
+ if msg.has_key?('error')
80
+ raise msg['error']
81
+ elsif msg.has_key?('exit')
82
+ # breaks the read loop
83
+ return msg['exit'].to_i
84
+ elsif msg.has_key?('stream')
85
+ if msg['stream'] == 'stdout'
86
+ $stdout << msg['chunk']
87
+ else
88
+ $stderr << msg['chunk']
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ # @param ws [Kontena::Websocket::Client]
95
+ # @param msg [Hash]
96
+ def websocket_exec_write(ws, msg)
97
+ logger.debug "websocket exec write: #{msg.inspect}"
98
+
99
+ ws.send(JSON.dump(msg))
100
+ end
101
+
102
+ # Start thread to read from stdin, and write to websocket.
103
+ # Closes websocket on stdin read errors.
104
+ #
105
+ # @param ws [Kontena::Websocket::Client]
106
+ # @param tty [Boolean]
107
+ # @return [Thread]
108
+ def websocket_exec_write_thread(ws, tty: nil)
109
+ Thread.new do
110
+ begin
111
+ if tty
112
+ console_height, console_width = TTY::Screen.size
113
+ websocket_exec_write(ws, 'tty_size' => {
114
+ width: console_width, height: console_height
115
+ })
116
+ end
117
+ read_stdin(tty: tty) do |stdin|
118
+ logger.debug "websocket exec stdin with encoding=#{stdin.encoding}: #{stdin.inspect}"
119
+ websocket_exec_write(ws, 'stdin' => stdin)
120
+ end
121
+ websocket_exec_write(ws, 'stdin' => nil) # EOF
122
+ rescue => exc
123
+ logger.error exc
124
+ ws.close(1001, "stdin read #{exc.class}: #{exc}")
125
+ end
126
+ end
127
+ end
128
+
129
+ # Connect to server websocket, send from stdin, and write out messages
130
+ #
131
+ # @param paths [String]
132
+ # @param options [Hash] @see Kontena::Websocket::Client
133
+ # @param cmd [Array<String>] command to execute
134
+ # @param interactive [Boolean] Interactive TTY on/off
135
+ # @param shell [Boolean] Shell on/of
136
+ # @param tty [Boolean] TTY on/of
137
+ # @return [Integer] exit code
138
+ def websocket_exec(path, cmd, interactive: false, shell: false, tty: false)
139
+ exit_status = nil
140
+ write_thread = nil
141
+
142
+ query = {}
143
+ query[:interactive] = interactive if interactive
144
+ query[:shell] = shell if shell
145
+ query[:tty] = tty if tty
146
+
147
+ server = require_current_master
148
+ url = websocket_url(path, query)
149
+ token = require_token
150
+ options = WEBSOCKET_CLIENT_OPTIONS.dup
151
+ options[:headers] = {
152
+ 'Authorization' => "Bearer #{token.access_token}"
153
+ }
154
+ options[:ssl_params] = {
155
+ verify_mode: ENV['SSL_IGNORE_ERRORS'].to_s == 'true' ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER,
156
+ ca_file: server.ssl_cert_path,
157
+ }
158
+ options[:ssl_hostname] = server.ssl_subject_cn
159
+
160
+ logger.debug { "websocket exec connect... #{url}" }
161
+
162
+ # we do not expect CloseError, because the server will send an 'exit' message first,
163
+ # and we return before seeing the close frame
164
+ # TODO: handle HTTP 404 errors
165
+ Kontena::Websocket::Client.connect(url, **options) do |ws|
166
+ logger.debug { "websocket exec open" }
167
+
168
+ # first frame contains exec command
169
+ websocket_exec_write(ws, 'cmd' => cmd)
170
+
171
+ if interactive
172
+ # start new thread to write from stdin to websocket
173
+ write_thread = websocket_exec_write_thread(ws, tty: tty)
174
+ end
175
+
176
+ # blocks reading from websocket, returns with exec exit code
177
+ exit_status = websocket_exec_read(ws)
178
+
179
+ fail ws.close_reason unless exit_status
180
+ end
181
+
182
+ rescue Kontena::Websocket::Error => exc
183
+ exit_with_error(exc)
184
+
185
+ rescue => exc
186
+ logger.error { "websocket exec error: #{exc}" }
187
+ raise
188
+
189
+ else
190
+ logger.debug { "websocket exec exit: #{exit_status}"}
191
+ return exit_status
192
+
193
+ ensure
194
+ if write_thread
195
+ write_thread.kill
196
+ write_thread.join
197
+ end
198
+ end
199
+
200
+ # Execute command on container using websocket API.
201
+ #
202
+ # @param id [String] Container ID (grid/host/name)
203
+ # @param cmd [Array<String>] command to execute
204
+ # @return [Integer] exit code
205
+ def container_exec(id, cmd, **exec_options)
206
+ websocket_exec("containers/#{id}/exec", cmd, **exec_options)
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,65 @@
1
+ module Kontena::Cli::Helpers
2
+ module HealthHelper
3
+ def health_icon(health)
4
+ case health
5
+ when nil
6
+ " "
7
+ when :ok
8
+ pastel.green('⊛')
9
+ when :warning
10
+ pastel.yellow('⊙')
11
+ when :error
12
+ pastel.red('⊗')
13
+ when :offline
14
+ pastel.dark('⊝')
15
+ else
16
+ fail "Invalid health=#{health}"
17
+ end
18
+ end
19
+
20
+ # Validate grid nodes configuration and status
21
+ #
22
+ # @param grid [Hash] get(/grids/:grid) => { ... }
23
+ # @param nodes [Array<Hash>] get(/grids/:grid/nodes)[nodes] => [ { ... } ]
24
+ # @return [Symbol] health
25
+ def grid_health(grid, nodes)
26
+ initial = grid['initial_size']
27
+ minimum = grid['initial_size'] / 2 + 1 # a majority is required for etcd quorum
28
+
29
+ online = nodes.select{|node| node['initial_member'] && node['connected']}
30
+
31
+ if online.length < minimum
32
+ return :error
33
+ elsif online.length < initial
34
+ return :warning
35
+ else
36
+ return :ok
37
+ end
38
+ end
39
+
40
+ # Validate grid node status based on the grid health
41
+ #
42
+ # @param node [Hash] GET /nodes/:grid/:node
43
+ # @param grid_health [Symbol] @see #grid_health
44
+ # @return [Symbol] health
45
+ def node_health(node, grid_health)
46
+ if node['initial_member']
47
+ return node['connected'] ? grid_health : :offline
48
+ else
49
+ return node['connected'] ? :ok : :offline
50
+ end
51
+ end
52
+
53
+ # @param node_etcd_health [Hash{health: String, error: String}]
54
+ # @return [Symbol, String]
55
+ def node_etcd_health(node_etcd_health)
56
+ if node_etcd_health['health']
57
+ return :ok, "healthy"
58
+ elsif node_etcd_health['error']
59
+ return :error, "unhealthy: #{node_etcd_health['error']}"
60
+ else
61
+ return :error, "unhealthy"
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,113 @@
1
+ module Kontena::Cli::Helpers
2
+ module LogHelper
3
+
4
+ def self.included(base)
5
+ if base.respond_to?(:option)
6
+ base.option ["-f", "--follow"], :flag, "Follow log output", :attribute_name => :tail, default: false
7
+ base.option ['--tail', '--lines'], "LINES", "Number of lines to show from the end of the logs", :attribute_name => :lines, default: 100 do |s|
8
+ Integer(s)
9
+ end
10
+ base.option "--since", "SINCE", "Show logs since given timestamp"
11
+ end
12
+ end
13
+
14
+ # @return [String]
15
+ def token
16
+ @token ||= require_token
17
+ end
18
+
19
+ def show_logs(url, query_params = { }, &block)
20
+ if tail?
21
+ stream_logs(url, query_params, &block)
22
+ else
23
+ get_logs(url, query_params, &block)
24
+ end
25
+ end
26
+
27
+ def get_logs(url, query_params)
28
+ query_params[:limit] = lines if lines
29
+ query_params[:since] = since if since
30
+
31
+ result = client(token).get(url, query_params)
32
+ result['logs'].each do |log|
33
+ yield log
34
+ end
35
+ end
36
+
37
+ # @param [String] url
38
+ # @param [Hash] query_params
39
+ def stream_logs(url, query_params)
40
+ query_params[:limit] = lines if lines
41
+ query_params[:since] = since if since
42
+ query_params[:follow] = 1
43
+
44
+ last_seen = nil
45
+ streamer = lambda do |chunk, remaining_bytes, total_bytes|
46
+ log = buffered_log_json(chunk)
47
+ if log
48
+ yield log
49
+ last_seen = log['id']
50
+ end
51
+ end
52
+
53
+ begin
54
+ query_params[:from] = last_seen if last_seen
55
+ client(token).get_stream(url, streamer, query_params)
56
+ rescue => exc
57
+ retry if exc.cause.is_a?(EOFError) # Excon wraps the EOFerror into SocketError
58
+ raise
59
+ end
60
+ end
61
+
62
+ # @param [String] chunk
63
+ # @return [Hash,NilClass]
64
+ def buffered_log_json(chunk)
65
+ @buffer = '' if @buffer.nil?
66
+ return if @buffer.empty? && chunk.strip.empty?
67
+ begin
68
+ orig_chunk = chunk
69
+ unless @buffer.empty?
70
+ chunk = @buffer + chunk
71
+ end
72
+ unless chunk.empty?
73
+ log = JSON.parse(chunk)
74
+ end
75
+ @buffer = ''
76
+ log
77
+ rescue
78
+ @buffer << orig_chunk
79
+ nil
80
+ end
81
+ end
82
+
83
+ def show_log(log)
84
+ color = color_for_container(log['name'])
85
+ prefix = "#{log['created_at']} #{log['name']}:"
86
+
87
+ puts "#{pastel.send(color, prefix)} #{log['data']}"
88
+ end
89
+
90
+ # @param [String] container_id
91
+ # @return [Symbol]
92
+ def color_for_container(container_id)
93
+ color_maps[container_id] = colors.shift unless color_maps[container_id]
94
+ color_maps[container_id].to_sym
95
+ end
96
+
97
+ # @return [Hash]
98
+ def color_maps
99
+ @color_maps ||= {}
100
+ end
101
+
102
+ # @return [Array<Symbol>]
103
+ def colors
104
+ if(@colors.nil? || @colors.size == 0)
105
+ @colors = %i(
106
+ red green yellow blue magenta cyan bright_red bright_green
107
+ bright_yellow bright_blue bright_magenta bright_cyan
108
+ )
109
+ end
110
+ @colors
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,29 @@
1
+ module Kontena::Cli::Helpers
2
+ module TimeHelper
3
+ # Return an approximation of how long ago the given time was.
4
+ # @param time [String]
5
+ # @param terse [Boolean] very terse output (2-3 chars wide)
6
+ def time_since(time, terse: false)
7
+ return '' if time.nil? || time.empty?
8
+
9
+ dt = Time.now - Time.parse(time)
10
+
11
+ dt_s = dt.to_i
12
+ dt_m, dt_s = dt_s / 60, dt_s % 60
13
+ dt_h, dt_m = dt_m / 60, dt_m % 60
14
+ dt_d, dt_h = dt_h / 60, dt_h % 60
15
+
16
+ parts = []
17
+ parts << "%dd" % dt_d if dt_d > 0
18
+ parts << "%dh" % dt_h if dt_h > 0
19
+ parts << "%dm" % dt_m if dt_m > 0
20
+ parts << "%ds" % dt_s
21
+
22
+ if terse
23
+ return parts.first
24
+ else
25
+ return parts.join('')
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,113 @@
1
+ require 'socket'
2
+ require 'uri'
3
+
4
+ module Kontena
5
+ class LocalhostWebServer
6
+ # Serves one request to http://localhost:<random_port>/cb
7
+ #
8
+ # Used for local webserver browser authentication flow.
9
+ #
10
+ # @example
11
+ # server = LocalhostWebServer.new
12
+ # server.url
13
+ # => "http://localhost:1234/cb"
14
+ # response = server.serve_one
15
+ # # <visit server.url?foo=bar&bar=123 on browser>
16
+ # => { "foo" => "bar", "bar" => 123 } # (it converts integers!)
17
+ attr_accessor :server, :success_response, :error_response, :port
18
+
19
+ DEFAULT_ERROR_MESSAGE = "Bad request"
20
+ SUCCESS_URL = "https://cloud.kontena.io/terminal-success"
21
+
22
+ # Get new server instance
23
+ #
24
+ # @param [String] success_response Returned for successful callback
25
+ # @param [String] error_response Returned for unsuccessful callback
26
+ def initialize(success_response: nil, error_response: nil, port: nil)
27
+ @success_response = success_response
28
+ @error_response = error_response || DEFAULT_ERROR_MESSAGE
29
+ @server = TCPServer.new('localhost', port || 0)
30
+ @port = @server.addr[1]
31
+ end
32
+
33
+ # The url to this service, send this as redirect_uri to auth provider.
34
+ def url
35
+ "http://localhost:#{port}/cb"
36
+ end
37
+
38
+ # Serve one request and return query params.
39
+ #
40
+ # @return [Hash] query_params
41
+ def serve_one
42
+ Kontena.logger.debug("LHWS") { "Waiting for connection on port #{port}.." }
43
+ socket = server.accept
44
+
45
+ content = socket.recvfrom(2048).first.split(/(?:\r)?\n/)
46
+
47
+ request = content.shift
48
+
49
+ headers = {}
50
+ while line = content.shift
51
+ break if line.nil?
52
+ break if line == ''
53
+ header, value = line.chomp.split(/:\s{0,}/, 2)
54
+ headers[header] = value
55
+ end
56
+
57
+ body = content.join("\n")
58
+
59
+ Kontena.logger.debug("LHWS") { "Got request: \"#{request.inspect}\n Headers: #{headers.inspect}\n Body: #{body}\"" }
60
+
61
+ get_request = request[/GET (\/cb.+?) HTTP/, 1]
62
+ if get_request
63
+ if success_response
64
+ socket.print [
65
+ 'HTTP/1.1 200 OK',
66
+ 'Content-Type: text/html',
67
+ "Content-Length: #{success_response.bytesize}",
68
+ "Connection: close",
69
+ '',
70
+ success_response
71
+ ].join("\r\n")
72
+ else
73
+ socket.print [
74
+ 'HTTP/1.1 302 Found',
75
+ "Location: #{SUCCESS_URL}",
76
+ "Referrer-Policy: no-referrer",
77
+ "Connection: close",
78
+ ''
79
+ ].join("\r\n")
80
+ end
81
+
82
+ socket.close
83
+ server.close
84
+ uri = URI.parse("http://localhost#{get_request}")
85
+ Kontena.logger.debug("LHWS") { " * Parsing params: \"#{uri.query}\"" }
86
+ params = {}
87
+ URI.decode_www_form(uri.query).each do |key, value|
88
+ if value.to_s == ''
89
+ next
90
+ elsif value.to_s =~ /\A\d+\z/
91
+ params[key] = value.to_i
92
+ else
93
+ params[key] = value
94
+ end
95
+ end
96
+ params
97
+ else
98
+ # Unless it's a query to /cb, send an error message and keep listening,
99
+ # it might have been something funny like fetching favicon.ico
100
+ socket.print [
101
+ 'HTTP/1.1 400 Bad request',
102
+ 'Content-Type: text/plain',
103
+ "Content-Length: #{error_response.bytesize}",
104
+ 'Connection: close',
105
+ '',
106
+ error_response
107
+ ].join("\r\n")
108
+ socket.close
109
+ serve_one # serve more, this one was not proper.
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,65 @@
1
+ require 'logger'
2
+
3
+ module Kontena
4
+ module Cli
5
+ module LogFormatter
6
+ class Compact < Logger::Formatter
7
+ def self.ms_since_first
8
+ Time.now.to_f - @first_log
9
+ end
10
+
11
+ def self.ms_since_last
12
+ ((Time.now.to_f - @last_log) * 1000).to_i
13
+ ensure
14
+ @last_log = Time.now.to_f
15
+ end
16
+
17
+ def self.__init_timers__
18
+ @first_log = $KONTENA_START_TIME || Time.now.to_f
19
+ @last_log = @first_log
20
+ end
21
+
22
+ __init_timers__
23
+
24
+ DEBUG_INDICATOR = Kontena.pastel.inverse.bright_blue('DEBUG').freeze
25
+ WARN_INDICATOR = Kontena.pastel.inverse.yellow('WARN ').freeze
26
+ INFO_INDICATOR = Kontena.pastel.inverse.cyan('INFO ').freeze
27
+ ERROR_INDICATOR = Kontena.pastel.inverse.red('ERROR').freeze
28
+
29
+ def colorize_severity(severity)
30
+ case severity[0..0]
31
+ when 'D' then DEBUG_INDICATOR
32
+ when 'W' then WARN_INDICATOR
33
+ when 'I' then INFO_INDICATOR
34
+ when 'E', 'F' then ERROR_INDICATOR
35
+ else severity[0..0]
36
+ end
37
+ end
38
+
39
+ TS_FORMAT = '%4d'.freeze
40
+
41
+ def colorized_time
42
+ elapsed = self.class.ms_since_last
43
+ ts = TS_FORMAT % [elapsed]
44
+ if elapsed > 300
45
+ Kontena.pastel.red(ts)
46
+ elsif elapsed > 100
47
+ Kontena.pastel.yellow(ts)
48
+ else
49
+ ts
50
+ end
51
+ end
52
+
53
+ if ENV['DEBUG_PERF']
54
+ define_method :call do |severity, time, progname, msg|
55
+ "#{colorize_severity(severity)} #{colorized_time} #{msg2str(msg)}\n"
56
+ end
57
+ else
58
+ define_method :call do |severity, time, progname, msg|
59
+ "#{colorize_severity(severity)} #{msg2str(msg)}\n"
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end