central-cli 0.6.3

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 (259) hide show
  1. checksums.yaml +7 -0
  2. data/.dockerignore +3 -0
  3. data/.gitignore +15 -0
  4. data/.rspec +6 -0
  5. data/.rubocop.yml +5 -0
  6. data/Dockerfile +15 -0
  7. data/Gemfile +10 -0
  8. data/LICENSE +191 -0
  9. data/README.md +39 -0
  10. data/Rakefile +9 -0
  11. data/VERSION +1 -0
  12. data/bin/cm +85 -0
  13. data/central-cli.gemspec +35 -0
  14. data/central-docker.sh +6 -0
  15. data/lib/central/cli/app_command.rb +29 -0
  16. data/lib/central/cli/apps/build_command.rb +24 -0
  17. data/lib/central/cli/apps/central_yml_generator.rb +88 -0
  18. data/lib/central/cli/apps/common.rb +166 -0
  19. data/lib/central/cli/apps/deploy_command.rb +191 -0
  20. data/lib/central/cli/apps/docker_compose_generator.rb +48 -0
  21. data/lib/central/cli/apps/docker_helper.rb +85 -0
  22. data/lib/central/cli/apps/dockerfile_generator.rb +15 -0
  23. data/lib/central/cli/apps/init_command.rb +91 -0
  24. data/lib/central/cli/apps/list_command.rb +68 -0
  25. data/lib/central/cli/apps/logs_command.rb +76 -0
  26. data/lib/central/cli/apps/monitor_command.rb +93 -0
  27. data/lib/central/cli/apps/remove_command.rb +80 -0
  28. data/lib/central/cli/apps/restart_command.rb +38 -0
  29. data/lib/central/cli/apps/scale_command.rb +31 -0
  30. data/lib/central/cli/apps/show_command.rb +23 -0
  31. data/lib/central/cli/apps/start_command.rb +39 -0
  32. data/lib/central/cli/apps/stop_command.rb +39 -0
  33. data/lib/central/cli/auth/aws/create_command.rb +34 -0
  34. data/lib/central/cli/auth/aws_command.rb +7 -0
  35. data/lib/central/cli/auth/list_command.rb +28 -0
  36. data/lib/central/cli/auth_command.rb +9 -0
  37. data/lib/central/cli/bytes_helper.rb +38 -0
  38. data/lib/central/cli/common.rb +148 -0
  39. data/lib/central/cli/container_command.rb +10 -0
  40. data/lib/central/cli/containers/exec_command.rb +21 -0
  41. data/lib/central/cli/containers/inspect_command.rb +22 -0
  42. data/lib/central/cli/etcd/common.rb +7 -0
  43. data/lib/central/cli/etcd/get_command.rb +26 -0
  44. data/lib/central/cli/etcd/list_command.rb +31 -0
  45. data/lib/central/cli/etcd/mkdir_command.rb +21 -0
  46. data/lib/central/cli/etcd/remove_command.rb +25 -0
  47. data/lib/central/cli/etcd/set_command.rb +22 -0
  48. data/lib/central/cli/etcd_command.rb +16 -0
  49. data/lib/central/cli/external_registries/add_command.rb +21 -0
  50. data/lib/central/cli/external_registries/delete_command.rb +15 -0
  51. data/lib/central/cli/external_registries/list_command.rb +27 -0
  52. data/lib/central/cli/external_registries/remove_command.rb +13 -0
  53. data/lib/central/cli/external_registry_command.rb +14 -0
  54. data/lib/central/cli/login_command.rb +121 -0
  55. data/lib/central/cli/logout_command.rb +7 -0
  56. data/lib/central/cli/master/aws/create_command.rb +41 -0
  57. data/lib/central/cli/master/aws_command.rb +7 -0
  58. data/lib/central/cli/master/azure/create_command.rb +39 -0
  59. data/lib/central/cli/master/azure_command.rb +11 -0
  60. data/lib/central/cli/master/digital_ocean/create_command.rb +35 -0
  61. data/lib/central/cli/master/digital_ocean_command.rb +11 -0
  62. data/lib/central/cli/master/list_command.rb +28 -0
  63. data/lib/central/cli/master/use_command.rb +34 -0
  64. data/lib/central/cli/master/users/add_role_command.rb +26 -0
  65. data/lib/central/cli/master/users/invite_command.rb +24 -0
  66. data/lib/central/cli/master/users/list_command.rb +18 -0
  67. data/lib/central/cli/master/users/remove_command.rb +22 -0
  68. data/lib/central/cli/master/users/remove_role_command.rb +25 -0
  69. data/lib/central/cli/master/users_command.rb +15 -0
  70. data/lib/central/cli/master/vagrant/create_command.rb +25 -0
  71. data/lib/central/cli/master/vagrant/restart_command.rb +20 -0
  72. data/lib/central/cli/master/vagrant/ssh_command.rb +15 -0
  73. data/lib/central/cli/master/vagrant/start_command.rb +20 -0
  74. data/lib/central/cli/master/vagrant/stop_command.rb +20 -0
  75. data/lib/central/cli/master/vagrant/terminate_command.rb +13 -0
  76. data/lib/central/cli/master/vagrant_command.rb +21 -0
  77. data/lib/central/cli/master_command.rb +19 -0
  78. data/lib/central/cli/node_command.rb +30 -0
  79. data/lib/central/cli/nodes/add_label_command.rb +19 -0
  80. data/lib/central/cli/nodes/aws/create_command.rb +40 -0
  81. data/lib/central/cli/nodes/aws/restart_command.rb +29 -0
  82. data/lib/central/cli/nodes/aws/terminate_command.rb +21 -0
  83. data/lib/central/cli/nodes/aws_command.rb +14 -0
  84. data/lib/central/cli/nodes/azure/create_command.rb +40 -0
  85. data/lib/central/cli/nodes/azure/restart_command.rb +31 -0
  86. data/lib/central/cli/nodes/azure/terminate_command.rb +21 -0
  87. data/lib/central/cli/nodes/azure_command.rb +14 -0
  88. data/lib/central/cli/nodes/digital_ocean/create_command.rb +32 -0
  89. data/lib/central/cli/nodes/digital_ocean/restart_command.rb +27 -0
  90. data/lib/central/cli/nodes/digital_ocean/terminate_command.rb +19 -0
  91. data/lib/central/cli/nodes/digital_ocean_command.rb +14 -0
  92. data/lib/central/cli/nodes/label_command.rb +12 -0
  93. data/lib/central/cli/nodes/labels/add_command.rb +19 -0
  94. data/lib/central/cli/nodes/labels/remove_command.rb +23 -0
  95. data/lib/central/cli/nodes/list_command.rb +62 -0
  96. data/lib/central/cli/nodes/remove_command.rb +16 -0
  97. data/lib/central/cli/nodes/remove_label_command.rb +23 -0
  98. data/lib/central/cli/nodes/show_command.rb +49 -0
  99. data/lib/central/cli/nodes/ssh_command.rb +31 -0
  100. data/lib/central/cli/nodes/update_command.rb +20 -0
  101. data/lib/central/cli/nodes/vagrant/create_command.rb +27 -0
  102. data/lib/central/cli/nodes/vagrant/restart_command.rb +26 -0
  103. data/lib/central/cli/nodes/vagrant/ssh_command.rb +21 -0
  104. data/lib/central/cli/nodes/vagrant/start_command.rb +26 -0
  105. data/lib/central/cli/nodes/vagrant/stop_command.rb +26 -0
  106. data/lib/central/cli/nodes/vagrant/terminate_command.rb +17 -0
  107. data/lib/central/cli/nodes/vagrant_command.rb +20 -0
  108. data/lib/central/cli/register_command.rb +21 -0
  109. data/lib/central/cli/registry/create_command.rb +144 -0
  110. data/lib/central/cli/registry/delete_command.rb +22 -0
  111. data/lib/central/cli/registry/remove_command.rb +19 -0
  112. data/lib/central/cli/registry_command.rb +11 -0
  113. data/lib/central/cli/service_command.rb +49 -0
  114. data/lib/central/cli/services/add_env_command.rb +19 -0
  115. data/lib/central/cli/services/add_secret_command.rb +24 -0
  116. data/lib/central/cli/services/container_command.rb +8 -0
  117. data/lib/central/cli/services/containers_command.rb +32 -0
  118. data/lib/central/cli/services/create_command.rb +90 -0
  119. data/lib/central/cli/services/delete_command.rb +19 -0
  120. data/lib/central/cli/services/deploy_command.rb +21 -0
  121. data/lib/central/cli/services/env_command.rb +11 -0
  122. data/lib/central/cli/services/envs/add_command.rb +19 -0
  123. data/lib/central/cli/services/envs/list_command.rb +20 -0
  124. data/lib/central/cli/services/envs/remove_command.rb +18 -0
  125. data/lib/central/cli/services/envs_command.rb +20 -0
  126. data/lib/central/cli/services/link_command.rb +26 -0
  127. data/lib/central/cli/services/list_command.rb +42 -0
  128. data/lib/central/cli/services/logs_command.rb +57 -0
  129. data/lib/central/cli/services/monitor_command.rb +58 -0
  130. data/lib/central/cli/services/remove_command.rb +17 -0
  131. data/lib/central/cli/services/remove_env_command.rb +18 -0
  132. data/lib/central/cli/services/remove_secret_command.rb +28 -0
  133. data/lib/central/cli/services/restart_command.rb +17 -0
  134. data/lib/central/cli/services/scale_command.rb +17 -0
  135. data/lib/central/cli/services/secret_command.rb +9 -0
  136. data/lib/central/cli/services/secrets/link_command.rb +24 -0
  137. data/lib/central/cli/services/secrets/unlink_command.rb +28 -0
  138. data/lib/central/cli/services/services_helper.rb +360 -0
  139. data/lib/central/cli/services/show_command.rb +18 -0
  140. data/lib/central/cli/services/start_command.rb +17 -0
  141. data/lib/central/cli/services/stats_command.rb +74 -0
  142. data/lib/central/cli/services/stop_command.rb +17 -0
  143. data/lib/central/cli/services/unlink_command.rb +25 -0
  144. data/lib/central/cli/services/update_command.rb +78 -0
  145. data/lib/central/cli/stack_command.rb +32 -0
  146. data/lib/central/cli/stack_options.rb +11 -0
  147. data/lib/central/cli/stacks/add_user_command.rb +18 -0
  148. data/lib/central/cli/stacks/audit_log_command.rb +21 -0
  149. data/lib/central/cli/stacks/cloud_config_command.rb +41 -0
  150. data/lib/central/cli/stacks/common.rb +95 -0
  151. data/lib/central/cli/stacks/create_command.rb +26 -0
  152. data/lib/central/cli/stacks/current_command.rb +25 -0
  153. data/lib/central/cli/stacks/env_command.rb +32 -0
  154. data/lib/central/cli/stacks/list_command.rb +35 -0
  155. data/lib/central/cli/stacks/list_users_command.rb +26 -0
  156. data/lib/central/cli/stacks/logs_command.rb +81 -0
  157. data/lib/central/cli/stacks/remove_command.rb +26 -0
  158. data/lib/central/cli/stacks/remove_user_command.rb +17 -0
  159. data/lib/central/cli/stacks/show_command.rb +19 -0
  160. data/lib/central/cli/stacks/trusted_subnets/add_command.rb +16 -0
  161. data/lib/central/cli/stacks/trusted_subnets/list_command.rb +17 -0
  162. data/lib/central/cli/stacks/trusted_subnets/remove_command.rb +20 -0
  163. data/lib/central/cli/stacks/update_command.rb +27 -0
  164. data/lib/central/cli/stacks/use_command.rb +21 -0
  165. data/lib/central/cli/stacks/user_command.rb +11 -0
  166. data/lib/central/cli/stacks/users/add_command.rb +18 -0
  167. data/lib/central/cli/stacks/users/list_command.rb +18 -0
  168. data/lib/central/cli/stacks/users/remove_command.rb +17 -0
  169. data/lib/central/cli/user/forgot_password_command.rb +16 -0
  170. data/lib/central/cli/user/reset_password_command.rb +21 -0
  171. data/lib/central/cli/user/verify_command.rb +22 -0
  172. data/lib/central/cli/user_command.rb +12 -0
  173. data/lib/central/cli/vault/list_command.rb +25 -0
  174. data/lib/central/cli/vault/read_command.rb +17 -0
  175. data/lib/central/cli/vault/remove_command.rb +14 -0
  176. data/lib/central/cli/vault/update_command.rb +18 -0
  177. data/lib/central/cli/vault/write_command.rb +22 -0
  178. data/lib/central/cli/vault_command.rb +16 -0
  179. data/lib/central/cli/version.rb +5 -0
  180. data/lib/central/cli/version_command.rb +22 -0
  181. data/lib/central/cli/vpn/config_command.rb +25 -0
  182. data/lib/central/cli/vpn/create_command.rb +71 -0
  183. data/lib/central/cli/vpn/delete_command.rb +21 -0
  184. data/lib/central/cli/vpn/remove_command.rb +19 -0
  185. data/lib/central/cli/vpn_command.rb +13 -0
  186. data/lib/central/cli/whoami_command.rb +20 -0
  187. data/lib/central/client.rb +208 -0
  188. data/lib/central/errors.rb +10 -0
  189. data/lib/central/machine/aws.rb +14 -0
  190. data/lib/central/machine/aws/auth_provisioner.rb +161 -0
  191. data/lib/central/machine/aws/cloudinit.yml +71 -0
  192. data/lib/central/machine/aws/cloudinit_master.yml +118 -0
  193. data/lib/central/machine/aws/cloudinit_oauth.yml +76 -0
  194. data/lib/central/machine/aws/common.rb +31 -0
  195. data/lib/central/machine/aws/master_provisioner.rb +171 -0
  196. data/lib/central/machine/aws/node_destroyer.rb +46 -0
  197. data/lib/central/machine/aws/node_provisioner.rb +214 -0
  198. data/lib/central/machine/azure.rb +13 -0
  199. data/lib/central/machine/azure/cloudinit.yml +64 -0
  200. data/lib/central/machine/azure/cloudinit_master.yml +106 -0
  201. data/lib/central/machine/azure/logger.rb +26 -0
  202. data/lib/central/machine/azure/master_provisioner.rb +125 -0
  203. data/lib/central/machine/azure/node_destroyer.rb +52 -0
  204. data/lib/central/machine/azure/node_provisioner.rb +126 -0
  205. data/lib/central/machine/cert_helper.rb +39 -0
  206. data/lib/central/machine/cloud_config/cloudinit.yml +70 -0
  207. data/lib/central/machine/cloud_config/node_generator.rb +27 -0
  208. data/lib/central/machine/common.rb +16 -0
  209. data/lib/central/machine/digital_ocean.rb +13 -0
  210. data/lib/central/machine/digital_ocean/cloudinit.yml +64 -0
  211. data/lib/central/machine/digital_ocean/cloudinit_master.yml +118 -0
  212. data/lib/central/machine/digital_ocean/master_provisioner.rb +99 -0
  213. data/lib/central/machine/digital_ocean/node_destroyer.rb +40 -0
  214. data/lib/central/machine/digital_ocean/node_provisioner.rb +81 -0
  215. data/lib/central/machine/random_name.rb +39 -0
  216. data/lib/central/machine/vagrant.rb +12 -0
  217. data/lib/central/machine/vagrant/Vagrantfile.master.rb.erb +116 -0
  218. data/lib/central/machine/vagrant/Vagrantfile.node.rb.erb +32 -0
  219. data/lib/central/machine/vagrant/cloudinit.yml +73 -0
  220. data/lib/central/machine/vagrant/master_destroyer.rb +34 -0
  221. data/lib/central/machine/vagrant/master_provisioner.rb +79 -0
  222. data/lib/central/machine/vagrant/node_destroyer.rb +38 -0
  223. data/lib/central/machine/vagrant/node_provisioner.rb +68 -0
  224. data/lib/central/scripts/completer +157 -0
  225. data/lib/central/scripts/init +11 -0
  226. data/spec/central/cli/app/common_spec.rb +150 -0
  227. data/spec/central/cli/app/deploy_command_spec.rb +598 -0
  228. data/spec/central/cli/app/docker_helper_spec.rb +102 -0
  229. data/spec/central/cli/app/scale_spec.rb +49 -0
  230. data/spec/central/cli/common_spec.rb +117 -0
  231. data/spec/central/cli/login_command_spec.rb +31 -0
  232. data/spec/central/cli/master/current_command_spec.rb +55 -0
  233. data/spec/central/cli/master/use_command_spec.rb +37 -0
  234. data/spec/central/cli/master/users/invite_command_spec.rb +34 -0
  235. data/spec/central/cli/master/users/remove_command_spec.rb +26 -0
  236. data/spec/central/cli/master/users/roles/add_command_spec.rb +34 -0
  237. data/spec/central/cli/master/users/roles/remove_command_spec.rb +34 -0
  238. data/spec/central/cli/register_command_spec.rb +56 -0
  239. data/spec/central/cli/services/containers_command_spec.rb +40 -0
  240. data/spec/central/cli/services/link_command_spec.rb +38 -0
  241. data/spec/central/cli/services/restart_command_spec.rb +27 -0
  242. data/spec/central/cli/services/secrets/link_command_spec.rb +59 -0
  243. data/spec/central/cli/services/secrets/unlink_command_spec.rb +48 -0
  244. data/spec/central/cli/services/services_helper_spec.rb +170 -0
  245. data/spec/central/cli/services/unlink_command_spec.rb +38 -0
  246. data/spec/central/cli/stacks/trusted_subnets/add_command_spec.rb +37 -0
  247. data/spec/central/cli/stacks/trusted_subnets/list_command_spec.rb +30 -0
  248. data/spec/central/cli/stacks/trusted_subnets/remove_command_spec.rb +37 -0
  249. data/spec/central/cli/version_command_spec.rb +16 -0
  250. data/spec/fixtures/central.yml +17 -0
  251. data/spec/fixtures/docker-compose.yml +8 -0
  252. data/spec/fixtures/mysql.yml +3 -0
  253. data/spec/fixtures/wordpress-scaled.yml +3 -0
  254. data/spec/fixtures/wordpress.yml +2 -0
  255. data/spec/spec_helper.rb +27 -0
  256. data/spec/support/client_helpers.rb +30 -0
  257. data/spec/support/fixtures_helpers.rb +7 -0
  258. data/tasks/rspec.rake +5 -0
  259. metadata +463 -0
