rubypond-s3backup-manager 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc ADDED
@@ -0,0 +1,8 @@
1
+ = s3backup-manager
2
+
3
+ The beginnings of a system for managing offsite encrypted backups using
4
+ AmazonS3.
5
+
6
+ == Copyright
7
+
8
+ Copyright (c) 2009 Glenn Gillen. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,41 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/gempackagetask'
4
+ require 'spec/rake/spectask'
5
+ require 'rake/rdoctask'
6
+
7
+ spec_data = File.open('s3backup-manager.gemspec').read
8
+ spec = nil
9
+ Thread.new do
10
+ spec = eval("$SAFE = 3\n#{spec_data}")
11
+ end.join
12
+
13
+ Rake::GemPackageTask.new(spec) do |pkg|
14
+ pkg.need_zip = false
15
+ pkg.need_tar = false
16
+ end
17
+
18
+ task :default => :spec
19
+
20
+ Rake::RDocTask.new do |rdoc|
21
+ if File.exist?('VERSION.yml')
22
+ config = YAML.load(File.read('VERSION.yml'))
23
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
24
+ else
25
+ version = ""
26
+ end
27
+
28
+ rdoc.rdoc_dir = 'rdoc'
29
+ rdoc.title = "s3backup-manager #{version}"
30
+ rdoc.rdoc_files.include('README*')
31
+ rdoc.rdoc_files.include('lib/**/*.rb')
32
+ end
33
+
34
+ desc "Run all specs"
35
+ Spec::Rake::SpecTask.new do |t|
36
+ t.spec_files = Dir['spec/**/*_spec.rb']
37
+ t.spec_opts = ['--options', 'spec/spec.opts']
38
+ t.rcov = false
39
+ # t.rcov_dir = '../doc/output/coverage'
40
+ # t.rcov_opts = ['--exclude', 'spec\/spec,bin\/spec,examples,\/var\/lib\/gems,\.autotest']
41
+ end
data/config/config.yml ADDED
@@ -0,0 +1,4 @@
1
+ aws_access_key_id:
2
+ aws_secret_access_key:
3
+ encryption_secret:
4
+ collection_prefix:
@@ -0,0 +1,24 @@
1
+ monthly_run_day: 7
2
+ weekly_run_day: Sun
3
+ daily_run_time: 04:13
4
+ hourly_run_minute: 47
5
+
6
+ hourlies:
7
+ database:
8
+ adapter: postgres
9
+ database: longpockets_production
10
+ dailies:
11
+ filesystem: /var/www/apps/rubypond
12
+ filesystem: /var/www/apps/longpockets
13
+ filesystem: /var/www/apps/cms
14
+
15
+ weeklies:
16
+ database:
17
+ adapter: postgres
18
+ database: rubypond_production
19
+
20
+ database:
21
+ adapter: couchdb
22
+ database: rubypond_production
23
+
24
+ monthlies:
@@ -0,0 +1,23 @@
1
+ module MysqlAdapter
2
+
3
+ def dump_all_databases_to_file(filename)
4
+ # `mysqldump --user=root --password=yourrootsqlpassword --lock-all-tables \
5
+ # --all-databases > #{filename}`
6
+ end
7
+
8
+ def dump_database_to_file(database, filename)
9
+ # `mysqldump --opt -h hostname -u user -p password #{database} > #{filename}`
10
+ end
11
+
12
+ def restore_database_from_file(database, filename)
13
+ # `mysql - u user_name -p your_password #{database} < #{filename}`
14
+ end
15
+
16
+ private
17
+ def get_all_databases
18
+ # `mysql -u root -h localhost -ppassword -Bse 'show databases'`
19
+ end
20
+
21
+ def recreate_database(database)
22
+ end
23
+ end
@@ -0,0 +1,24 @@
1
+ module S3BackupManager
2
+ module PostgresAdapter
3
+
4
+ def dump_database_to_file(filename, options = {})
5
+ database = options[:database]
6
+ username = options[:username]
7
+ system "sudo -u #{username} vacuumdb -z #{database} >/dev/null 2>&1"
8
+ exit(1) unless $?.success?
9
+ system "sudo -u #{username} pg_dump --blobs --format=t #{database} > #{filename}"
10
+ exit(1) unless $?.success?
11
+ end
12
+
13
+ def restore_database_from_file(database, filename)
14
+ `sudo -u postgres pg_restore --format=t -d #{database} #{filename}`
15
+ end
16
+
17
+ private
18
+ def recreate_database(database)
19
+ `sudo -u postgres dropdb #{database}`
20
+ `sudo -u postgres createdb --encoding=UNICODE #{database}`
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,64 @@
1
+ %w{rubygems sinatra haml sass}.each do |lib|
2
+ require lib
3
+ end
4
+
5
+ Dir["models/*"].each do |model|
6
+ require model
7
+ end
8
+
9
+ get '/' do
10
+ @buckets = Bucket.find_all
11
+ haml :index
12
+ end
13
+
14
+ get '/new' do
15
+ haml :new
16
+ end
17
+
18
+ post '/' do
19
+ begin
20
+ Bucket.create!(params[:collection_name])
21
+ flash[:notice] = "Successfully created new backup collection"
22
+ redirect "/"
23
+ rescue AWS::S3::InvalidBucketName => exception
24
+ flash[:error] = exception.message
25
+ haml :new
26
+ end
27
+ end
28
+
29
+ get '/:id' do
30
+ haml :show
31
+ end
32
+
33
+ get '/:id/files' do
34
+ haml :files
35
+ end
36
+
37
+ get '/:id/databases' do
38
+ hamls :databases
39
+ end
40
+
41
+ get '/stylesheet.css' do
42
+ content_type 'text/css', :charset => 'utf-8'
43
+ sass :stylesheet
44
+ end
45
+
46
+ def flash
47
+ session[:flash] = {} if session[:flash] && session[:flash].class != Hash
48
+ session[:flash] ||= {}
49
+ end
50
+
51
+ template :layout do
52
+ %Q{
53
+ !!!
54
+ %html
55
+ %head
56
+ %title My Title Here
57
+ %body
58
+ - if flash
59
+ - flash.each do |type,message|
60
+ %p{ :class=> "message #{type}" }= message
61
+ - flash.clear
62
+ = yield
63
+ }
64
+ end
@@ -0,0 +1,78 @@
1
+ module S3BackupManager
2
+ module BucketError
3
+ class NoNameError < StandardError; end
4
+ class NoConfigError < StandardError; end
5
+ class NoBucketFoundError < StandardError; end
6
+ end
7
+
8
+ class Bucket
9
+ attr_accessor :name
10
+ attr_accessor :s3_bucket
11
+
12
+ def initialize(name)
13
+ @name = name
14
+ end
15
+
16
+ def self.find_all
17
+ connect!
18
+ AWS::S3::Service.buckets.select{|b| b.name =~ %r{^#{config["collection_prefix"]}_}}.map{|b| b.name.sub(%r{^#{config["collection_prefix"]}_},"")}
19
+ end
20
+
21
+ def self.find(id)
22
+ connect!
23
+ bucket = AWS::S3::Bucket.find(expand_name(id))
24
+ initialize_with_bucket(id, bucket)
25
+ rescue AWS::S3::CurrentBucketNotSpecified
26
+ raise BucketError::NoNameError
27
+ rescue AWS::S3::NoSuchBucket
28
+ raise BucketError::NoBucketFoundError
29
+ end
30
+
31
+ def self.create!(name)
32
+ raise BucketError::NoNameError.new if name.nil? || name.strip == ""
33
+ connect!
34
+ AWS::S3::Bucket.create("#{config["collection_prefix"]}_#{name}")
35
+ end
36
+
37
+ def store(filename, data)
38
+ AWS::S3::S3Object.store(filename, data, bucket_name)
39
+ end
40
+
41
+ def retrieve(filename)
42
+ AWS::S3::S3Object.value(filename, bucket_name)
43
+ end
44
+
45
+ def files
46
+ @s3_bucket.objects
47
+ end
48
+
49
+ private
50
+ def self.initialize_with_bucket(name, bucket)
51
+ this_bucket = new(name)
52
+ this_bucket.s3_bucket = bucket
53
+ this_bucket
54
+ end
55
+
56
+ def self.config
57
+ YAML.load_file("/etc/s3backup-manager/config.yml")
58
+ rescue Errno::ENOENT
59
+ raise S3BackupManager::BucketError::NoConfigError.new(
60
+ "No configuration file could be found at /etc/s3backup-manager/config.yml")
61
+ end
62
+
63
+ def self.expand_name(name)
64
+ "#{config["collection_prefix"]}_#{name}"
65
+ end
66
+
67
+ def self.connect!
68
+ AWS::S3::Base.establish_connection!(
69
+ :access_key_id => config["aws_access_key_id"],
70
+ :secret_access_key => config["aws_secret_access_key"]
71
+ )
72
+ end
73
+
74
+ def bucket_name
75
+ Bucket.expand_name(name)
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,43 @@
1
+ module S3BackupManager
2
+ class DatabaseBackup < FileBackup
3
+ def initialize(opts = {})
4
+ @options = opts
5
+ super
6
+ case @options[:adapter]
7
+ when "postgres"
8
+ self.extend S3BackupManager::PostgresAdapter
9
+ when "mysql"
10
+ self.extend ::S3BackupManager::MysqlAdapter
11
+ when "couchdb"
12
+ self.extend ::S3BackupManager::PostgresAdapter
13
+ end
14
+ self
15
+ end
16
+
17
+ def files
18
+ bucket.files.select{|f| f.key.match(%r{^databases/})}
19
+ end
20
+
21
+ def backup(database)
22
+ filename = "/tmp/#{database}"
23
+ dump_database_to_file(filename, @options.merge(:database => database))
24
+ super(filename, "databases/#{@options[:adapter]}")
25
+ end
26
+
27
+ def restore(database, timestamp)
28
+ filename = "#{@options[:adapter]}/#{timestamp}/#{database}"
29
+ @dumped_filename = "/tmp/#{random_string}"
30
+ super(filename, timestamp, @dumped_filename, "databases")
31
+ restore_database_from_file(@dumped_filename, @options)
32
+ db_cleanup!
33
+ end
34
+
35
+ private
36
+ def db_cleanup!
37
+ if @dumped_filename
38
+ File.delete(@dumped_filename)
39
+ @dumped_filename = nil
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,110 @@
1
+ module S3BackupManager
2
+ module FileBackupError
3
+ class NoBucketError < StandardError; end
4
+ end
5
+
6
+ class FileBackup
7
+ attr_accessor :bucket
8
+
9
+ def initialize(opts = {})
10
+ @bucket = Bucket.find(opts[:bucket])
11
+ super()
12
+ end
13
+
14
+ def files
15
+ bucket.files.select{|f| f.key.match(%r{^filesystem/})}
16
+ end
17
+
18
+ def backup(file, directory = "filesystem")
19
+ stored_file_name = "#{Time.now.strftime("%Y%m%d%H%M%S")}/#{File.basename(file)}"
20
+ encrypted_file = encrypt(pack(file))
21
+ bucket.store("#{directory}/#{stored_file_name}", open(encrypted_file))
22
+ cleanup!
23
+ end
24
+
25
+ def restore(file, timestamp, destination, directory = "filesystem")
26
+ if file.match(timestamp)
27
+ data = bucket.retrieve("#{directory}/#{file}")
28
+ else
29
+ data = bucket.retrieve("#{directory}/#{timestamp}/#{file}")
30
+ end
31
+ decrypted_file = decrypt(file, timestamp, data)
32
+ unpack(decrypted_file, destination)
33
+ cleanup!
34
+ end
35
+
36
+ private
37
+ def cleanup!
38
+ if @encrypted_filename
39
+ File.delete(@encrypted_filename)
40
+ @encrypted_filename = nil
41
+ end
42
+ if @packed_filename
43
+ File.delete(@packed_filename)
44
+ @packed_filename = nil
45
+ end
46
+ if @decrypted_filename
47
+ File.delete(@decrypted_filename)
48
+ @decrypted_filename = nil
49
+ end
50
+ end
51
+
52
+ def encrypt(file)
53
+ aes = OpenSSL::Cipher::Cipher.new("AES-256-CBC")
54
+ aes.encrypt
55
+ aes.key = Digest::SHA256.digest(FileBackup.config["encryption_secret"])
56
+ aes.iv = Digest::SHA256.digest(Time.now.strftime("%Y%m%d"))
57
+
58
+ @encrypted_filename = "#{random_string}_#{File.basename(file)}"
59
+ File.open(@encrypted_filename, 'w') do |enc|
60
+ File.open(file) do |f|
61
+ loop do
62
+ r = f.read(4096)
63
+ break unless r
64
+ cipher = aes.update(r)
65
+ enc << cipher
66
+ end
67
+ end
68
+ enc << aes.final
69
+ end
70
+ @encrypted_filename
71
+ end
72
+
73
+ def decrypt(filename, timestamp, data)
74
+ aes = OpenSSL::Cipher::Cipher.new("AES-256-CBC")
75
+ aes.decrypt
76
+ aes.key = Digest::SHA256.digest(FileBackup.config["encryption_secret"])
77
+ aes.iv = Digest::SHA256.digest(timestamp[0...8])
78
+ @decrypted_filename = "#{random_string}_#{File.basename(filename)}"
79
+ File.open(@decrypted_filename, 'w') do |dec|
80
+ dec.write aes.update(data)
81
+ dec.write aes.final
82
+ end
83
+ @decrypted_filename
84
+ end
85
+
86
+ def pack(file)
87
+ @packed_filename = "#{random_string}_#{File.basename(file)}.tgz"
88
+ tgz = Zlib::GzipWriter.new(File.open(@packed_filename, 'wb'))
89
+ Archive::Tar::Minitar.pack("#{file}", tgz, recurse_directories = true)
90
+ @packed_filename
91
+ end
92
+
93
+ def unpack(file, destination)
94
+ tgz = Zlib::GzipReader.new(File.open(file, 'rb'))
95
+ Archive::Tar::Minitar.unpack(tgz, destination)
96
+ end
97
+
98
+ def random_string
99
+ o = [('a'..'z'),('A'..'Z')].map{|i| i.to_a}.flatten
100
+ (0..50).map{ o[rand(o.length)] }.join
101
+ end
102
+
103
+ def self.config
104
+ YAML.load_file("/etc/s3backup-manager/config.yml")
105
+ rescue Errno::ENOENT
106
+ raise S3BackupManager::BucketError::NoConfigError.new(
107
+ "No configuration file could be found at /etc/s3backup-manager/config.yml")
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,30 @@
1
+ class Schedule
2
+
3
+ def self.find_pending
4
+ if Time.now.min == config["hourly_run_minute"]
5
+ run_hourlies
6
+ end
7
+ if Time.now.strftime("%H:%M") == config["daily_run_time"]
8
+ run_dailies
9
+ end
10
+ # if Time.n
11
+ end
12
+
13
+ private
14
+ def self.run_hourlies
15
+ end
16
+
17
+ def self.run_dailies
18
+ end
19
+
20
+ def self.run_monthlies
21
+ end
22
+
23
+ def self.run_weeklies
24
+ end
25
+
26
+ def self.config
27
+ YAML.load_file("#{File.dirname(__FILE__)}/../config/schedule.yml")
28
+ end
29
+
30
+ end
@@ -0,0 +1,13 @@
1
+ require 'aws/s3'
2
+ require 'zlib'
3
+ require 'archive/tar/minitar'
4
+ require 'yaml'
5
+
6
+ Dir["#{File.dirname(__FILE__)}/adapters/*"].each do |lib|
7
+ require lib
8
+ end
9
+
10
+ require "#{File.dirname(__FILE__)}/models/bucket"
11
+ require "#{File.dirname(__FILE__)}/models/file_backup"
12
+ require "#{File.dirname(__FILE__)}/models/database_backup"
13
+ require "#{File.dirname(__FILE__)}/models/schedule"
File without changes
@@ -0,0 +1,14 @@
1
+ require "#{File.dirname(__FILE__)}/../spec_helper.rb"
2
+
3
+ describe MysqlAdapter do
4
+ before(:each) do
5
+ end
6
+
7
+ it "should dump the database to a file" do
8
+ pending
9
+ end
10
+
11
+ it "should import the file into the database" do
12
+ pending
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ require "#{File.dirname(__FILE__)}/../spec_helper.rb"
2
+
3
+ describe PostgresAdapter do
4
+ before(:each) do
5
+ end
6
+
7
+ it "should dump the database to a file" do
8
+ pending
9
+ end
10
+
11
+ it "should import the file into the database" do
12
+ pending
13
+ end
14
+ end
@@ -0,0 +1 @@
1
+ my test data
data/spec/lib/mocks.rb ADDED
@@ -0,0 +1,67 @@
1
+ module S3BackupManager
2
+ module Mocks
3
+
4
+ def mock_bucket
5
+ stub_aws
6
+ stub_bucket_find
7
+ @bucket.stub!(:store)
8
+ end
9
+
10
+ def mock_filesystem_files
11
+ @lines = mock("lines")
12
+ @lines.stub!(:each).and_yield(["my data here"])
13
+ @lines.stub!(:write)
14
+ end
15
+
16
+ def mock_filebackup_dependencies
17
+ mock_filesystem_files
18
+ @encrypter = mock("aes", :key= => nil, :iv= => nil, :final => nil)
19
+ @encrypter.stub!(:encrypt)
20
+ @encrypter.stub!(:decrypt)
21
+ OpenSSL::Cipher::Cipher.stub!(:new).with("AES-256-CBC").and_return(@encrypter)
22
+
23
+ FileBackup.stub!(:open)
24
+ File.stub!(:delete)
25
+ Zlib::GzipWriter.stub!(:new)
26
+ Zlib::GzipReader.stub!(:new)
27
+ Archive::Tar::Minitar.stub!(:pack)
28
+ end
29
+
30
+ def mock_backup_files
31
+ files = [mock("aws_object", :key => "filesystem/filename1.txt"),
32
+ mock("aws_object", :key => "filesystem/filename2.txt"),
33
+ mock("aws_object", :key => "filesystem/filename3.txt"),
34
+ mock("aws_object", :key => "databases/db1.txt"),
35
+ mock("aws_object", :key => "databases/db2.txt")]
36
+ @bucket.stub!(:files).and_return(files)
37
+ end
38
+
39
+ def stub_aws
40
+ stub_bucket_config
41
+ stub_aws_connection
42
+ end
43
+
44
+ def stub_bucket_config
45
+ YAML.stub!(:load_file).with(
46
+ "/etc/s3backup-manager/config.yml").and_return(
47
+ {"aws_access_key_id" => "unique_key_id",
48
+ "aws_secret_access_key" => "sekret_keyz",
49
+ "encryption_secret" => "hrrmm_how_secret?",
50
+ "collection_prefix" => "backup_collection_name"})
51
+ end
52
+
53
+ def stub_aws_connection
54
+ AWS::S3::Base.stub!(:establish_connection!)
55
+ end
56
+
57
+ def stub_bucket_find
58
+ @bucket = mock("bucket")
59
+ Bucket.stub!(:find).and_return(@bucket)
60
+ end
61
+
62
+ def stub_aws_find
63
+ AWS::S3::Bucket.stub!(:find).and_return(mock("aws_bucket"))
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,83 @@
1
+ require "#{File.dirname(__FILE__)}/../spec_helper.rb"
2
+
3
+ describe Bucket do
4
+
5
+ describe "when there is no configuration file" do
6
+ it "should raise a config file missing error" do
7
+ lambda do
8
+ Bucket.find_all
9
+ end.should raise_error(S3BackupManager::BucketError::NoConfigError)
10
+ end
11
+ end
12
+
13
+ describe "when there is a configuration file" do
14
+ before(:each) do
15
+ stub_aws
16
+ AWS::S3::Service.stub!(:buckets).and_return([
17
+ mock("bucket", :name => "backup_collection_name_bucket_1"),
18
+ mock("bucket", :name => "backup_collection_name_bucket_2"),
19
+ mock("bucket", :name => "backup_collection_name_bucket_3")
20
+ ])
21
+ end
22
+
23
+ it "should connect using the credentials in the file" do
24
+ AWS::S3::Base.should_receive(:establish_connection!).with(
25
+ :access_key_id => "unique_key_id",
26
+ :secret_access_key => "sekret_keyz")
27
+ Bucket.find_all
28
+ end
29
+
30
+ it "should it should find a bucket by name" do
31
+ AWS::S3::Bucket.should_receive(:find).with("backup_collection_name_bucket_name")
32
+ Bucket.find("bucket_name")
33
+ end
34
+
35
+ it "should find all buckets and strip off collection prefix" do
36
+ Bucket.find_all.should be_include("bucket_1")
37
+ end
38
+
39
+ describe "when creating a new bucket" do
40
+ it "should create it" do
41
+ AWS::S3::Bucket.should_receive(:create).with(
42
+ "backup_collection_name_new_bucket")
43
+ Bucket.create!("new_bucket")
44
+ end
45
+
46
+ it "should raise an error if no name provided" do
47
+ lambda do
48
+ Bucket.create!("")
49
+ end.should raise_error(S3BackupManager::BucketError::NoNameError)
50
+ end
51
+ end
52
+
53
+ describe "when managing files in a bucket" do
54
+ before(:each) do
55
+ @bucket = Bucket.new("test_bucket")
56
+ AWS::S3::S3Object.stub!(:store)
57
+ AWS::S3::S3Object.stub!(:value)
58
+ end
59
+
60
+ it "should store the data" do
61
+ AWS::S3::S3Object.should_receive(:store).with(
62
+ "filename.txt","some data here", "backup_collection_name_test_bucket")
63
+ @bucket.store("filename.txt","some data here")
64
+ end
65
+
66
+ it "should retrieve the data" do
67
+ AWS::S3::S3Object.should_receive(:value).with(
68
+ "filename.txt", "backup_collection_name_test_bucket").and_return(
69
+ "some data returned")
70
+ @bucket.retrieve("filename.txt").should == "some data returned"
71
+ end
72
+
73
+ it "should list the files in a bucket" do
74
+ AWS::S3::Bucket.stub!(:find).with(
75
+ "backup_collection_name_bucket_name").and_return(
76
+ mock("bucket", :objects => ["file 1", "file 2"]))
77
+ @bucket = Bucket.find("bucket_name")
78
+ @bucket.files.should be_include("file 2")
79
+ end
80
+ end
81
+ end
82
+
83
+ end
@@ -0,0 +1,26 @@
1
+ require "#{File.dirname(__FILE__)}/../spec_helper.rb"
2
+
3
+ describe DatabaseBackup do
4
+ before(:each) do
5
+ end
6
+
7
+ it "should return just database files" do
8
+ pending
9
+ end
10
+
11
+ it "should dump the database to a file" do
12
+ pending
13
+ end
14
+
15
+ it "should backup the dumped file" do
16
+ pending
17
+ end
18
+
19
+ it "should restore the backup to a file" do
20
+ pending
21
+ end
22
+
23
+ it "should import the file into the database" do
24
+ pending
25
+ end
26
+ end
@@ -0,0 +1,71 @@
1
+ require "#{File.dirname(__FILE__)}/../spec_helper.rb"
2
+
3
+ describe FileBackup do
4
+ before(:each) do
5
+ mock_bucket
6
+ mock_backup_files
7
+ mock_filebackup_dependencies
8
+ @file_backup = FileBackup.new(:bucket => "test_bucket")
9
+ @file_backup.stub!(:open)
10
+ end
11
+
12
+ it "should return just filesystem files" do
13
+ @file_backup.files.detect{|f| f.key =~ /filename1/}.should be
14
+ @file_backup.files.detect{|f| f.key =~ /filename2/}.should be
15
+ end
16
+
17
+ it "should pack the file/directory into a tarball" do
18
+ tgz_mock = mock("tgz")
19
+ Zlib::GzipWriter.should_receive(:new).and_return(tgz_mock)
20
+ Archive::Tar::Minitar.should_receive(:pack).with(
21
+ "somefile.txt", tgz_mock, true)
22
+ @file_backup.backup("somefile.txt")
23
+ end
24
+
25
+ it "should encrypt the data" do
26
+ @encrypter.should_receive(:encrypt)
27
+ # @encrypter.should_receive(:update)
28
+ @file_backup.backup("#{File.dirname(__FILE__)}/../fixtures/test_backup_file.txt")
29
+ end
30
+
31
+ it "should decrypt the data" do
32
+ pending
33
+ end
34
+
35
+ it "should unpack the tarball into a file/directory" do
36
+ pending
37
+ end
38
+
39
+ it "should backup the packed & encrypted file in the bucket" do
40
+ pending
41
+ end
42
+
43
+ it "should restore the file/directory" do
44
+ pending
45
+ end
46
+
47
+ it "should cleanup any temporary files" do
48
+ pending
49
+ end
50
+
51
+ it "should timestamp the backups" do
52
+ pending
53
+ end
54
+
55
+ it "should encrypt using the configured secret" do
56
+ pending
57
+ end
58
+
59
+ it "should encrypt using the current day as an initialization vector" do
60
+ pending
61
+ end
62
+
63
+ it "should decrypt using the configured secret" do
64
+ pending
65
+ end
66
+
67
+ it "should decrypt using the backup day as an initialization vector" do
68
+ pending
69
+ end
70
+
71
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,6 @@
1
+ --colour
2
+ --format
3
+ specdoc
4
+ --loadby
5
+ mtime
6
+ --reverse
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+ require "#{File.dirname(__FILE__)}/../lib/s3backup-manager.rb"
4
+ Dir[File.join(File.dirname(__FILE__)+'/lib/*.rb')].sort.each { |lib| require lib }
5
+
6
+ include S3BackupManager
7
+ include S3BackupManager::Mocks
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubypond-s3backup-manager
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Glenn Gillen
@@ -42,8 +42,36 @@ extensions: []
42
42
 
43
43
  extra_rdoc_files: []
44
44
 
45
- files: []
46
-
45
+ files:
46
+ - README.rdoc
47
+ - Rakefile
48
+ - lib/adapters/mysql_adapter.rb
49
+ - lib/adapters/postgres_adapter.rb
50
+ - lib/controllers/backup_manager.rb
51
+ - lib/models/bucket.rb
52
+ - lib/models/database_backup.rb
53
+ - lib/models/file_backup.rb
54
+ - lib/models/schedule.rb
55
+ - lib/s3backup-manager.rb
56
+ - bin/s3backup
57
+ - bin/s3backup_monitor
58
+ - bin/s3restore
59
+ - config/config.yml
60
+ - config/schedule.yml
61
+ - spec/adapters
62
+ - spec/adapters/couchdb_adapter_spec.rb
63
+ - spec/adapters/mysql_adapter_spec.rb
64
+ - spec/adapters/postgres_adapter_spec.rb
65
+ - spec/fixtures
66
+ - spec/fixtures/test_backup_file.txt
67
+ - spec/lib
68
+ - spec/lib/mocks.rb
69
+ - spec/models
70
+ - spec/models/bucket_spec.rb
71
+ - spec/models/database_backup_spec.rb
72
+ - spec/models/file_backup_spec.rb
73
+ - spec/spec.opts
74
+ - spec/spec_helper.rb
47
75
  has_rdoc: "false"
48
76
  homepage: http://github.com/rubypond/s3backup-manager
49
77
  post_install_message:
@@ -71,5 +99,18 @@ rubygems_version: 1.2.0
71
99
  signing_key:
72
100
  specification_version: 2
73
101
  summary: Scripts and daemon to manage encrypted backups on AmazonS3
74
- test_files: []
75
-
102
+ test_files:
103
+ - spec/adapters
104
+ - spec/adapters/couchdb_adapter_spec.rb
105
+ - spec/adapters/mysql_adapter_spec.rb
106
+ - spec/adapters/postgres_adapter_spec.rb
107
+ - spec/fixtures
108
+ - spec/fixtures/test_backup_file.txt
109
+ - spec/lib
110
+ - spec/lib/mocks.rb
111
+ - spec/models
112
+ - spec/models/bucket_spec.rb
113
+ - spec/models/database_backup_spec.rb
114
+ - spec/models/file_backup_spec.rb
115
+ - spec/spec.opts
116
+ - spec/spec_helper.rb