capistrano-releases 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 42c8b02de2ee347d75131b77ed59df3d2f8ca392
4
- data.tar.gz: 71d451dbfeb6ac72decab1c8e973d336b7a64294
3
+ metadata.gz: 59d6dff6482631156eba519cee7dc7205baa6953
4
+ data.tar.gz: 82fa108d36ff56bc11d2606ad3fd34764fea3ba2
5
5
  SHA512:
6
- metadata.gz: aa4d61c892fee55dbe10e26c50ff658139e408c016c2273af00fe97e076464c5f557e3560649622dfe62268b3a6c8b162dd559feddaf2503d0aa1ba850267567
7
- data.tar.gz: 13eca03654b74f18c1aaec90524475883b72995ccc0f53a0285ed20cd2742132811deb55970fc3c2a1f4c27c45703d49559855a2a51e60ca814e45d89e9a9a68
6
+ metadata.gz: 4f6ed45f6baeda7c996f49ca855c061c521e6680bbfae80c96bffbaa55ea5f77467785295c0a1c8c727ad4ab8532331b757136e9b2b6de1933f34ebc639ccc26
7
+ data.tar.gz: 5b8d7226a89243e6c079cf69eeef4999a9fbb889a55001b4d45aa2e24024b21db89e757b0dd7e9394bd65b2beb6608add9137bb3dde1486b1a56171d8a501bdb
data/README.md CHANGED
@@ -1,7 +1,14 @@
1
1
  # Capistrano::Releases
