capistrano_s3 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Bill Kirtley <bill@virosity.com>
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 ADDED
@@ -0,0 +1,31 @@
1
+ = Introduction
2
+
3
+ Capistrano-S3 is a capistrano deployment strategy that will:
4
+
5
+ * svn export locally
6
+ * make a tarball (named after the svn revision) of the release
7
+ * push the tarball to S3
8
+ * each server pulls that tarball from S3
9
+
10
+ This allows one to use an svn repository not exposed to the outside world, save time pushing out of a poky cable modem, and have new EC2 instances pull directly from S3 on startup.
11
+
12
+ If the tarball is already in S3 (from a previous deployment, say to a staging instance) the checkout is skipped.
13
+
14
+ = Installation
15
+ gem install capistrano_s3
16
+
17
+ To use it, specify properties in <tt>config/deploy.rb</tt>:
18
+ set :deploy_via, :s3_bucket
19
+ set :deploy_s3_bucket, 'com.example.releases' # The name of the S3 bucket that should get releases
20
+ s3_config = YAML::load(ERB.new(IO.read("secret/s3.yml")).result) # Follow this pattern and don't ckin your secrets
21
+ # s3_config = { 'AWS_ACCOUNT_NUMBER' => '1234-5678-9012', 'AWS_ACCESS_KEY_ID' => 'ABCDEFGHIJKLMNOPQRST', 'AWS_SECRET_ACCESS_KEY' => 'abcdefghijklmnopqrstuvwxyz01234567890ABC' }
22
+ set :s3_config, s3_config
23
+
24
+ Now regular capistrano deployment tasks will go through S3
25
+
26
+ = About
27
+
28
+ Rubyforge Project:: http://rubyforge.org/projects/capistrano-s3
29
+ Author:: Bill Kirtley - bill at [nospam] virosity dt com
30
+ License:: Distributed under MIT License
31
+ Copyright:: 2008 Bill Kirtley, Virosity Inc.
@@ -0,0 +1,96 @@
1
+ require 'capistrano/recipes/deploy/strategy/copy'
2
+ require 'fileutils'
3
+ require 'tempfile' # Dir.tmpdir
4
+
5
+ #implementing a capistrano deploy strategy that:
6
+ # - Expects a deploy_bucket it can read from and write to
7
+ # - Uses configuration[:s3_config] to find creds
8
+ # - Names releases {application}_{revision}.tgz
9
+ # - Looks in the bucket for a file with that name - skip to actual deployment if found
10
+ # - Checks out the specified revision, bundles it up, and pushes to the S3 bucket
11
+ # - depends on the s3cmd command, perhaps installed with `gem install s3sync`
12
+
13
+ # Copyright 2008 Bill Kirtley, Virosity Inc.
14
+ # Distributed via MIT license
15
+ # Feedback appreciated: bill at [nospam] virosity dt com
16
+
17
+ module Capistrano
18
+ module Deploy
19
+ module Strategy
20
+
21
+ class S3Bucket < Copy
22
+
23
+ def deploy!
24
+ logger.debug "getting (via #{copy_strategy}) revision #{revision} to #{destination}"
25
+ logger.debug "#{configuration[:release_path]} #{File.basename(configuration[:release_path])}"
26
+ put_package
27
+
28
+ run "#{aws_environment} s3cmd get #{bucket_name}:#{package_name} #{remote_filename}"
29
+ run "mkdir #{configuration[:release_path]} && cd #{configuration[:release_path]} && #{decompress(remote_filename).join(" ")} && rm #{remote_filename}"
30
+ logger.debug "done!"
31
+ end
32
+
33
+ #!! implement me!
34
+ # Performs a check on the remote hosts to determine whether everything
35
+ # is setup such that a deploy could succeed.
36
+ # def check!
37
+ # end
38
+
39
+ private
40
+ def aws_environment
41
+ @aws_environment ||= "AWS_ACCOUNT_NUMBER=#{configuration[:s3_config]['AWS_ACCOUNT_NUMBER']} AWS_ACCESS_KEY_ID=#{configuration[:s3_config]['AWS_ACCESS_KEY_ID']} AWS_SECRET_ACCESS_KEY=#{configuration[:s3_config]['AWS_SECRET_ACCESS_KEY']}"
42
+ end
43
+ # Responsible for ensuring that the package for the current revision is in the bucket
44
+ def put_package
45
+ set :release_name, revision
46
+ logger.debug "#{package_name} already in bucket #{bucket_name}" and return if bucket_includes_package
47
+ logger.debug "#{package_name} not found in bucket #{bucket_name} so ckout to add it"
48
+
49
+ # Do the checkout locally
50
+ system(command)
51
+ File.open(File.join(destination, "REVISION"), "w") { |f| f.puts(revision) }
52
+
53
+ # Compress it
54
+ logger.trace "compressing in #{destination}"
55
+ logger.trace compress('*', package_path).join(" ")
56
+
57
+ Dir.chdir(destination) { system(compress('*', package_path).join(" ")) }
58
+
59
+ # Put to S3
60
+ logger.trace "pushing to S3 bucket #{bucket_name} key #{package_name}"
61
+ system("s3cmd put #{bucket_name}:#{package_name} #{package_path}")
62
+ end
63
+
64
+ def bucket_includes_package
65
+ /#{package_name}/.match(`s3cmd list #{bucket_name}:#{package_name}`)
66
+ end
67
+
68
+ def package_name
69
+ @package_name ||= "#{configuration[:application]}_#{revision}.tgz"
70
+ end
71
+
72
+ def package_path
73
+ @package_path ||= File.join(tmpdir, package_name)
74
+ end
75
+
76
+ def bucket_name
77
+ configuration[:deploy_s3_bucket]
78
+ end
79
+
80
+ def bucket
81
+ @bucket ||= Bucket.find(bucket_name) or raise "Failed to find bucket #{configuration[:deploy_s3_bucket]}"
82
+ end
83
+
84
+ def initialize(config={})
85
+ super(config)
86
+
87
+ raise "Failed to find :s3_config" unless configuration[:s3_config]
88
+ # Annoying that merge doesnt work because ENV isn't really a Hash:
89
+ # ENV.merge(configuration[:s3_config])
90
+ configuration[:s3_config].each_pair { |name, value| ENV[name] = value }
91
+ end
92
+
93
+ end
94
+ end
95
+ end
96
+ end
data/lib/version.rb ADDED
@@ -0,0 +1,9 @@
1
+ module Capistrano_S3 #:nodoc:
2
+ module Version #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ TINY = 1
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -0,0 +1,62 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ require 'capistrano/logger'
4
+ require 'capistrano/recipes/deploy/strategy/s3_bucket'
5
+ require 'stringio'
6
+
7
+ context "Capistrano::Deploy::Strategy::S3Bucket" do
8
+ def setup
9
+ logger = Capistrano::Logger.new(:output => StringIO.new)
10
+ # Uncomment this line to see the output a cap user would see for debugging
11
+ # logger = Capistrano::Logger.new
12
+ logger.level = Capistrano::Logger::MAX_LEVEL
13
+ @config = { :application => "testapp",
14
+ :logger => logger,
15
+ :releases_path => "/u/apps/test/releases",
16
+ :release_path => "/u/apps/test/releases/1234567890",
17
+ :real_revision => "154",
18
+ :deploy_s3_bucket => 'com.example.bucket',
19
+ :s3_config => {'AWS_ACCOUNT_NUMBER' => '1234-5678-9012',
20
+ 'AWS_ACCESS_KEY_ID' => 'ABCDEFGHIJKLMNOPQRST',
21
+ 'AWS_SECRET_ACCESS_KEY' => 'abcdefghijklmnopqrstuvwxyz01234567890ABC' }
22
+ }
23
+ @source = mock("source")
24
+ @config.stubs(:source).returns(@source)
25
+ @config.stubs(:set)
26
+ @strategy = Capistrano::Deploy::Strategy::S3Bucket.new(@config)
27
+ Dir.stubs(:tmpdir).returns("/temp/dir")
28
+ end
29
+
30
+ specify "does not push to S3 if already there" do
31
+ @strategy.expects(:`).returns("--------------------\ncom.example.bucket:testapp_154.tgz")
32
+ prepare_deploy
33
+ @strategy.deploy!
34
+ end
35
+
36
+ specify "does push to S3 if not already there" do
37
+ @strategy.expects(:`).returns("--------------------\n")
38
+ prepare_deploy
39
+ @source.expects(:checkout).with("154", "/temp/dir/1234567890").returns(:local_checkout)
40
+ @strategy.expects(:system).with(:local_checkout)
41
+ File.expects(:open).with('/temp/dir/1234567890/REVISION', 'w')
42
+ Dir.expects(:chdir).with("/temp/dir/1234567890").yields
43
+ @strategy.expects(:system).with('tar czf /temp/dir/testapp_154.tgz *')
44
+ @strategy.expects(:system).with('s3cmd put com.example.bucket:testapp_154.tgz /temp/dir/testapp_154.tgz')
45
+ @strategy.deploy!
46
+ end
47
+
48
+ private
49
+
50
+ def aws_credential_envs
51
+ "AWS_ACCOUNT_NUMBER=1234-5678-9012 AWS_ACCESS_KEY_ID=ABCDEFGHIJKLMNOPQRST AWS_SECRET_ACCESS_KEY=abcdefghijklmnopqrstuvwxyz01234567890ABC"
52
+ end
53
+
54
+ # These are expected for any deploy
55
+ def prepare_deploy
56
+ @strategy.expects(:run).with("#{aws_credential_envs} s3cmd get com.example.bucket:testapp_154.tgz /tmp/1234567890.tar.gz")
57
+ @strategy.expects(:run).with("mkdir /u/apps/test/releases/1234567890 && cd /u/apps/test/releases/1234567890 && tar xzf /tmp/1234567890.tar.gz && rm /tmp/1234567890.tar.gz")
58
+ end
59
+
60
+ end
61
+
62
+
@@ -0,0 +1,18 @@
1
+ $:.unshift 'lib/', File.dirname(__FILE__) + '/../lib'
2
+
3
+ require 'rubygems'
4
+
5
+ try = proc do |library, version|
6
+ begin
7
+ dashed = library.gsub('/','-')
8
+ require library
9
+ gem dashed, version
10
+ rescue LoadError
11
+ puts "=> You need the #{library} gem to run these tests.",
12
+ "=> $ sudo gem install #{dashed}"
13
+ exit
14
+ end
15
+ end
16
+
17
+ try['test/spec', '>= 0.3']
18
+ try['mocha', '>= 0.4']
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capistrano_s3
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Bill Kirtley
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-06-06 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: capistrano
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 2.1.0
23
+ version:
24
+ - !ruby/object:Gem::Dependency
25
+ name: s3sync
26
+ version_requirement:
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: "0"
32
+ version:
33
+ description: A deployment strategy for capistrano using S3
34
+ email: bill@virosity.com
35
+ executables: []
36
+
37
+ extensions: []
38
+
39
+ extra_rdoc_files: []
40
+
41
+ files:
42
+ - lib/capistrano
43
+ - lib/capistrano/recipes
44
+ - lib/capistrano/recipes/deploy
45
+ - lib/capistrano/recipes/deploy/strategy
46
+ - lib/capistrano/recipes/deploy/strategy/s3_bucket.rb
47
+ - lib/version.rb
48
+ - test/deploy_s3_bucket_test.rb
49
+ - test/test_helper.rb
50
+ - README
51
+ - MIT-LICENSE
52
+ has_rdoc: true
53
+ homepage: http://virosity.com
54
+ post_install_message:
55
+ rdoc_options: []
56
+
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: "0"
70
+ version:
71
+ requirements: []
72
+
73
+ rubyforge_project: capistrano-s3
74
+ rubygems_version: 1.0.1
75
+ signing_key:
76
+ specification_version: 2
77
+ summary: A deployment strategy for capistrano using S3
78
+ test_files: []
79
+