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,31 @@
1
+ module Central
2
+ module Machine
3
+ module Aws
4
+ module Common
5
+ # @param [String] region
6
+ # @return String
7
+ def resolve_ami(region)
8
+ response = Excon.get('https://coreos.com/dist/aws/aws-stable.json')
9
+ images = JSON.parse(response.body)
10
+ info = images[region]
11
+ info ? info['hvm'] : nil
12
+ end
13
+
14
+ # @param [String] vpc_id
15
+ # @param [String] zone
16
+ # @return [Aws::EC2::Types::Subnet, NilClass]
17
+ def default_subnet(vpc_id, zone)
18
+ ec2.subnets(filters: [
19
+ { name: 'vpc-id', values: [vpc_id] },
20
+ { name: 'availability-zone', values: [zone] }
21
+ ]).first
22
+ end
23
+
24
+ # @return [Aws::EC2::Types::Vpc, NilClass]
25
+ def default_vpc
26
+ ec2.vpcs(filters: [{ name: 'is-default', values: ['true'] }]).first
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,171 @@
1
+ require 'fileutils'
2
+ require 'erb'
3
+ require 'open3'
4
+ require 'shell-spinner'
5
+ require_relative 'common'
6
+
7
+ module Central
8
+ module Machine
9
+ module Aws
10
+ class MasterProvisioner
11
+ include RandomName
12
+ include Common
13
+ include Machine::CertHelper
14
+ attr_reader :ec2, :http_client, :region
15
+
16
+ # @param [String] access_key_id aws_access_key_id
17
+ # @param [String] secret_key aws_secret_access_key
18
+ # @param [String] region
19
+ def initialize(access_key_id, secret_key, region)
20
+ @ec2 = ::Aws::EC2::Resource.new(
21
+ region: region,
22
+ credentials: ::Aws::Credentials.new(access_key_id, secret_key)
23
+ )
24
+ end
25
+
26
+ # @param [Hash] opts
27
+ def run!(opts)
28
+ ssl_cert = nil
29
+ if opts[:ssl_cert]
30
+ unless File.exist?(File.expand_path(opts[:ssl_cert]))
31
+ abort('Invalid ssl cert')
32
+ end
33
+ ssl_cert = File.read(File.expand_path(opts[:ssl_cert]))
34
+ else
35
+ ShellSpinner 'Generating self-signed SSL certificate' do
36
+ ssl_cert = generate_self_signed_cert
37
+ end
38
+ end
39
+
40
+ ami = resolve_ami(region)
41
+ abort('No valid AMI found for region') unless ami
42
+ opts[:vpc] = default_vpc.vpc_id unless opts[:vpc]
43
+ subnet = if opts[:subnet].nil?
44
+ default_subnet(opts[:vpc], region + opts[:zone])
45
+ else
46
+ ec2.subnet(opts[:subnet])
47
+ end
48
+ userdata_vars = {
49
+ ssl_cert: ssl_cert,
50
+ auth_server: opts[:auth_server],
51
+ version: opts[:version],
52
+ vault_secret: opts[:vault_secret],
53
+ vault_iv: opts[:vault_iv],
54
+ mongodb_uri: opts[:mongodb_uri]
55
+ }
56
+
57
+ security_group = ensure_security_group(opts[:vpc])
58
+ name = generate_name
59
+ ec2_instance = ec2.create_instances(
60
+ image_id: ami,
61
+ min_count: 1,
62
+ max_count: 1,
63
+ instance_type: opts[:type],
64
+ security_group_ids: [security_group.group_id],
65
+ key_name: opts[:key_pair],
66
+ subnet_id: subnet.subnet_id,
67
+ user_data: Base64.encode64(user_data(userdata_vars)),
68
+ block_device_mappings: [
69
+ {
70
+ device_name: '/dev/xvda',
71
+ virtual_name: 'Root',
72
+ ebs: {
73
+ volume_size: opts[:storage],
74
+ volume_type: 'gp2'
75
+ }
76
+ }
77
+ ]
78
+ ).first
79
+ ec2_instance.create_tags(tags: [{ key: 'Name', value: name }])
80
+ ShellSpinner "Creating AWS instance #{name.colorize(:cyan)} " do
81
+ sleep 5 until ec2_instance.reload.state.name == 'running'
82
+ end
83
+ master_url = "https://#{ec2_instance.public_ip_address}"
84
+ Excon.defaults[:ssl_verify_peer] = false
85
+ http_client = Excon.new(master_url, connect_timeout: 10)
86
+ ShellSpinner "Waiting for #{name.colorize(:cyan)} to start " do
87
+ sleep 5 until master_running?(http_client)
88
+ end
89
+
90
+ puts "Central Machine is now running at #{master_url}"
91
+ puts "Use #{"cm login --name=#{name.sub('central-machine-', '')} #{master_url}".colorize(:yellow)} to complete Central Machine setup"
92
+ end
93
+
94
+ # @param [String] vpc_id
95
+ # @return [Aws::EC2::SecurityGroup]
96
+ def ensure_security_group(vpc_id)
97
+ group_name = 'central_machine'
98
+ sg = ec2.security_groups(
99
+ filters: [
100
+ { name: 'group-name', values: [group_name] },
101
+ { name: 'vpc-id', values: [vpc_id] }
102
+ ]
103
+ ).first
104
+ unless sg
105
+ ShellSpinner 'Creating AWS security group' do
106
+ sg = create_security_group(group_name, vpc_id)
107
+ end
108
+ end
109
+ sg
110
+ end
111
+
112
+ # creates security_group and authorizes default port ranges
113
+ #
114
+ # @param [String] name
115
+ # @param [String, NilClass] vpc_id
116
+ # @return Aws::EC2::SecurityGroup
117
+ def create_security_group(name, vpc_id = nil)
118
+ sg = ec2.create_security_group(
119
+ group_name: name,
120
+ description: 'Central Machine',
121
+ vpc_id: vpc_id)
122
+ sg.create_tags(tags: [
123
+ { key: 'Name', value: name }
124
+ ])
125
+ sg.authorize_ingress( # SSHD
126
+ ip_protocol: 'tcp',
127
+ from_port: 22,
128
+ to_port: 22,
129
+ cidr_ip: '24.7.32.100/32')
130
+ sg.authorize_ingress( # HTTPS
131
+ ip_protocol: 'tcp',
132
+ from_port: 443,
133
+ to_port: 443,
134
+ cidr_ip: '0.0.0.0/0')
135
+ sg.authorize_ingress( # OAUTH
136
+ ip_protocol: 'tcp',
137
+ from_port: 5000,
138
+ to_port: 5000,
139
+ cidr_ip: '24.7.32.100/32')
140
+ sg
141
+ end
142
+
143
+ # @return [String]
144
+ def region
145
+ ec2.client.config.region
146
+ end
147
+
148
+ def user_data(vars)
149
+ cloudinit_template = File.join(__dir__, '/cloudinit_master.yml')
150
+ erb(File.read(cloudinit_template), vars)
151
+ end
152
+
153
+ def generate_name
154
+ "central-machine-#{super}-#{rand(1..9)}"
155
+ end
156
+
157
+ def master_running?(http_client)
158
+ http_client.get(path: '/').status == 200
159
+ rescue
160
+ false
161
+ end
162
+
163
+ def erb(template, vars)
164
+ ERB.new(template, nil, '%<>-').result(
165
+ OpenStruct.new(vars).instance_eval { binding }
166
+ )
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,46 @@
1
+ require 'shell-spinner'
2
+
3
+ module Central
4
+ module Machine
5
+ module Aws
6
+ class NodeDestroyer
7
+ attr_reader :ec2, :api_client
8
+
9
+ # @param [Central::Client] api_client Central api client
10
+ # @param [String] access_key_id aws_access_key_id
11
+ # @param [String] secret_key aws_secret_access_key
12
+ # @param [String] region
13
+ def initialize(api_client, access_key_id, secret_key, region = 'us-west-2')
14
+ @api_client = api_client
15
+ @ec2 = ::Aws::EC2::Resource.new(
16
+ region: region,
17
+ credentials: ::Aws::Credentials.new(access_key_id, secret_key)
18
+ )
19
+ end
20
+
21
+ def run!(stack, name)
22
+ instances = ec2.instances(filters: [
23
+ { name: 'tag:Name', values: [name] }
24
+ ])
25
+ abort("Cannot find AWS instance #{name}") if instances.to_a.size == 0
26
+ abort("There are multiple instances with name #{name}") if instances.to_a.size > 1
27
+ instance = instances.first
28
+ if instance
29
+ ShellSpinner "Terminating AWS instance #{name.colorize(:cyan)} " do
30
+ instance.terminate
31
+ sleep 2 until instance.reload.state.name.to_s == 'terminated'
32
+ end
33
+ else
34
+ abort "Cannot find instance #{name.colorize(:cyan)} in AWS"
35
+ end
36
+ node = api_client.get("stacks/#{stack['id']}/nodes")['nodes'].find { |n| n['name'] == name }
37
+ if node
38
+ ShellSpinner "Removing node #{name.colorize(:cyan)} from stack #{stack['name'].colorize(:cyan)} " do
39
+ api_client.delete("stacks/#{stack['id']}/nodes/#{name}")
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,214 @@
1
+ require 'fileutils'
2
+ require 'erb'
3
+ require 'open3'
4
+ require 'shell-spinner'
5
+ require_relative 'common'
6
+
7
+ module Central
8
+ module Machine
9
+ module Aws
10
+ class NodeProvisioner
11
+ include RandomName
12
+ include Common
13
+
14
+ attr_reader :ec2, :api_client
15
+
16
+ # @param [Central::Client] api_client Central api client
17
+ # @param [String] access_key_id aws_access_key_id
18
+ # @param [String] secret_key aws_secret_access_key
19
+ # @param [String] region
20
+ def initialize(api_client, access_key_id, secret_key, region)
21
+ @api_client = api_client
22
+ @ec2 = ::Aws::EC2::Resource.new(
23
+ region: region,
24
+ credentials: ::Aws::Credentials.new(access_key_id, secret_key)
25
+ )
26
+ end
27
+
28
+ # @param [Hash] opts
29
+ def run!(opts)
30
+ ami = resolve_ami(region)
31
+ abort('No valid AMI found for region') unless ami
32
+
33
+ opts[:vpc] = default_vpc.vpc_id unless opts[:vpc]
34
+
35
+ security_group = ensure_security_group(opts[:stack], opts[:vpc])
36
+ name = opts[:name] || generate_name
37
+
38
+ subnet = if opts[:subnet].nil?
39
+ default_subnet(opts[:vpc], region + opts[:zone])
40
+ else
41
+ ec2.subnet(opts[:subnet])
42
+ end
43
+ dns_server = aws_dns_supported?(opts[:vpc]) ? '169.254.169.253' : '8.8.8.8'
44
+ userdata_vars = {
45
+ name: name,
46
+ version: opts[:version],
47
+ master_uri: opts[:master_uri],
48
+ stack_token: opts[:stack_token],
49
+ dns_server: dns_server
50
+ }
51
+
52
+ ec2_instance = ec2.create_instances(
53
+ image_id: ami,
54
+ min_count: 1,
55
+ max_count: 1,
56
+ instance_type: opts[:type],
57
+ security_group_ids: [security_group.group_id],
58
+ key_name: opts[:key_pair],
59
+ subnet_id: subnet.subnet_id,
60
+ user_data: Base64.encode64(user_data(userdata_vars)),
61
+ block_device_mappings: [
62
+ {
63
+ device_name: '/dev/xvda',
64
+ virtual_name: 'Root',
65
+ ebs: {
66
+ volume_size: opts[:storage],
67
+ volume_type: 'gp2'
68
+ }
69
+ }
70
+ ]
71
+ ).first
72
+ ec2_instance.create_tags(tags: [
73
+ { key: 'Name', value: name },
74
+ { key: 'central_stack', value: opts[:stack] }
75
+ ])
76
+
77
+ ShellSpinner "Creating AWS instance #{name.colorize(:cyan)} " do
78
+ sleep 5 until ec2_instance.reload.state.name == 'running'
79
+ end
80
+ node = nil
81
+ ShellSpinner "Waiting for node #{name.colorize(:cyan)} join to stack #{opts[:stack].colorize(:cyan)} " do
82
+ sleep 2 until node = instance_exists_in_stack?(opts[:stack], name)
83
+ end
84
+ labels = ["region=#{region}", "az=#{opts[:zone]}"]
85
+ set_labels(node, labels)
86
+ end
87
+
88
+ # @param [String] stack
89
+ # @return [Aws::EC2::SecurityGroup]
90
+ def ensure_security_group(stack, vpc_id)
91
+ group_name = "central_stack_#{stack}"
92
+ sg = ec2.security_groups(
93
+ filters: [
94
+ {
95
+ name: 'group-name',
96
+ values: [group_name]
97
+ },
98
+ {
99
+ name: 'vpc-id',
100
+ values: [vpc_id]
101
+ }
102
+ ]
103
+ ).first
104
+ unless sg
105
+ ShellSpinner 'Creating AWS security group' do
106
+ sg = create_security_group(group_name, vpc_id)
107
+ end
108
+ end
109
+ sg
110
+ end
111
+
112
+ # creates security_group and authorizes default port ranges
113
+ #
114
+ # @param [String] name
115
+ # @param [String] vpc_id
116
+ # @return [Aws::EC2::SecurityGroup]
117
+ def create_security_group(name, vpc_id)
118
+ sg = ec2.create_security_group(
119
+ group_name: name,
120
+ description: 'Central Stack',
121
+ vpc_id: vpc_id)
122
+ sg.create_tags(tags: [
123
+ { key: 'Name', value: name }
124
+ ])
125
+ sg.authorize_ingress( # SSHD
126
+ ip_protocol: 'tcp',
127
+ from_port: 22,
128
+ to_port: 22,
129
+ cidr_ip: '24.7.32.100/32')
130
+ sg.authorize_ingress( # HTTPS
131
+ ip_protocol: 'tcp',
132
+ from_port: 443,
133
+ to_port: 443,
134
+ cidr_ip: '24.7.32.100/32')
135
+ sg.authorize_ingress( # OAUTH
136
+ ip_protocol: 'tcp',
137
+ from_port: 5000,
138
+ to_port: 5000,
139
+ cidr_ip: '24.7.32.100/32')
140
+ sg.authorize_ingress( # OpenVPN
141
+ ip_protocol: 'udp',
142
+ from_port: 1194,
143
+ to_port: 1194,
144
+ cidr_ip: '0.0.0.0/0')
145
+ sg.authorize_ingress( # Overlay / Weave network
146
+ ip_permissions: [
147
+ {
148
+ from_port: 6783,
149
+ to_port: 6783,
150
+ ip_protocol: 'tcp',
151
+ user_id_group_pairs: [
152
+ {
153
+ group_id: sg.group_id,
154
+ vpc_id: vpc_id
155
+ }
156
+ ]
157
+ },
158
+ {
159
+ from_port: 6783,
160
+ to_port: 6784,
161
+ ip_protocol: 'udp',
162
+ user_id_group_pairs: [
163
+ {
164
+ group_id: sg.group_id,
165
+ vpc_id: vpc_id
166
+ }
167
+ ]
168
+ }
169
+ ]
170
+ )
171
+ sg
172
+ end
173
+
174
+ # @return [String]
175
+ def region
176
+ ec2.client.config.region
177
+ end
178
+
179
+ def user_data(vars)
180
+ cloudinit_template = File.join(__dir__, '/cloudinit.yml')
181
+ erb(File.read(cloudinit_template), vars)
182
+ end
183
+
184
+ def generate_name
185
+ "#{super}-#{rand(1..99)}"
186
+ end
187
+
188
+ def instance_exists_in_stack?(stack, name)
189
+ api_client.get("stacks/#{stack}/nodes")['nodes'].find { |n| n['name'] == name }
190
+ end
191
+
192
+ def erb(template, vars)
193
+ ERB.new(template).result(OpenStruct.new(vars).instance_eval { binding })
194
+ end
195
+
196
+ # @param [Hash] node
197
+ # @param [Array<String>] labels
198
+ def set_labels(node, labels)
199
+ data = {}
200
+ data[:labels] = labels
201
+ api_client.put("nodes/#{node['id']}", data, {}, 'Central-Stack-Token' => node['stack']['token'])
202
+ end
203
+
204
+ # @param [String] vpc_id
205
+ # @return [Boolean]
206
+ def aws_dns_supported?(vpc_id)
207
+ vpc = ec2.vpc(vpc_id)
208
+ response = vpc.describe_attribute(attribute: 'enableDnsSupport')
209
+ response.enable_dns_support
210
+ end
211
+ end
212
+ end
213
+ end
214
+ end