aerosol 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.cane +3 -0
  3. data/.gitignore +15 -0
  4. data/.rspec +3 -0
  5. data/.travis.yml +6 -0
  6. data/Gemfile +3 -0
  7. data/LICENSE.txt +20 -0
  8. data/README.md +399 -0
  9. data/Rakefile +18 -0
  10. data/aerosol.gemspec +32 -0
  11. data/bin/aerosol +8 -0
  12. data/img/aerosol.pdf +3898 -11
  13. data/img/aerosol.png +0 -0
  14. data/lib/aerosol/auto_scaling.rb +240 -0
  15. data/lib/aerosol/aws.rb +62 -0
  16. data/lib/aerosol/aws_model.rb +93 -0
  17. data/lib/aerosol/cli.rb +41 -0
  18. data/lib/aerosol/connection.rb +39 -0
  19. data/lib/aerosol/deploy.rb +105 -0
  20. data/lib/aerosol/env.rb +6 -0
  21. data/lib/aerosol/instance.rb +55 -0
  22. data/lib/aerosol/launch_configuration.rb +106 -0
  23. data/lib/aerosol/rake_task.rb +141 -0
  24. data/lib/aerosol/runner.rb +329 -0
  25. data/lib/aerosol/util.rb +41 -0
  26. data/lib/aerosol/version.rb +5 -0
  27. data/lib/aerosol.rb +83 -0
  28. data/spec/aerosol/auto_scaling_spec.rb +420 -0
  29. data/spec/aerosol/aws_spec.rb +24 -0
  30. data/spec/aerosol/cli_spec.rb +10 -0
  31. data/spec/aerosol/connection_spec.rb +94 -0
  32. data/spec/aerosol/deploy_spec.rb +192 -0
  33. data/spec/aerosol/env_spec.rb +16 -0
  34. data/spec/aerosol/instance_spec.rb +57 -0
  35. data/spec/aerosol/launch_configuration_spec.rb +328 -0
  36. data/spec/aerosol/rake_task_spec.rb +19 -0
  37. data/spec/aerosol/runner_spec.rb +482 -0
  38. data/spec/aerosol_spec.rb +41 -0
  39. data/spec/fixtures/Procfile +1 -0
  40. data/spec/fixtures/Rakefile +17 -0
  41. data/spec/fixtures/not_a_tar-2.txt +1 -0
  42. data/spec/fixtures/not_a_tar.txt +1 -0
  43. data/spec/fixtures/tar-2.tar +0 -0
  44. data/spec/fixtures/test-1.tar +0 -0
  45. data/spec/fixtures/test-2.tar.gz +0 -0
  46. data/spec/spec_helper.rb +22 -0
  47. data/spec/support/vcr.rb +11 -0
  48. data/spec/vcr/Deployz_Docker/_fetch_import/when_both_import_and_name_are_present_present/and_it_points_to_a_non-S3_url/pulls_the_file.yml +214 -0
  49. metadata +312 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e6cf29a31c88ffb04c424c3bcbbcb0645d74e071
