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,29 @@
1
+ require_relative 'apps/init_command'
2
+ require_relative 'apps/build_command'
3
+ require_relative 'apps/deploy_command'
4
+ require_relative 'apps/start_command'
5
+ require_relative 'apps/stop_command'
6
+ require_relative 'apps/restart_command'
7
+ require_relative 'apps/remove_command'
8
+ require_relative 'apps/list_command'
9
+ require_relative 'apps/logs_command'
10
+ require_relative 'apps/monitor_command'
11
+ require_relative 'apps/show_command'
12
+ require_relative 'apps/scale_command'
13
+
14
+ class Central::Cli::AppCommand < Clamp::Command
15
+ subcommand 'init', 'Init Central application', Central::Cli::Apps::InitCommand
16
+ subcommand 'build', 'Build Central services', Central::Cli::Apps::BuildCommand
17
+ subcommand 'deploy', 'Deploy Central services', Central::Cli::Apps::DeployCommand
18
+ subcommand 'scale', 'Scale services', Central::Cli::Apps::ScaleCommand
19
+ subcommand 'start', 'Start services', Central::Cli::Apps::StartCommand
20
+ subcommand 'stop', 'Stop services', Central::Cli::Apps::StopCommand
21
+ subcommand 'restart', 'Restart services', Central::Cli::Apps::RestartCommand
22
+ subcommand 'show', 'Show service details', Central::Cli::Apps::ShowCommand
23
+ subcommand %w(ps list ls), 'List services', Central::Cli::Apps::ListCommand
24
+ subcommand ['logs'], 'Show service logs', Central::Cli::Apps::LogsCommand
25
+ subcommand 'monitor', 'Monitor services', Central::Cli::Apps::MonitorCommand
26
+ subcommand %w(remove rm), 'Remove services', Central::Cli::Apps::RemoveCommand
27
+ def execute
28
+ end
29
+ end
@@ -0,0 +1,24 @@
1
+ require_relative 'common'
2
+ require_relative 'docker_helper'
3
+
4
+ module Central::Cli::Apps
5
+ class BuildCommand < Clamp::Command
6
+ include Central::Cli::Common
7
+ include Common
8
+ include DockerHelper
9
+
10
+ option ['-p', '--project-name'], 'NAME', 'Specify an alternate project name (default: directory name)'
11
+ option ['-f', '--file'], 'FILE', 'Specify an alternate Central compose file', attribute_name: :filename, default: 'central.yml'
12
+ option ['--no-cache'], :flag, 'Do not use cache when building the image', default: false
13
+ parameter '[SERVICE] ...', 'Services to build'
14
+
15
+ attr_reader :services, :service_prefix
16
+
17
+ def execute
18
+ require_config_file(filename)
19
+ @service_prefix = project_name || current_dir
20
+ @services = load_services(filename, service_list, service_prefix)
21
+ process_docker_images(services, true, no_cache?)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,88 @@
1
+ require 'yaml'
2
+ require_relative 'common'
3
+
4
+ module Central::Cli::Apps
5
+ class CentralYmlGenerator
6
+ include Common
7
+
8
+ attr_reader :image_name, :service_prefix
9
+
10
+ def initialize(image_name, service_prefix)
11
+ @image_name = image_name
12
+ @service_prefix = service_prefix
13
+ end
14
+
15
+ def generate_from_compose_file(docker_compose_file)
16
+ services = {}
17
+ # extend services from docker-compose.yml
18
+ file = File.read(docker_compose_file)
19
+ compose_services = YAML.load(file)
20
+ compose_services.each do |name, options|
21
+ services[name] = { 'extends' => { 'file' => 'docker-compose.yml', 'service' => name } }
22
+ if options.key?('build')
23
+ image = image_name || "registry.central.local/#{File.basename(Dir.getwd)}:latest"
24
+ services[name]['image'] = image
25
+ end
26
+
27
+ # set Heroku addon service as stateful by default
28
+ services[name]['stateful'] = true if valid_addons.key?(name)
29
+
30
+ # we have to generate Central urls to env vars for Heroku addons
31
+ # redis://openredis:6379 -> redis://project-name-openredis:6379
32
+ next unless options['links']
33
+ options['links'].each do |link|
34
+ service_link = link.split(':').first
35
+ if valid_addons.key?(service_link)
36
+ services[name]['environment'] ||= []
37
+ services[name]['environment'] += valid_addons(service_prefix)[service_link]['environment']
38
+ end
39
+ end
40
+ end
41
+ create_yml(services, 'central.yml')
42
+ end
43
+
44
+ def generate(procfile, addons, env_file)
45
+ image = image_name || "registry.central.local/#{File.basename(Dir.getwd)}:latest"
46
+ if procfile.keys.size > 0
47
+ # generate services found in Procfile
48
+ services = {}
49
+ procfile.keys.each do |name|
50
+ services[name] = { 'image' => image }
51
+ services[name]['environment'] = ['PORT=5000'] if app_json && name == 'web' # Heroku generates PORT env variable so should we do too
52
+ services[name]['command'] = "/start #{name}" if name != 'web'
53
+ services[name]['env_file'] = env_file if env_file
54
+
55
+ # generate addon services
56
+ addons.each do |addon|
57
+ addon_service = addon.split(':')[0]
58
+ addon_service.slice!('heroku-')
59
+ next unless valid_addons.key?(addon_service)
60
+ services[name]['links'] ||= []
61
+ services[name]['links'] << "#{addon_service}:#{addon_service}"
62
+ services[name]['environment'] ||= []
63
+ services[name]['environment'] += valid_addons(service_prefix)[addon_service]['environment']
64
+ services[addon_service] = { 'image' => valid_addons[addon_service]['image'], 'stateful' => true }
65
+ end
66
+ end
67
+ else
68
+ # no Procfile found, create dummy web service
69
+ services = { 'web' => { 'image' => image } }
70
+ services['web']['env_file'] = env_file if env_file
71
+ end
72
+ # create central.yml file
73
+ create_yml(services, 'central.yml')
74
+ end
75
+
76
+ def create_yml(services, filename)
77
+ if File.exist?(filename)
78
+ central_services = YAML.load(File.read(filename))
79
+ services.each do |name, _options|
80
+ if central_services[name]
81
+ services[name].merge!(central_services[name])
82
+ end
83
+ end
84
+ end
85
+ super(services, filename)
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,166 @@
1
+ require 'yaml'
2
+ require_relative '../services/services_helper'
3
+
4
+ module Central::Cli::Apps
5
+ module Common
6
+ include Central::Cli::Services::ServicesHelper
7
+
8
+ def require_config_file(filename)
9
+ abort("File #{filename} does not exist") unless File.exist?(filename)
10
+ end
11
+
12
+ # @param [String] filename
13
+ # @param [Array<String>] service_list
14
+ # @param [String] prefix
15
+ # @return [Hash]
16
+ def load_services(filename, service_list, prefix)
17
+ services = parse_services(filename, nil, prefix)
18
+ services.delete_if { |name, _service| !service_list.include?(name) } unless service_list.empty?
19
+ services
20
+ end
21
+
22
+ # @return [String]
23
+ def token
24
+ @token ||= require_token
25
+ end
26
+
27
+ # @param [String] name
28
+ # @return [String]
29
+ def prefixed_name(name)
30
+ return name if service_prefix.strip == ''
31
+
32
+ "#{service_prefix}-#{name}"
33
+ end
34
+
35
+ # @return [String]
36
+ def current_dir
37
+ File.basename(Dir.getwd)
38
+ end
39
+
40
+ # @param [String] name
41
+ # @return [Boolean]
42
+ def service_exists?(name)
43
+ get_service(token, prefixed_name(name))
44
+ rescue
45
+ false
46
+ end
47
+
48
+ # @param [String] file
49
+ # @param [String,NilClass] name
50
+ # @param [String] prefix
51
+ # @return [Hash]
52
+ def parse_services(file, name = nil, prefix = '')
53
+ services = YAML.load(File.read(File.expand_path(file)) % { project: prefix, stack: current_stack })
54
+ Dir.chdir(File.dirname(File.expand_path(file))) do
55
+ services.each do |name, options|
56
+ normalize_env_vars(options)
57
+ next unless options.key?('extends')
58
+ extension_file = options['extends']['file']
59
+ service_name = options['extends']['service']
60
+ options.delete('extends')
61
+ services[name] = extend_options(options, extension_file, service_name, prefix)
62
+ end
63
+ end
64
+ if name.nil?
65
+ services
66
+ else
67
+ abort("Service #{name} not found in #{file}") unless services.key?(name)
68
+ services[name]
69
+ end
70
+ end
71
+
72
+ # @param [Hash] options
73
+ # @param [String] file
74
+ # @param [String] service_name
75
+ # @param [String] prefix
76
+ # @return [Hash]
77
+ def extend_options(options, file, service_name, prefix)
78
+ parent_options = parse_services(file, service_name, prefix)
79
+ options['environment'] = extend_env_vars(parent_options['environment'], options['environment'])
80
+ options['secrets'] = extend_secrets(parent_options['secrets'], options['secrets'])
81
+ parent_options.merge(options)
82
+ end
83
+
84
+ # @param [Hash] options
85
+ def normalize_env_vars(options)
86
+ if options['environment'].is_a?(Hash)
87
+ options['environment'] = options['environment'].map { |k, v| "#{k}=#{v}" }
88
+ end
89
+ end
90
+
91
+ # @param [Array] from
92
+ # @param [Array] to
93
+ # @return [Array]
94
+ def extend_env_vars(from, to)
95
+ env_vars = to || []
96
+ if from
97
+ from.each do |env|
98
+ env_vars << env unless to && to.find { |key| key.split('=').first == env.split('=').first }
99
+ end
100
+ end
101
+ env_vars
102
+ end
103
+
104
+ # @param [Array] from
105
+ # @param [Array] to
106
+ # @return [Array]
107
+ def extend_secrets(from, to)
108
+ secrets = to || []
109
+ if from
110
+ from.each do |from_secret|
111
+ secrets << from_secret unless to && to.any? { |to_secret| to_secret['secret'] == from_secret['secret'] }
112
+ end
113
+ end
114
+ secrets
115
+ end
116
+
117
+ # @param [Hash] services
118
+ # @param [String] file
119
+ def create_yml(services, file = 'central.yml')
120
+ yml = File.new(file, 'w')
121
+ yml.puts services.to_yaml
122
+ yml.close
123
+ end
124
+
125
+ # @return [Hash]
126
+ def app_json
127
+ @app_json = if !@app_json && File.exist?('app.json')
128
+ JSON.parse(File.read('app.json'))
129
+ else
130
+ {}
131
+ end
132
+ @app_json
133
+ end
134
+
135
+ def valid_addons(prefix = nil)
136
+ prefix = "#{prefix}-" if prefix
137
+
138
+ {
139
+ 'openredis' => {
140
+ 'image' => 'redis:latest',
141
+ 'environment' => ["REDIS_URL=redis://#{prefix}openredis:6379"]
142
+ },
143
+ 'redis' => {
144
+ 'image' => 'redis:latest',
145
+ 'environment' => ["REDIS_URL=redis://#{prefix}redis:6379"]
146
+ },
147
+ 'rediscloud' => {
148
+ 'image' => 'redis:latest',
149
+ 'environment' => ["REDISCLOUD_URL=redis://#{prefix}rediscloud:6379"]
150
+ },
151
+ 'postgresql' => {
152
+ 'image' => 'postgres:latest',
153
+ 'environment' => ["DATABASE_URL=postgres://#{prefix}postgres:@postgresql:5432/postgres"]
154
+ },
155
+ 'mongolab' => {
156
+ 'image' => 'mongo:latest',
157
+ 'environment' => ["MONGOLAB_URI=#{prefix}mongolab:27017"]
158
+ },
159
+ 'memcachedcloud' => {
160
+ 'image' => 'memcached:latest',
161
+ 'environment' => ["MEMCACHEDCLOUD_SERVERS=#{prefix}memcachedcloud:11211"]
162
+ }
163
+ }
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,191 @@
1
+ require 'yaml'
2
+ require_relative 'common'
3
+ require_relative 'docker_helper'
4
+
5
+ module Central::Cli::Apps
6
+ class DeployCommand < Clamp::Command
7
+ include Central::Cli::Common
8
+ include Central::Cli::StackOptions
9
+ include Common
10
+ include DockerHelper
11
+
12
+ option ['-f', '--file'], 'FILE', 'Specify an alternate Central compose file', attribute_name: :filename, default: 'central.yml'
13
+ option ['--no-build'], :flag, 'Don\'t build an image, even if it\'s missing', default: false
14
+ option ['-p', '--project-name'], 'NAME', 'Specify an alternate project name (default: directory name)'
15
+ option '--async', :flag, 'Run deploys async/parallel'
16
+ option '--force-deploy', :flag, 'Force deploy even if service does not have any changes'
17
+
18
+ parameter '[SERVICE] ...', 'Services to start'
19
+
20
+ attr_reader :services, :service_prefix, :deploy_queue
21
+
22
+ def execute
23
+ require_api_url
24
+ require_token
25
+ require_config_file(filename)
26
+ @deploy_queue = []
27
+ @service_prefix = project_name || current_dir
28
+ @services = load_services(filename, service_list, service_prefix)
29
+ process_docker_images(services) unless no_build?
30
+ create_or_update_services(services)
31
+ deploy_services(deploy_queue)
32
+ end
33
+
34
+ private
35
+
36
+ # @param [Hash] services
37
+ def create_or_update_services(services)
38
+ services.each do |name, config|
39
+ create_or_update_service(name, config)
40
+ end
41
+ end
42
+
43
+ # @param [Array] queue
44
+ def deploy_services(queue)
45
+ queue.each do |service|
46
+ name = service['id'].split('/').last
47
+ options = {}
48
+ options[:force] = true if force_deploy?
49
+ deploy_service(token, name, options)
50
+ print "deploying #{name.sub("#{service_prefix}-", '').colorize(:cyan)}"
51
+ unless async?
52
+ wait_for_deploy_to_finish(token, service['id'])
53
+ else
54
+ puts ''
55
+ end
56
+ end
57
+ end
58
+
59
+ # @param [String] name
60
+ # @param [Hash] options
61
+ def create_or_update_service(name, options)
62
+ # skip if service is already processed or it's not present
63
+ return nil if in_deploy_queue?(name) || !services.keys.include?(name)
64
+
65
+ # create/update linked services recursively before continuing
66
+ unless options['links'].nil?
67
+ parse_links(options['links']).each_with_index do |linked_service, index|
68
+ # change prefixed service name also to links options
69
+ options['links'][index] = "#{prefixed_name(linked_service[:name])}:#{linked_service[:alias]}"
70
+ create_or_update_service(linked_service[:name], services[linked_service[:name]]) unless in_deploy_queue?(linked_service[:name])
71
+ end
72
+ end
73
+
74
+ merge_external_links(options)
75
+ merge_env_vars(options)
76
+
77
+ service = if service_exists?(name)
78
+ update(name, options)
79
+ else
80
+ create(name, options)
81
+ end
82
+
83
+ deploy_queue.push service
84
+ end
85
+
86
+ # @param [String] name
87
+ def find_service_by_name(name)
88
+ get_service(token, prefixed_name(name))
89
+ rescue
90
+ nil
91
+ end
92
+
93
+ # @param [String] name
94
+ # @param [Hash] options
95
+ def create(name, options)
96
+ puts "creating #{name.colorize(:cyan)}"
97
+ name = prefixed_name(name)
98
+ data = { name: name }
99
+ data.merge!(parse_data(options))
100
+ create_service(token, current_stack, data)
101
+ end
102
+
103
+ # @param [String] id
104
+ # @param [Hash] options
105
+ def update(id, options)
106
+ puts "updating #{id.colorize(:cyan)}"
107
+ id = prefixed_name(id)
108
+ data = parse_data(options)
109
+ update_service(token, id, data)
110
+ end
111
+
112
+ # @param [String] name
113
+ def in_deploy_queue?(name)
114
+ deploy_queue.find { |service| service['name'] == prefixed_name(name) } != nil
115
+ end
116
+
117
+ # @param [Hash] options
118
+ def merge_env_vars(options)
119
+ return unless options['env_file']
120
+
121
+ options['env_file'] = [options['env_file']] if options['env_file'].is_a?(String)
122
+ options['environment'] = [] unless options['environment']
123
+
124
+ options['env_file'].each do |env_file|
125
+ options['environment'].concat(read_env_file(env_file))
126
+ end
127
+
128
+ options['environment'].uniq! { |s| s.split('=').first }
129
+ end
130
+
131
+ # @param [Hash] options
132
+ def merge_external_links(options)
133
+ if options['external_links']
134
+ options['links'] ||= []
135
+ options['links'] = options['links'] + options['external_links']
136
+ options.delete('external_links')
137
+ end
138
+ end
139
+
140
+ # @param [String] path
141
+ def read_env_file(path)
142
+ File.readlines(path).delete_if { |line| line.start_with?('#') || line.empty? }
143
+ end
144
+
145
+ ##
146
+ # @param [Hash] options
147
+ def parse_data(options)
148
+ data = {}
149
+ data[:image] = parse_image(options['image'])
150
+ data[:env] = options['environment']
151
+ data[:container_count] = options['instances']
152
+ data[:links] = parse_links(options['links'] || [])
153
+ data[:ports] = parse_ports(options['ports'] || [])
154
+ data[:memory] = parse_memory(options['mem_limit'].to_s) if options['mem_limit']
155
+ data[:memory_swap] = parse_memory(options['memswap_limit'].to_s) if options['memswap_limit']
156
+ data[:cpu_shares] = options['cpu_shares'] if options['cpu_shares']
157
+ data[:volumes] = options['volumes'] || []
158
+ data[:volumes_from] = options['volumes_from'] || []
159
+ data[:cmd] = options['command'].split(' ') if options['command']
160
+ data[:affinity] = options['affinity'] || []
161
+ data[:user] = options['user'] if options['user']
162
+ data[:stateful] = options['stateful'] == true
163
+ data[:privileged] = options['privileged'] unless options['privileged'].nil?
164
+ data[:cap_add] = options['cap_add'] if options['cap_add']
165
+ data[:cap_drop] = options['cap_drop'] if options['cap_drop']
166
+ data[:net] = options['net'] if options['net']
167
+ data[:pid] = options['pid'] if options['pid']
168
+ data[:log_driver] = options['log_driver'] if options['log_driver']
169
+ data[:log_opts] = options['log_opt'] if options['log_opt'] && !options['log_opt'].empty?
170
+
171
+ deploy_opts = options['deploy'] || {}
172
+ data[:strategy] = deploy_opts['strategy'] if deploy_opts['strategy']
173
+ deploy = {}
174
+ if deploy_opts.key?('wait_for_port')
175
+ deploy[:wait_for_port] = deploy_opts['wait_for_port']
176
+ end
177
+ if deploy_opts.key?('min_health')
178
+ deploy[:min_health] = deploy_opts['min_health']
179
+ end
180
+ if deploy_opts.key?('interval')
181
+ deploy[:interval] = parse_relative_time(deploy_opts['interval'])
182
+ end
183
+ data[:deploy_opts] = deploy unless deploy.empty?
184
+
185
+ data[:hooks] = options['hooks'] || {}
186
+ data[:secrets] = options['secrets'] if options['secrets']
187
+
188
+ data
189
+ end
190
+ end
191
+ end