Permalink
Browse files

Add Rackspace Cloud Files support.

  • Loading branch information...
1 parent 99da5b6 commit 681b37958aa2a4dec2030e56a3a880ef99f3bf1f @minter minter committed Dec 8, 2009
Showing with 119 additions and 17 deletions.
  1. +14 −5 README.markdown
  2. +3 −2 Rakefile
  3. +13 −6 astrails-safe.gemspec
  4. +1 −1 bin/astrails-safe
  5. +3 −1 lib/astrails/safe.rb
  6. +66 −0 lib/astrails/safe/cloudfiles.rb
  7. +1 −1 lib/astrails/safe/config/builder.rb
  8. +18 −1 templates/script.rb
View
@@ -1,7 +1,7 @@
astrails-safe
=============
-Simple database and filesystem backups with S3 support (with optional encryption)
+Simple database and filesystem backups with S3 and Rackspace Cloud Files support (with optional encryption)
Home: http://blog.astrails.com/astrails-safe
@@ -15,8 +15,8 @@ We needed a backup solution that will satisfy the following requirements:
* support for simple ‘tar’ backups of directories (with includes/excludes)
* support for simple mysqldump of mysql databases
* support for symmetric or public key encryption
-* support for local filesystem and Amazon S3 for storage
-* support for backup rotation. we don’t want backups filling all the diskspace or cost a fortune on S3
+* support for local filesystem, Amazon S3, and Rackspace Cloud Files for storage
+* support for backup rotation. we don’t want backups filling all the diskspace or cost a fortune on S3 or Cloud Files
And since we didn't find any, we wrote our own :)
@@ -51,7 +51,7 @@ Usage
-h, --help This help screen
-v, --verbose be verbose, duh!
-n, --dry-run just pretend, don't do anything.
- -L, --local skip S3
+ -L, --local skip S3 and Cloud Files
Note: CONFIG_FILE will be created from template if missing
@@ -132,7 +132,15 @@ Example configuration
bucket "backup.astrails.com"
path "servers/alpha/:kind/:id"
end
-
+
+ cloudfiles do
+ username "..........."
+ api_key "................................."
+ container "safe_backup"
+ path ":kind/" # this is default
+ service_net false
+ end
+
sftp do
host "sftp.astrails.com"
user "astrails"
@@ -151,6 +159,7 @@ Example configuration
keep do
local 20
s3 30
+ cloudfiles 30
end
mysqldump do
View
@@ -5,14 +5,15 @@ begin
require 'jeweler'
Jeweler::Tasks.new do |gem|
gem.name = "astrails-safe"
- gem.summary = %Q{Backup filesystem and databases (MySQL and PostgreSQL) to Amazon S3 (with encryption)}
- gem.description = "Simple tool to backup databases (MySQL and PostgreSQL) and filesystem locally or to Amazon S3 (with optional encryption)"
+ gem.summary = %Q{Backup filesystem and databases (MySQL and PostgreSQL) to Amazon S3 and Rackspace Cloud Files (with encryption)}
+ gem.description = "Simple tool to backup databases (MySQL and PostgreSQL) and filesystem locally or to Amazon S3 and Rackspace Cloud Files (with optional encryption)"
gem.email = "we@astrails.com"
gem.homepage = "http://blog.astrails.com/astrails-safe"
gem.authors = ["Astrails Ltd.", "Mark Mansour"]
gem.files = FileList["[A-Z]*.*", "{bin,examples,generators,lib,rails,spec,test,templates}/**/*", 'Rakefile', 'LICENSE*']
gem.add_dependency("aws-s3")
+ gem.add_dependency("cloudfiles")
gem.add_dependency("net-sftp")
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
View
@@ -1,6 +1,6 @@
# Generated by jeweler
-# DO NOT EDIT THIS FILE
-# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
+# DO NOT EDIT THIS FILE DIRECTLY
+# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
# -*- encoding: utf-8 -*-
Gem::Specification.new do |s|
@@ -9,14 +9,15 @@ Gem::Specification.new do |s|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Astrails Ltd.", "Mark Mansour"]
- s.date = %q{2009-10-20}
+ s.date = %q{2009-12-07}
s.default_executable = %q{astrails-safe}
- s.description = %q{Simple tool to backup databases (MySQL and PostgreSQL) and filesystem locally or to Amazon S3 (with optional encryption)}
+ s.description = %q{Simple tool to backup databases (MySQL and PostgreSQL) and filesystem locally or to Amazon S3 and Rackspace Cloud Files (with optional encryption)}
s.email = %q{we@astrails.com}
s.executables = ["astrails-safe"]
s.extra_rdoc_files = [
"LICENSE",
- "README.markdown"
+ "README.markdown",
+ "TODO"
]
s.files = [
"LICENSE",
@@ -39,6 +40,7 @@ Gem::Specification.new do |s|
"lib/astrails/safe.rb",
"lib/astrails/safe/archive.rb",
"lib/astrails/safe/backup.rb",
+ "lib/astrails/safe/cloudfiles.rb",
"lib/astrails/safe/config/builder.rb",
"lib/astrails/safe/config/node.rb",
"lib/astrails/safe/gpg.rb",
@@ -54,14 +56,15 @@ Gem::Specification.new do |s|
"lib/astrails/safe/stream.rb",
"lib/astrails/safe/svndump.rb",
"lib/astrails/safe/tmp_file.rb",
+ "lib/cloudfiles.cf",
"lib/extensions/mktmpdir.rb",
"templates/script.rb"
]
s.homepage = %q{http://blog.astrails.com/astrails-safe}
s.rdoc_options = ["--charset=UTF-8"]
s.require_paths = ["lib"]
s.rubygems_version = %q{1.3.5}
- s.summary = %q{Backup filesystem and databases (MySQL and PostgreSQL) to Amazon S3 (with encryption)}
+ s.summary = %q{Backup filesystem and databases (MySQL and PostgreSQL) to Amazon S3 and Rackspace Cloud Files (with encryption)}
s.test_files = [
"examples/example_helper.rb",
"examples/integration/archive_integration_example.rb",
@@ -83,13 +86,17 @@ Gem::Specification.new do |s|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
s.add_runtime_dependency(%q<aws-s3>, [">= 0"])
+ s.add_runtime_dependency(%q<cloudfiles>, [">= 0"])
s.add_runtime_dependency(%q<net-sftp>, [">= 0"])
else
s.add_dependency(%q<aws-s3>, [">= 0"])
+ s.add_dependency(%q<cloudfiles>, [">= 0"])
s.add_dependency(%q<net-sftp>, [">= 0"])
end
else
s.add_dependency(%q<aws-s3>, [">= 0"])
+ s.add_dependency(%q<cloudfiles>, [">= 0"])
s.add_dependency(%q<net-sftp>, [">= 0"])
end
end
+
View
@@ -20,7 +20,7 @@ Options:
-h, --help This help screen
-v, --verbose be verbose, duh!
-n, --dry-run just pretend, don't do anything.
- -L, --local skip S3
+ -L, --local skip S3 and Cloud Files
Note: config file will be created from template if missing
END
View
@@ -1,4 +1,5 @@
require "aws/s3"
+require "cloudfiles"
require 'net/sftp'
require 'fileutils'
require 'benchmark'
@@ -30,6 +31,7 @@
require 'astrails/safe/sink'
require 'astrails/safe/local'
require 'astrails/safe/s3'
+require 'astrails/safe/cloudfiles'
require 'astrails/safe/sftp'
module Astrails
@@ -48,7 +50,7 @@ def safe(&block)
].each do |klass, path|
if collection = config[*path]
collection.each do |name, config|
- klass.new(name, config).backup.run(config, :gpg, :gzip, :local, :s3, :sftp)
+ klass.new(name, config).backup.run(config, :gpg, :gzip, :local, :s3, :cloudfiles, :sftp)
end
end
end
@@ -0,0 +1,66 @@
+module Astrails
+ module Safe
+ class Cloudfiles < Sink
+
+ protected
+
+ def active?
+ container && username && api_key
+ end
+
+ def path
+ @path ||= expand(config[:cloudfiles, :path] || config[:local, :path] || ":kind/:id")
+ end
+
+ def save
+
+ raise RuntimeError, "pipe-streaming not supported for S3." unless @backup.path
+
+ # needed in cleanup even on dry run
+ cf = CloudFiles::Connection.new(username, api_key, true, service_net) unless $LOCAL
+ puts "Uploading #{container}:#{full_path} from #{@backup.path}" if $_VERBOSE || $DRY_RUN
+ unless $DRY_RUN || $LOCAL
+ benchmark = Benchmark.realtime do
+ cf_container = cf.create_container(container)
+ o = cf_container.create_object(full_path,true)
+ o.write(open(@backup.path))
+ end
+ puts "...done" if $_VERBOSE
+ puts("Upload took " + sprintf("%.2f", benchmark) + " second(s).") if $_VERBOSE
+ end
+ end
+
+ def cleanup
+ return if $LOCAL
+
+ return unless keep = @config[:keep, :cloudfiles]
+
+
+ puts "listing files: #{container}:#{base}*" if $_VERBOSE
+ cf = CloudFiles::Connection.new(username, api_key, true, service_net) unless $LOCAL
+ files = cf.container(container).objects(:prefix => base)
+
+ cleanup_with_limit(files, keep) do |f|
+ puts "removing Cloud File #{container}:#{f}" if $DRY_RUN || $_VERBOSE
+ cf.container(container).delete_object(f) unless $DRY_RUN || $LOCAL
+ end
+ end
+
+ def container
+ @config[:cloudfiles, :container]
+ end
+
+ def username
+ @config[:cloudfiles, :username]
+ end
+
+ def api_key
+ @config[:cloudfiles, :api_key]
+ end
+
+ def service_net
+ @config[:cloudfiles, :service_net] || false
+ end
+ end
+ end
+end
@@ -3,7 +3,7 @@ module Safe
module Config
class Builder
COLLECTIONS = %w/database archive repo/
- ITEMS = %w/s3 key secret bucket path gpg password keep local mysqldump pgdump options
+ ITEMS = %w/s3 cloudfiles key secret bucket username api_key container service_net path gpg password keep local mysqldump pgdump options
user host port socket skip_tables tar files exclude filename svndump repo_path sftp/
NAMES = COLLECTIONS + ITEMS
def initialize(node)
View
@@ -23,7 +23,24 @@
## alternative style:
# s3 :key => YOUR_S3_KEY, :secret => YOUR_S3_SECRET, :bucket => S3_BUCKET, :path => ":kind/"
-
+
+ ## uncomment to enable uploads to Rackspace Cloud Files
+ ## http://www.rackspacecloud.com/cloud_hosting_products/files
+ ## Rackspace auth (optional)
+ # cloudfiles do
+ # username "YOUR_RACKSPACE_CLOUD_USERNAME"
+ # api_key "YOUR_RACKSPACE_API_KEY"
+ # container "YOUR_CONTAINER_NAME"
+ # # path for uploads to Cloud Files, supports same substitution like :local/:path
+ # path ":kind/" # this is default
+ # # If you are running the backup from a system within the Rackspace/Slicehost network and would like
+ # # to back up over the private (unbilled) service net, set this value to true.
+ # # service_net true
+ # end
+
+ ## alternative style:
+ # cloudfiles :username => YOUR_RACKSPACE_USERNAME, :api_key => YOUR_RACKSPACE_API_KEY, :container => CONTAINER_NAME, :path => ":kind/"
+
## uncomment to enable uploads via SFTP
# sftp do
# host "YOUR_REMOTE_HOSTNAME"

0 comments on commit 681b379

Please sign in to comment.