4
+ data.tar.gz: 4e9f58b45fd64a4875e09ec9c3ce0645f82d6ecf
5
+ SHA512:
6
+ metadata.gz: 25cb41164e46803c1abe915dd809c12fdf050b3427d6ded99353b1e7ca3a434eb3a74d60f24f1ef66896b3510ea1905483f66bb8c279d59bfce7588026ecc234
7
+ data.tar.gz: 525852da882273707a57af5161075dd36a9c1f1ad3abaa032ba8dcc80ed4697c20c7e67a9c4e713f497461e187e876cd481d1ff669e0be043d4fe0465eede0bf
data/.cane ADDED
@@ -0,0 +1,3 @@
1
+ --no-doc
2
+ --abc-max 30
3
+ --style-measure 120
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ # bundler
2
+ .bundle
3
+
4
+ # OSX
5
+ .DS_Store
6
+
7
+ # Vim
8
+ *.swp
9
+
10
+ Gemfile.lock
11
+ *.gem
12
+ build/
13
+ dist/
14
+
15
+ docker-export-ubuntu-latest.tar.gz
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --profile
3
+ --format documentation
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ script: CI=true bundle exec rake
6
+
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Swipely, Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,399 @@
1
+ [![Gem Version](https://badge.fury.io/rb/aerosol.png)](http://badge.fury.io/rb/aerosol)
2
+ [![Build Status](https://travis-ci.org/swipely/aerosol.png)](https://travis-ci.org/swipely/aerosol)
3
+
4
+ ![Aerosol](https://raw.github.com/swipely/aerosol/master/img/aerosol.png)
5
+ =========================================================================
6
+
7
+ Aerosol orchestrates instance-based-deploys. Start new EC2 instances running your app every release, using auto scaling groups to orchestrate the startup of the new version and the graceful shutdown of the old version.
8
+
9
+ Getting Started
10
+ ---------------
11
+
12
+ Add it to your Gemfile:
13
+
14
+ ```ruby
15
+ gem 'aerosol'
16
+ ```
17
+
18
+ And build an aerosol.rb
19
+
20
+ If you're not using Rails, add it to your Rakefile:
21
+
22
+ ```ruby
23
+ require 'aerosol'
24
+ ```
25
+
26
+ Usage
27
+ -----
28
+
29
+ ### Rake Tasks
30
+
31
+ The deploy tasks are within the `aerosol:deploy_name` namespace where deploy_name is based upon the deploy section detailed below.
32
+
33
+ #### Full deploy tasks
34
+
35
+ `all` - Full serial deployment: Run migration, create auto scaling group, wait for instances, stop old application, destroy old auto scaling groups and run the post deploy command
36
+
37
+ `all_asynch` - Same as `all` but runs the migration and creates auto scaling groups in parallel
38
+
39
+ #### The separate deploy rake tasks
40
+
41
+ `run_migration` - Runs the ActiveRecord migration through the SSH connection given
42
+
43
+ `create_auto_scaling_group` - Creates a new auto scaling group for the current git hash
44
+
45
+ `wait_for_new_instances` - Waits for instances of the new autoscaling groups to start up
46
+
47
+ `stop_old_app` - Runs command to shut down the application on the old instances instead of just terminating
48
+
49
+ `destroy_old_auto_scaling_groups` - Terminates instances with the current tag and different git hash
50
+
51
+ `destroy_new_auto_scaling_groups` - Terminates instances with the current tag and same git hash
52
+
53
+ `run_post_deploy` - Runs a post deploy command
54
+
55
+ #### Non-deploy rake tasks
56
+
57
+ `aerosol:ssh:deploy_name` - Prints out ssh command to all instances of the latest deploy
58
+
59
+ ### CLI
60
+
61
+ `aerosol ssh deploy_name` - Same as aerosol:ssh:deploy_name
62
+
63
+ `aerosol ssh -r deploy_name` - Runs the ssh command to the first instance available (still prints out the others)
64
+
65
+ Demo
66
+ ----
67
+
68
+ ```ruby
69
+ namespace :test
70
+
71
+ launch_configuration :launch_config do
72
+ ami 'ami-1715317e' # Ubuntu 13.04 US-East-1 ebs amd64
73
+ instance_type 'm1.small'
74
+ iam_role 'role-app'
75
+ key_name 'app'
76
+
77
+ user_data ERB.new(File.read('startup.sh.erb')).result(binding)
78
+ end
79
+
80
+ auto_scaling :auto_scaling_group do
81
+ availability_zones ['us-east-1a']
82
+ max_size 1
83
+ min_size 1
84
+ launch_configuration :launch_config
85
+ end
86
+
87
+ ssh :ssh do
88
+ user 'ubuntu'
89
+ end
90
+
91
+ ssh :migration do
92
+ user 'ubuntu'
93
+ host 'dbserver.example.com'
94
+ end
95
+
96
+ ssh :local do
97
+ jump :user => 'ubuntu', :host => 'jump.example.com'
98
+ end
99
+
100
+ deploy :deploy do
101
+ ssh :ssh
102
+ migration_ssh :migration
103
+ local_ssh :local
104
+ auto_scaling :auto_scaling_group
105
+ stop_command 'sudo stop app'
106
+ live_check '/version'
107
+ app_port 443
108
+ post_deploy_command 'bundle exec rake postdeploycommand'
109
+ end
110
+ ```
111
+
112
+ The DSL
113
+ -------
114
+
115
+ The DSL is broken down into multiple objects, all of which conform to a specific format. Each object starts with the name of the section,
116
+ followed by a name for the object you're creating, and a block for configuration.
117
+
118
+ ```ruby
119
+ auto_scaling :test_auto_scaling do
120
+ # code here
121
+ end
122
+ ```
123
+
124
+ Each object has an enumeration of valid attributes. The following code sets the `max_size` attribute in a `auto_scaling` group called `test_auto_scaling`:
125
+
126
+ ```ruby
127
+ auto_scaling :test_auto_scaling do
128
+ max_size 1
129
+ end
130
+ ```
131
+
132
+ Finally, each object has zero or more valid references to other DSL objects. The following code sets `auto_scaling` that references a `launch_configuration`:
133
+
134
+ ```ruby
135
+ launch_configuration :my_launch_config do
136
+ max_size 1
137
+ end
138
+
139
+ auto_scaling :my_auto_scaling do
140
+ launch_configuration :my_launch_config
141
+ end
142
+ ```
143
+
144
+ Below is an alternative syntax that accomplishes the same thing:
145
+
146
+ ```ruby
147
+ auto_scaling :my_auto_scaling do
148
+ launch_configuration do
149
+ max_size 1
150
+ end
151
+ end
152
+ ```
153
+
154
+ Network Design
155
+ --------------
156
+
157
+ A simplified version of the AWS network design that Aerosol manages is: auto scaling groups control running instances, and determine how those instances start up.
158
+
159
+ Aerosol defines a way to deploy to an auto scaling group, with the correct launch configuration and properly brings up the instances.
160
+
161
+ Controlling SSH connections
162
+ ---------------------------
163
+
164
+ SSH connections are used when connecting for migrations, checking if the instances are live and running local connections.
165
+
166
+ Options:
167
+
168
+ - user - The user to connect with
169
+ - host - Where to connect to (will be filled in for instance and local connections)
170
+ - jump - A hash of a user and host to connect through. For secure/VPN connections.
171
+
172
+ ### Examples
173
+
174
+ Minimal SSH connection for local connections:
175
+
176
+ ```ruby
177
+ ssh :local_ssh do
178
+ end
179
+ ```
180
+
181
+ Since a machine could start up with your user and not need a jump server, this could be all you need.
182
+
183
+ SSH connection with a jump server:
184
+
185
+ ```ruby
186
+ ssh :jump_ssh do
187
+ jump :user => 'ec2_user', :host => 'jump.example.com'
188
+ end
189
+ ```
190
+
191
+ A lot of network structures use a middle jump server before connecting to the internal network. Supplying either a user, host or both, you can establish a jump server to connect through.
192
+
193
+ SSH connection with a user and host:
194
+
195
+ ```ruby
196
+ ssh :migration_ssh do
197
+ user 'db_user'
198
+ host 'dbserver.example.com'
199
+ end
200
+ ```
201
+
202
+ When using ActiveRecord, you'll need to supply a connection to pass through. Supply your database server credentials like this (you can also use a jump server here).
203
+
204
+ Controlling instance definition
205
+ -------------------------------
206
+
207
+ Launch configurations define the EC2 instance startup. All the features entered via the EC2 wizard are available.
208
+
209
+ Options:
210
+
211
+ - ami - The Amazon Machine Image that designates what operating system and possible tiers to run on.
212
+ - instance_type - The tier to run the instance on (m1.large, etc.)
213
+ - security_groups - A list of security groups the instances are paired with.
214
+ - user_data - The bash script that is run as the instance comes live
215
+ - iam_role - the Identity and Access Management role the instances should startup with
216
+ - kernel_id - The kernel ID configurable for the EC2 instance (best found through the EC2 wizard)
217
+ - key_name - The name of the EC2 key pair for initial connections to the instance
218
+ - spot_price - The max hourly price to be paid for any spot prices
219
+
220
+ ### Examples
221
+
222
+ Launch configurations must specify an AMI and instance type. Everything else can be ignored and the instance will start up:
223
+
224
+ ```ruby
225
+ launch_configuration :minimal_lc do
226
+ ami 'ami-1715317e' # Ubuntu 13.04 US-East-1 ebs amd64
227
+ instance_type 'm1.small'
228
+ end
229
+ ```
230
+
231
+ This instance will startup and do nothing, with almost no way to connect to it though.
232
+
233
+ Adding a script into the user_data section sets how the instance will start up. Either use plain text, read from a file, or use ERB:
234
+
235
+ Text:
236
+
237
+ ```ruby
238
+ launch_configuration :startup_lc do
239
+ ami 'ami-1715317e' # Ubuntu 13.04 US-East-1 ebs amd64
240
+ instance_type 'm1.small'
241
+ user_data "#!/bin/bash\n# Get file here"
242
+ end
243
+ ```
244
+
245
+ File:
246
+
247
+ ```ruby
248
+ launch_configuration :startup_lc do
249
+ ami 'ami-1715317e' # Ubuntu 13.04 US-East-1 ebs amd64
250
+ instance_type 'm1.small'
251
+ user_data File.read('startup.sh')
252
+ end
253
+ ```
254
+
255
+ ERB:
256
+
257
+ ```ruby
258
+ launch_configuration :startup_lc do
259
+ ami 'ami-1715317e' # Ubuntu 13.04 US-East-1 ebs amd64
260
+ instance_type 'm1.small'
261
+
262
+ thing = "google.com" # This is accessible within the ERB file!
263
+
264
+ user_data ERB.new(File.read('startup.sh.erb')).result(binding)
265
+ end
266
+ ```
267
+
268
+ Using an ERB file is likely the most powerful especially since anything defined within the launch configurations context is available, as well as any other gems required before this.
269
+
270
+ Controlling auto scaling groups
271
+ -------------------------------
272
+
273
+ Auto scaling groups define how your network expands as needed and spans multiple availability zones.
274
+
275
+ Options:
276
+
277
+ - availability_zones - A list of availability zones
278
+ - min_size/max_size - The min and max number of instances for the auto scaling group
279
+ - default_cooldown - The number of seconds after a scaling activity completes before any further trigger-related scaling activities can start
280
+ - desired_capacity - The number of instances that should be running in the group
281
+ - health_check_grace_period - The number of seconds AWS waits before it befores a health check
282
+ - health_check_type - The type of health check to perform, `'ELB'` and `'EC2'` are valid options
283
+ - load_balancer_names - A list of the names of desired load balancers
284
+ - placement_group - Physical location of your cluster placement group created in EC2
285
+ - tag - A hash of tags for the instances in the group
286
+ - launch_configuration - A reference to the launch configuration used by this auto scaling group
287
+ - vpc_zone_identifier - A comma-separated list of subnet identifiers of Amazon Virtual Private Clouds
288
+
289
+ Auto scaling groups only require an availability zone, a min and max size, and a launch configuration.
290
+
291
+ ```ruby
292
+ auto_scaling :minimal_asg do
293
+ launch_configuration :minimal_lc
294
+ availability_zones ['us-east-1a']
295
+ min_size 1
296
+ max_size 1
297
+ end
298
+ ```
299
+
300
+ This will start up a single instance using our most basic launch configuration in US East 1A
301
+
302
+ Adding tags can help identify the instances (two are already made for you: Deploy and GitSha)
303
+
304
+ ```ruby
305
+ auto_scaling :tagged_asg do
306
+ launch_configuration :minimal_lc
307
+ availability_zones ['us-east-1a']
308
+ min_size 1
309
+ max_size 1
310
+
311
+ tag 'Name' => 'tagged_asg'
312
+ tag 'NextTag' => 'NewValue'
313
+ # or
314
+ tag 'Name' => 'tagged_asg', 'NextTag' => 'NewValue'
315
+ end
316
+ ```
317
+
318
+ Configuring your deploy
319
+ -----------------------
320
+
321
+ A deploy ties the auto scaling groups and possible SSH connections together for application logic
322
+
323
+ Options:
324
+
325
+ - auto_scaling - Auto scaling group for this deployment
326
+ - ssh - SSH connection from deployment computer to new instance
327
+ - migration_ssh - SSH connection from deployment computer to database connection instance (optional: only needed if deployment computer cannot connect to database directly)
328
+ - do_not_migrate! - Do not try and do a migration (for non-ActiveRecord deploys)
329
+ - local_ssh - SSH connection from local computer to running instances
330
+ - stop_command - This command is run before an auto scaling group is run to stop your application gracefully
331
+ - live_check - 'Local path to query on the instance to verify the application is running'
332
+ - instance_live_grace_period - The number of seconds to wait for an instance to be live (default: 30 minutes - 1800 seconds)
333
+ - db_config_path - relative path of your database config file (default: 'config/database.yml')
334
+ - app_port - which port the application is running on
335
+ - stop_app_retries - The number of times to retry stopping the application (default: 2)
336
+ - continue_if_stop_app_fails - When true, will ignore a failure when stopping the application (default: 'false')
337
+ - post_deploy_command - Command run after the deploy has finished
338
+ - sleep_before_termination - Time to wait after the new instance spawns and before terminating the old instance (allow time for external load balancers to start working)
339
+ - ssl - Boolean that enables/disables ssl when doing the live check (default: 'false').
340
+ - log_files - Paths to files on each instance to tail during deploy (default: '/var/log/syslog')
341
+ - tail_logs - Boolean that will enable/disable tailing log files (default: 'false')
342
+
343
+ A lot of the options for deployment are required, but we've defined some sane defaults.
344
+
345
+ A basic deployment could look like:
346
+
347
+ ```ruby
348
+ deploy :quick_app do
349
+ ssh :jump_ssh
350
+ do_not_migrate!
351
+ auto_scaling :minimal_asg
352
+ stop_command 'sudo stop app'
353
+ live_check '/version'
354
+ app_port 80
355
+ end
356
+ ```
357
+
358
+ This won't perform a migration, will stop the application with 'sudo stop app' after checking the instance is live at 'localhost:80/version' after SSHing to the instance through jump_ssh.
359
+ It will use the default of waiting 30 minutes for a deploy before failing, and fail if the previous application does not stop correctly.
360
+
361
+ If the server you're deploying from is not behind the same restrictions a development machine is, add a local SSH connection. The local connection will be used when generating commands for connecting to the instances.
362
+
363
+ Environments
364
+ ------------
365
+
366
+ An environment is a set of deploys that may be run in parallel.
367
+ This can be useful if you, for example, want to deploy a load balancer at the same time you deploy your backend application.
368
+
369
+ Options:
370
+
371
+ - deploy - Add a deploy to this environment.
372
+
373
+ A basic environment (assuming there is already a deploy named `:quick_app` and another named `:quick_app_worker`):
374
+
375
+ ```ruby
376
+ env :staging do
377
+ deploy :quick_app
378
+ deploy :quick_app_worker
379
+ end
380
+ ```
381
+
382
+ To run these deploys, the following task can be run:
383
+
384
+ ```shell
385
+ $ bundle exec rake aerosol:env:staging
386
+ ```
387
+
388
+ Namespace
389
+ ---------
390
+
391
+ A namespace will enable branches of a main project to be deployed separately without interfering with auto scaling groups, launch configurations or elastic IPs
392
+
393
+ ```ruby
394
+ namespace :test
395
+ ```
396
+
397
+ This will prefix all auto scaling groups and launch configurations with `test-` and also the `Deploy` tag that is on each auto scaling group by default.
398
+
399
+ Copyright (c) 2013 Swipely, Inc. See LICENSE.txt for further details.
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ # Copyright Swipely, Inc. All rights reserved.
2
+
3
+ $LOAD_PATH.unshift( File.join( File.dirname(__FILE__), 'lib' ) )
4
+
5
+ require 'rake'
6
+ require 'aerosol'
7
+ require 'rspec/core/rake_task'
8
+ require 'cane/rake_task'
9
+
10
+ task :default => [:spec, :quality]
11
+
12
+ RSpec::Core::RakeTask.new do |t|
13
+ t.pattern = 'spec/**/*_spec.rb'
14
+ end
15
+
16
+ Cane::RakeTask.new(:quality) do |cane|
17
+ cane.canefile = '.cane'
18
+ end
data/aerosol.gemspec ADDED
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/aerosol/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Swipely, Inc."]
6
+ gem.email = %w{tomhulihan@swipely.com bright@swipely.com toddlunter@swipely.com}
7
+ gem.description = %q{Instance-based deploys made easy}
8
+ gem.summary = %q{Instance-based deploys made easy}
9
+ gem.homepage = "https://github.com/swipely/aerosol"
10
+ gem.license = 'MIT'
11
+
12
+ gem.files = `git ls-files`.split($\)
13
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
14
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
+ gem.name = "aerosol"
16
+ gem.require_paths = %w{lib}
17
+ gem.version = Aerosol::VERSION
18
+ gem.add_dependency 'activerecord', '>= 3.2.0'
19
+ gem.add_dependency 'clamp', '~> 0.6'
20
+ gem.add_dependency 'excon'
21
+ gem.add_dependency 'fog', '~> 1.21'
22
+ gem.add_dependency 'grit'
23
+ gem.add_dependency 'net-ssh'
24
+ gem.add_dependency 'net-ssh-gateway'
25
+ gem.add_dependency 'dockly-util', '~> 0.0.5'
26
+ gem.add_development_dependency 'cane'
27
+ gem.add_development_dependency 'pry'
28
+ gem.add_development_dependency 'rake'
29
+ gem.add_development_dependency 'rspec', '< 3.0'
30
+ gem.add_development_dependency 'webmock'
31
+ gem.add_development_dependency 'vcr'
32
+ end
data/bin/aerosol ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ $: << File.join(File.dirname(__FILE__), "..", "lib")
5
+ require 'aerosol'
6
+ require 'aerosol/cli'
7
+
8
+ Aerosol::Cli.run