2
- Auto scaling AWS EC2 environments need a way to share the Capistrano 'releases' directory and 'current' symlink.
3
- This gem provides that capability using AWS S3 to store releases.
4
- Each release is stored as a zip file.
2
+
3
+ This gem simplifies working with [Auto scaling for AWS EC2](https://aws.amazon.com/autoscaling/) and [Capistrano](http://capistranorb.com). It does this by storing your releases in AWS S3 and synchronizing them when needed (after deploy, instance reboot, and after a new instance is created).
4
+
5
+ ## Requirements
6
+
7
+ * Ruby 2.X or greater
8
+ * aws-sdk 2.X or greater
9
+ * An AWS S3 bucket to store releases
10
+ * Read and write API permissions to the S3 bucket
11
+ * Capistrano installed and configured properly with deploys already working
5
12
 
6
13
  ## Installation
7
14
 
@@ -21,8 +28,93 @@ Or install it yourself as:
21
28
 
22
29
  ## Usage
23
30
 
31
+ It is assumed that you have already setup a S3 bucket and granted API read/write permissions to it.
32
+ You should test to make sure your instances are able to read/write to the bucket before continuing.
33
+
34
+ You normally interact with the gem through the command line (see below for flag details):
35
+
24
36
  $ releases --help
25
37
 
38
+ The general idea is that after each deploy, you 'push' the new release to S3.
39
+ Then, after each boot (or reboot) your instances 'pull' the latest releases from S3.
40
+
41
+ For 'push' you need to edit your *deploy.rb* and add something like this:
42
+
43
+ namespace :releases do
44
+ bucket = 'your-bucket-name-goes-here'
45
+
46
+ desc 'Push releases'
47
+ task :push do
48
+ on roles(:all, primary: true) do
49
+ execute "releases -b #{bucket} -d #{fetch(:deploy_to)} -m push"
50
+ end
51
+ end
52
+ end
53
+ after 'deploy:finished', 'releases:push'
54
+
55
+ For 'pull' you need to configure your server to run a command **before** your Rails processes (Puma, Thin, Sidekiq, etc) start:
56
+
57
+ $ releases -b your-bucket-name-goes-here -d /your/deploy/to/name/goes/here -m pull
58
+
59
+ You must now write a boot script for your Rails processes.
60
+ These tend to be very specific to your environment and the set of Capistrano gems you are using.
61
+ An example is provided below.
62
+
63
+ ## Flags
64
+
65
+ #### --mode
66
+
67
+ You must pick a mode to run in: 'push' or 'pull'.
68
+
69
+ The push mode compare your local releases to those stored in S3.
70
+ Any missing releases will get compressed and uploaded.
71
+ The 'current' symlink version will also get uploaded.
72
+
73
+ The pull mode compares the releases stored in S3 to your local releases.
74
+ Any missing releases will get downloaded and uncompressed.
75
+ Finally, the 'current' symlink will get updated to match the remote version.
76
+
77
+ #### --bucket
78
+
79
+ Your instances must have read/write access to the specified S3 bucket.
80
+ Make sure your instances have the correct permissions with an IAM role
81
+ or make sure you specify the ````AWS_ACCESS_KEY_ID```` and ````AWS_SECRET_ACCESS_KEY```` environment variables.
82
+ Under the hood this gem uses the [aws-sdk](https://github.com/aws/aws-sdk-ruby) gem for all API calls.
83
+
84
+ #### --deploy-to
85
+
86
+ This flag must be set to match the Capistrano configuration variable of the same name.
87
+ You can normally find it in your *deploy.rb*. An example from a stock config:
88
+
89
+ set :deploy_to, "/var/www/my_app_name"
90
+
91
+ ## Rails boot script
92
+
93
+ This is just a sample.
94
+ You will need to modify it based on your Capistrano configuration.
95
+ Watch the commands that are executed when you run ````cap production deploy```` to see what commands are executed.
96
+ Also make sure you run it as ````:deploy_user```` as specified in your *deploy.rb*.
97
+
98
+ #!/bin/bash
99
+
100
+ echo '***** pulling releases *****' &&
101
+ releases -b my-releases-bucket -d /apps/my-app -m pull &&
102
+
103
+ echo '***** Deleting old PID files *****' &&
104
+ rm -rf /apps/my-app/shared/tmp/pids/* &&
105
+
106
+ echo '***** Installing gems *****' &&
107
+ bundle install --path /apps/my-app/shared/bundle --without development test --deployment --quiet &&
108
+
109
+ echo '***** Precompiling assets *****' &&
110
+ bundle exec rake assets:precompile &&
111
+
112
+ echo '***** Starting web server *****' &&
113
+ echo 'put your web server command here' &&
114
+
115
+ echo '***** Starting job server *****' &&
116
+ echo 'put your job server command here'
117
+
26
118
  ## Development
27
119
 
28
120
  After checking out the repo, run `bin/setup` to install dependencies.
@@ -27,29 +27,45 @@ module Capistrano
27
27
 
28
28
  def push
29
29
  make_dirs
30
+
30
31
  remotes = Set.new(remote_releases)
31
- to_upload = local_releases.reject { |r| remotes.include?(r) }
32
- to_upload.each { |r| upload(r) }
32
+ puts "Remote releases: #{remotes.to_a.inspect}"
33
+
34
+ to_upload_releases = local_releases.reject { |r| remotes.include?(r) }
35
+ to_upload_releases.each do |r|
36
+ puts "Uploading release: #{r}"
37
+ upload_release(r)
38
+ end
39
+
40
+ puts "Setting remote current to: #{remote_current}"
33
41
  self.remote_current = local_current
34
42
 
35
- to_upload
43
+ upload_bundle
44
+
45
+ to_upload_releases
36
46
  end
37
47
 
38
48
  def pull
39
49
  make_dirs
50
+
40
51
  locals = Set.new(local_releases)
41
52
  puts "Local releases: #{locals.to_a.inspect}"
42
- to_download = remote_releases.last(params[:keep_releases])
43
- .reject { |r| locals.include?(r) }
44
- to_download.each do |r|
53
+
54
+ to_download_releases = remote_releases.last(params[:keep_releases])
55
+ .reject { |r| locals.include?(r) }
56
+ to_download_releases.each do |r|
45
57
  puts "Downloading release: #{r}"
46
- download(r)
58
+ download_release(r)
47
59
  end
60
+
48
61
  self.local_current = remote_current
62
+
49
63
  puts "Setting local current to: #{local_current}"
50
64
  Dir.chdir(File.join(params[:deploy_to], 'current'))
51
65
 
52
- to_download
66
+ download_bundle
67
+
68
+ to_download_releases
53
69
  end
54
70
 
55
71
  private
@@ -86,6 +102,10 @@ module Capistrano
86
102
  File.join(params[:deploy_to], 'releases')
87
103
  end
88
104
 
105
+ def local_shared_path
106
+ File.join(params[:deploy_to], 'shared')
107
+ end
108
+
89
109
  def local_releases
90
110
  Dir.glob("#{local_releases_path}/*")
91
111
  .sort
@@ -95,7 +115,7 @@ module Capistrano
95
115
  def remote_releases
96
116
  bucket.objects
97
117
  .map(&:key)
98
- .select { |k| k.end_with?('.tar.gz') }
118
+ .select { |k| k =~ /\A\d+.*\.tar\.gz\z/ }
99
119
  .map { |k| k.gsub(/\.tar\.gz\z/, '') }
100
120
  .sort
101
121
  end
@@ -124,8 +144,8 @@ module Capistrano
124
144
  nil
125
145
  end
126
146
 
127
- def upload(release)
128
- tmp = Tempfile.new(["capistrano-releases_upload-#{release}", '.tar.gz'],
147
+ def upload_release(release)
148
+ tmp = Tempfile.new(["capistrano-releases_upload-release-#{release}", '.tar.gz'],
129
149
  Dir.tmpdir, encoding: 'BINARY')
130
150
 
131
151
  begin
@@ -137,8 +157,8 @@ module Capistrano
137
157
  end
138
158
  end
139
159
 
140
- def download(release)
141
- tmp = Tempfile.new(["capistrano-releases_download-#{release}", '.tar.gz'],
160
+ def download_release(release)
161
+ tmp = Tempfile.new(["capistrano-releases_download-release-#{release}", '.tar.gz'],
142
162
  Dir.tmpdir, encoding: 'BINARY')
143
163
 
144
164
  begin
@@ -150,6 +170,40 @@ module Capistrano
150
170
  end
151
171
  end
152
172
 
173
+ def upload_bundle
174
+ return unless Dir.exist?(File.join(local_shared_path, 'bundle'))
175
+
176
+ puts 'Uploading bundle'
177
+
178
+ tmp = Tempfile.new(['capistrano-releases_upload-bundle', '.tar.gz'],
179
+ Dir.tmpdir, encoding: 'BINARY')
180
+
181
+ begin
182
+ system!(['tar', 'Ccfz', local_shared_path, tmp.path, 'bundle'])
183
+ bucket.object('bundle.tar.gz').put(body: tmp)
184
+ ensure
185
+ tmp.close
186
+ tmp.unlink
187
+ end
188
+ end
189
+
190
+ def download_bundle
191
+ return if Dir.exist?(File.join(local_shared_path, 'bundle'))
192
+
193
+ puts 'Downloading bundle'
194
+
195
+ tmp = Tempfile.new(['capistrano-releases_download-bundle', '.tar.gz'],
196
+ Dir.tmpdir, encoding: 'BINARY')
197
+
198
+ begin
199
+ bucket.object('bundle.tar.gz').get(response_target: tmp)
200
+ system!(['tar', 'Cxfz', local_shared_path, tmp.path])
201
+ ensure
202
+ tmp.close
203
+ tmp.unlink
204
+ end
205
+ end
206
+
153
207
  def bucket
154
208
  @bucket ||= Aws::S3::Bucket.new(params[:bucket])
155
209
  end
@@ -1,5 +1,5 @@
1
1
  module Capistrano
2
2
  module Releases
3
- VERSION = '0.1.1'.freeze
3
+ VERSION = '0.2.0'.freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capistrano-releases
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chad Remesch
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-08-31 00:00:00.000000000 Z
11
+ date: 2017-09-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler