capistrano_s3 0.1.1

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