capistrano-releases 0.1.1 → 0.2.0

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.
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