@@ -0,0 +1,42 @@
1
+ require_relative 'services_helper'
2
+ require 'tty'
3
+
4
+ module Central::Cli::Services
5
+ class ListCommand < Clamp::Command
6
+ include Central::Cli::Common
7
+ include Central::Cli::StackOptions
8
+ include ServicesHelper
9
+
10
+ def execute
11
+ require_api_url
12
+ token = require_token
13
+ stacks = client(token).get("stacks/#{current_stack}/services")
14
+ services = stacks['services'].sort_by { |s| s['updated_at'] }.reverse
15
+ header = ['Name', 'Instances', 'Stateful', 'State', 'Exposed Ports']
16
+ rows = []
17
+
18
+ services.each do |service|
19
+ stateful = service['stateful'] ? 'yes' : 'no'
20
+ running = service['instances']['running']
21
+ desired = service['container_count']
22
+ instances = "#{running} / #{desired}"
23
+ ports = service['ports'].map do|p|
24
+ "#{p['ip']}:#{p['node_port']}->#{p['container_port']}/#{p['protocol']}"
25
+ end.join(', ')
26
+ rows << [
27
+ service['name'],
28
+ instances,
29
+ stateful,
30
+ (service['state'] ? ' ✓ '.colorize(:green) : ' ✘ '.colorize(:red)),
31
+ ports
32
+ ]
33
+ end
34
+
35
+ ttable = TTY::Table.new header: header, rows: Array.new(rows)
36
+ renderer = TTY::Table::Renderer::Unicode.new(ttable)
37
+ renderer.border.style = :cyan
38
+ renderer.padding = [0, 1, 0, 1]
39
+ puts renderer.render
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,57 @@
1
+ require_relative 'services_helper'
2
+
3
+ module Central::Cli::Services
4
+ class LogsCommand < Clamp::Command
5
+ include Central::Cli::Common
6
+ include Central::Cli::StackOptions
7
+ include ServicesHelper
8
+
9
+ parameter 'NAME', 'Service name'
10
+ option ['-t', '--tail'], :flag, 'Tail (follow) logs', default: false
11
+ option ['-l', '--lines'], 'LINES', 'How many lines to show', default: '100'
12
+ option '--since', 'SINCE', 'Show logs since given timestamp'
13
+ option ['-i', '--instance'], 'INSTANCE', 'Show only given instance specific logs'
14
+
15
+ def execute
16
+ require_api_url
17
+ token = require_token
18
+ last_id = nil
19
+ loop do
20
+ query_params = []
21
+ query_params << "limit=#{lines}"
22
+ query_params << "from=#{last_id}" unless last_id.nil?
23
+ query_params << "since=#{since}" if !since.nil? && last_id.nil?
24
+ query_params << "container=#{name}-#{instance}" if instance
25
+
26
+ result = client(token).get("services/#{current_stack}/#{name}/container_logs?#{query_params.join('&')}")
27
+ result['logs'].each do |log|
28
+ color = color_for_container(log['name'])
29
+ instance_number = log['name'].match(/^.+-(\d+)$/)[1]
30
+ name = instance_number.nil? ? log['name'] : instance_number
31
+ prefix = "#{log['created_at']} [#{name}]:".colorize(color)
32
+ puts "#{prefix} #{log['data']}"
33
+ last_id = log['id']
34
+ end
35
+ break unless tail?
36
+ sleep(2)
37
+ end
38
+ end
39
+
40
+ def color_for_container(container_id)
41
+ color_maps[container_id] = colors.shift unless color_maps[container_id]
42
+ color_maps[container_id].to_sym
43
+ end
44
+
45
+ def color_maps
46
+ @color_maps ||= {}
47
+ end
48
+
49
+ def colors
50
+ if @colors.nil? || @colors.size == 0
51
+ @colors = [:green, :yellow, :magenta, :cyan, :red,
52
+ :light_green, :light_yellow, :ligh_magenta, :light_cyan, :light_red]
53
+ end
54
+ @colors
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,58 @@
1
+ require_relative 'services_helper'
2
+
3
+ module Central::Cli::Services
4
+ class MonitorCommand < Clamp::Command
5
+ include Central::Cli::Common
6
+ include Central::Cli::StackOptions
7
+ include ServicesHelper
8
+
9
+ parameter 'NAME', 'Service name'
10
+ option '--interval', 'SECONDS', 'How often view is refreshed', default: 2
11
+
12
+ def execute
13
+ require_api_url
14
+ token = require_token
15
+
16
+ loop do
17
+ nodes = {}
18
+ service = client(token).get("services/#{current_stack}/#{name}")
19
+ result = client(token).get("services/#{current_stack}/#{name}/containers")
20
+ result['containers'].each do |container|
21
+ nodes[container['node']['name']] ||= []
22
+ nodes[container['node']['name']] << container
23
+ end
24
+ clear_terminal
25
+ puts "service: #{name} (#{result['containers'].size}/#{service['container_count']} instances)"
26
+ puts "strategy: #{service['strategy']}"
27
+ puts "status: #{service['state']}"
28
+ puts "stateful: #{service['stateful'] == true ? 'yes' : 'no'}"
29
+ puts 'nodes:'
30
+ node_names = nodes.keys.sort
31
+ node_names.each do |name|
32
+ containers = nodes[name]
33
+ puts " #{name} (#{containers.size} instances)"
34
+ print ' '
35
+ containers.each do |container|
36
+ color = container['status']
37
+ color = if container['status'] == 'running'
38
+ :green
39
+ elsif container['status'] == 'killed'
40
+ :red
41
+ elsif container['status'] == 'stopped'
42
+ :gray
43
+ else
44
+ :yellow
45
+ end
46
+ print "■".colorize(color)
47
+ end
48
+ puts ''
49
+ end
50
+ sleep interval.to_f
51
+ end
52
+ end
53
+
54
+ def clear_terminal
55
+ print "\e[H\e[2J"
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,17 @@
1
+ require_relative 'services_helper'
2
+
3
+ module Central::Cli::Services
4
+ class RemoveCommand < Clamp::Command
5
+ include Central::Cli::Common
6
+ include ServicesHelper
7
+
8
+ parameter 'NAME', 'Service name'
9
+
10
+ def execute
11
+ require_api_url
12
+ token = require_token
13
+
14
+ result = client(token).delete("services/#{parse_service_id(name)}")
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'services_helper'
2
+
3
+ module Central::Cli::Services
4
+ class RemoveEnvCommand < Clamp::Command
5
+ include Central::Cli::Common
6
+ include Central::Cli::StackOptions
7
+ include ServicesHelper
8
+
9
+ parameter 'NAME', 'Service name'
10
+ parameter 'ENV', 'Environment variable name'
11
+
12
+ def execute
13
+ require_api_url
14
+ token = require_token
15
+ client(token).delete("services/#{parse_service_id(name)}/envs/#{env}")
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,28 @@
1
+ require_relative 'services_helper'
2
+
3
+ module Central::Cli::Services
4
+ class RemoveSecretCommand < Clamp::Command
5
+ include Central::Cli::Common
6
+ include Central::Cli::StackOptions
7
+ include 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
+ abort('Secret not found')
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ require_relative 'services_helper'
2
+
3
+ module Central::Cli::Services
4
+ class RestartCommand < Clamp::Command
5
+ include Central::Cli::Common
6
+ include Central::Cli::StackOptions
7
+ include ServicesHelper
8
+
9
+ parameter 'NAME', 'Service name'
10
+
11
+ def execute
12
+ require_api_url
13
+ token = require_token
14
+ restart_service(token, name)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ require_relative 'services_helper'
2
+
3
+ module Central::Cli::Services
4
+ class ScaleCommand < Clamp::Command
5
+ include Central::Cli::Common
6
+ include Central::Cli::StackOptions
7
+ include ServicesHelper
8
+
9
+ parameter 'NAME', 'Service name'
10
+ parameter 'INSTANCES', 'Scales service to given number of instances'
11
+
12
+ def execute
13
+ token = require_token
14
+ scale_service(token, name, instances)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ module Central::Cli::Services
2
+ require_relative 'secrets/link_command'
3
+ require_relative 'secrets/unlink_command'
4
+
5
+ class SecretCommand < Clamp::Command
6
+ subcommand 'link', 'Link secret from Vault', Secrets::LinkCommand
7
+ subcommand 'unlink', 'Unlink secret from Vault', Secrets::UnlinkCommand
8
+ end
9
+ end
@@ -0,0 +1,24 @@
1
+ require_relative '../services_helper'
2
+
3
+ module Central::Cli::Services::Secrets
4
+ class LinkCommand < Clamp::Command
5
+ include Central::Cli::Common
6
+ include Central::Cli::StackOptions
7
+ include Central::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
+ result = client(token).get("services/#{parse_service_id(name)}")
16
+ secrets = result['secrets']
17
+ secrets << parse_secrets([secret])[0]
18
+ data = {
19
+ secrets: secrets
20
+ }
21
+ client(token).put("services/#{parse_service_id(name)}", data)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,28 @@
1
+ require_relative '../services_helper'
2
+
3
+ module Central::Cli::Services::Secrets
4
+ class UnlinkCommand < Clamp::Command
5
+ include Central::Cli::Common
6
+ include Central::Cli::StackOptions
7
+ include Central::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
+ abort('Secret not found')
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,360 @@
1
+ require 'central/client'
2
+ require_relative '../common'
3
+ require 'shell-spinner'
4
+
5
+ module Central
6
+ module Cli
7
+ module Services
8
+ module ServicesHelper
9
+ include Central::Cli::Common
10
+
11
+ # @param [String] token
12
+ # @param [String] stack_id
13
+ # @param [Hash] data
14
+ def create_service(token, stack_id, data)
15
+ client(token).post("stacks/#{stack_id}/services", data)
16
+ end
17
+
18
+ # @param [String] token
19
+ # @param [String] service_id
20
+ # @param [Hash] data
21
+ def update_service(token, service_id, data)
22
+ param = parse_service_id(service_id)
23
+ client(token).put("services/#{param}", data)
24
+ end
25
+
26
+ # @param [String] token
27
+ # @param [String] service_id
28
+ # @param [Integer] instances
29
+ def scale_service(token, service_id, instances)
30
+ param = parse_service_id(service_id)
31
+ client(token).post("services/#{param}/scale", instances: instances)
32
+ end
33
+
34
+ # @param [String] token
35
+ # @param [String] service_id
36
+ def get_service(token, service_id)
37
+ param = parse_service_id(service_id)
38
+ client(token).get("services/#{param}")
39
+ end
40
+
41
+ # @param [String] token
42
+ # @param [String] service_id
43
+ def show_service(token, service_id)
44
+ service = get_service(token, service_id)
45
+ stack = service['id'].split('/')[0]
46
+ puts "#{service['id']}:"
47
+ puts " status: #{service['state']}"
48
+ puts " image: #{service['image']}"
49
+ puts " stateful: #{service['stateful'] == true ? 'yes' : 'no'}"
50
+ puts " scaling: #{service['container_count']}"
51
+ puts " strategy: #{service['strategy']}"
52
+ puts ' deploy_opts:'
53
+ puts " min_health: #{service['deploy_opts']['min_health']}"
54
+ if service['deploy_opts']['wait_for_port']
55
+ puts " wait_for_port: #{service['deploy_opts']['wait_for_port']}"
56
+ end
57
+ if service['deploy_opts']['interval']
58
+ puts " interval: #{service['deploy_opts']['interval']}"
59
+ end
60
+ puts " dns: #{service['name']}.#{stack}.central.local"
61
+
62
+ if service['affinity'].to_a.size > 0
63
+ puts ' affinity: '
64
+ service['affinity'].to_a.each do |a|
65
+ puts " - #{a}"
66
+ end
67
+ end
68
+
69
+ unless service['cmd'].to_s.empty?
70
+ if service['cmd']
71
+ puts " cmd: #{service['cmd'].join(' ')}"
72
+ else
73
+ puts ' cmd: '
74
+ end
75
+ end
76
+
77
+ if service['hooks'].to_a.size > 0
78
+ puts ' hooks: '
79
+ service['hooks'].to_a.each do |hook|
80
+ puts " - name: #{hook['name']}"
81
+ puts " type: #{hook['type']}"
82
+ puts " cmd: #{hook['cmd']}"
83
+ puts " oneshot: #{hook['oneshot']}"
84
+ end
85
+ end
86
+
87
+ if service['secrets'].to_a.size > 0
88
+ puts ' secrets: '
89
+ service['secrets'].to_a.each do |s|
90
+ puts " - secret: #{s['secret']}"
91
+ puts " name: #{s['name']}"
92
+ puts " type: #{s['type']}"
93
+ end
94
+ end
95
+
96
+ if service['env'].to_a.size > 0
97
+ puts ' env: '
98
+ service['env'].to_a.each do |e|
99
+ if e.length > 50
100
+ puts " - #{e[0..50]}..."
101
+ else
102
+ puts " - #{e}"
103
+ end
104
+ end
105
+ end
106
+
107
+ puts " net: #{service['net']}" unless service['net'].to_s.empty?
108
+
109
+ if service['ports'].to_a.size > 0
110
+ puts ' ports:'
111
+ service['ports'].to_a.each do |p|
112
+ puts " - #{p['node_port']}:#{p['container_port']}/#{p['protocol']}"
113
+ end
114
+ end
115
+
116
+ if service['volumes'].to_a.size > 0
117
+ puts ' volumes:'
118
+ service['volumes'].to_a.each do |v|
119
+ puts " - #{v}"
120
+ end
121
+ end
122
+
123
+ if service['volumes_from'].to_a.size > 0
124
+ puts ' volumes_from:'
125
+ service['volumes_from'].to_a.each do |v|
126
+ puts " - #{v}"
127
+ end
128
+ end
129
+
130
+ if service['links'].to_a.size > 0
131
+ puts ' links: '
132
+ service['links'].to_a.each do |l|
133
+ puts " - #{l['alias']}"
134
+ end
135
+ end
136
+
137
+ if service['cap_add'].to_a.size > 0
138
+ puts ' cap_add:'
139
+ service['cap_add'].to_a.each do |c|
140
+ puts " - #{c}"
141
+ end
142
+ end
143
+
144
+ if service['cap_drop'].to_a.size > 0
145
+ puts ' cap_drop:'
146
+ service['cap_drop'].to_a.each do |c|
147
+ puts " - #{c}"
148
+ end
149
+ end
150
+
151
+ unless service['log_driver'].to_s.empty?
152
+ puts " log_driver: #{service['log_driver']}"
153
+ puts ' log_opts:'
154
+ service['log_opts'].each do |opt, value|
155
+ puts " #{opt}: #{value}"
156
+ end
157
+ end
158
+
159
+ unless service['memory'].to_s.empty?
160
+ puts " memory: #{int_to_filesize(service['memory'])}"
161
+ end
162
+
163
+ unless service['memory_swap'].to_s.empty?
164
+ puts " memory_swap: #{int_to_filesize(service['memory_swap'])}"
165
+ end
166
+
167
+ puts " pid: #{service['pid']}" unless service['pid'].to_s.empty?
168
+
169
+ puts ' instances:'
170
+ result = client(token).get("services/#{parse_service_id(service_id)}/containers")
171
+ result['containers'].each do |container|
172
+ puts " #{container['name']}:"
173
+ puts " rev: #{container['deploy_rev']}"
174
+ puts " node: #{begin
175
+ container['node']['name']
176
+ rescue
177
+ 'unknown'
178
+ end}"
179
+ puts " dns: #{container['name']}.#{stack}.central.local"
180
+ puts " ip: #{container['overlay_cidr'].to_s.split('/')[0]}"
181
+ puts " public ip: #{begin
182
+ container['node']['public_ip']
183
+ rescue
184
+ 'unknown'
185
+ end}"
186
+ if container['status'] == 'unknown'
187
+ puts " status: #{container['status'].colorize(:yellow)}"
188
+ else
189
+ puts " status: #{container['status']}"
190
+ end
191
+ if container['state']['error'] && container['state']['error'] != ''
192
+ puts " reason: #{container['state']['error']}"
193
+ end
194
+ end
195
+ end
196
+
197
+ # @param [String] token
198
+ # @param [String] service_id
199
+ # @param [Hash] data
200
+ def deploy_service(token, service_id, data)
201
+ param = parse_service_id(service_id)
202
+ client(token).post("services/#{param}/deploy", data)
203
+ end
204
+
205
+ # @param [String] token
206
+ # @param [String] name
207
+ def wait_for_deploy_to_finish(token, name)
208
+ ShellSpinner ' ' do
209
+ until client(token).get("services/#{name}")['state'] != 'deploying'
210
+ sleep 1
211
+ end
212
+ end
213
+ end
214
+
215
+ # @param [String] token
216
+ # @param [String] service_id
217
+ def start_service(token, service_id)
218
+ param = parse_service_id(service_id)
219
+ client(token).post("services/#{param}/start", {})
220
+ end
221
+
222
+ # @param [String] token
223
+ # @param [String] service_id
224
+ def stop_service(token, service_id)
225
+ param = parse_service_id(service_id)
226
+ client(token).post("services/#{param}/stop", {})
227
+ end
228
+
229
+ # @param [String] token
230
+ # @param [String] service_id
231
+ def restart_service(token, service_id)
232
+ param = parse_service_id(service_id)
233
+ client(token).post("services/#{param}/restart", {})
234
+ end
235
+
236
+ # @param [String] token
237
+ # @param [String] service_id
238
+ def delete_service(token, service_id)
239
+ param = parse_service_id(service_id)
240
+ client(token).delete("services/#{param}")
241
+ end
242
+
243
+ # @param [String] service_id
244
+ # @return [String]
245
+ def parse_service_id(service_id)
246
+ param = if service_id.to_s.include?('/')
247
+ service_id
248
+ else
249
+ "#{current_stack}/#{service_id}"
250
+ end
251
+ end
252
+
253
+ # @param [Array<String>] port_options
254
+ # @return [Array<Hash>]
255
+ def parse_ports(port_options)
256
+ port_options.map do|p|
257
+ node_port, container_port, protocol = p.split(':')
258
+ if node_port.nil? || container_port.nil?
259
+ fail ArgumentError.new("Invalid port value #{p}")
260
+ end
261
+ {
262
+ container_port: container_port,
263
+ node_port: node_port,
264
+ protocol: protocol || 'tcp'
265
+ }
266
+ end
267
+ end
268
+
269
+ # @param [Array<String>] link_options
270
+ # @return [Array<Hash>]
271
+ def parse_links(link_options)
272
+ link_options.map do|l|
273
+ service_name, alias_name = l.split(':')
274
+ if service_name.nil?
275
+ fail ArgumentError.new("Invalid link value #{l}")
276
+ end
277
+ alias_name = service_name if alias_name.nil?
278
+ {
279
+ name: service_name,
280
+ alias: alias_name
281
+ }
282
+ end
283
+ end
284
+
285
+ # @param [String] memory
286
+ # @return [Integer]
287
+ def parse_memory(memory)
288
+ if memory.end_with?('k')
289
+ memory.to_i * 1024
290
+ elsif memory.end_with?('m')
291
+ memory.to_i * 1024 * 1024
292
+ elsif memory.end_with?('g')
293
+ memory.to_i * 1024 * 1024 * 1024
294
+ else
295
+ memory.to_i
296
+ end
297
+ end
298
+
299
+ # @param [String] image
300
+ # @return [String]
301
+ def parse_image(image)
302
+ image = "#{image}:latest" unless image.include?(':')
303
+ image
304
+ end
305
+
306
+ ##
307
+ # @param [Array] log_opts
308
+ # @return [Hash]
309
+ def parse_log_opts(log_opts)
310
+ opts = {}
311
+ log_opts.each do |opt|
312
+ key, value = opt.split('=')
313
+ opts[key] = value
314
+ end
315
+ opts
316
+ end
317
+
318
+ # @param [Array<String>] secret_opts
319
+ # @return [Array<Hash>]
320
+ def parse_secrets(secret_opts)
321
+ secrets = []
322
+ secret_opts.each do |s|
323
+ secret, name, type = s.split(':')
324
+ secrets << { secret: secret, name: name, type: type }
325
+ end
326
+ secrets
327
+ end
328
+
329
+ # @param [String] time
330
+ # @return [Integer, NilClass]
331
+ def parse_relative_time(time)
332
+ if time.end_with?('min')
333
+ time.to_i * 60
334
+ elsif time.end_with?('h')
335
+ time.to_i * 60 * 60
336
+ elsif time.end_with?('d')
337
+ time.to_i * 60 * 60 * 24
338
+ else
339
+ time = time.to_i
340
+ if time == 0
341
+ nil
342
+ else
343
+ time
344
+ end
345
+ end
346
+ end
347
+
348
+ def int_to_filesize(int)
349
+ {
350
+ 'B' => 1000,
351
+ 'KB' => 1000 * 1000,
352
+ 'MB' => 1000 * 1000 * 1000,
353
+ 'GB' => 1000 * 1000 * 1000 * 1000,
354
+ 'TB' => 1000 * 1000 * 1000 * 1000 * 1000
355
+ }.each_pair { |e, s| return "#{(int.to_i / (s / 1000))}#{e}" if int < s }
356
+ end
357
+ end
358
+ end
359
+ end
360
+ end