alg-backup 3.0.10
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/.gitignore +2 -0
- data/.infinity_test +7 -0
- data/.rspec +3 -0
- data/Gemfile +25 -0
- data/Gemfile.lock +101 -0
- data/LICENSE.md +24 -0
- data/README.md +276 -0
- data/backup.gemspec +39 -0
- data/bin/backup +260 -0
- data/lib/backup.rb +168 -0
- data/lib/backup/archive.rb +73 -0
- data/lib/backup/cli.rb +50 -0
- data/lib/backup/compressor/base.rb +17 -0
- data/lib/backup/compressor/gzip.rb +61 -0
- data/lib/backup/configuration/base.rb +15 -0
- data/lib/backup/configuration/compressor/base.rb +10 -0
- data/lib/backup/configuration/compressor/gzip.rb +23 -0
- data/lib/backup/configuration/database/base.rb +18 -0
- data/lib/backup/configuration/database/mongodb.rb +37 -0
- data/lib/backup/configuration/database/mysql.rb +37 -0
- data/lib/backup/configuration/database/postgresql.rb +37 -0
- data/lib/backup/configuration/database/redis.rb +35 -0
- data/lib/backup/configuration/encryptor/base.rb +10 -0
- data/lib/backup/configuration/encryptor/gpg.rb +17 -0
- data/lib/backup/configuration/encryptor/open_ssl.rb +26 -0
- data/lib/backup/configuration/helpers.rb +54 -0
- data/lib/backup/configuration/notifier/base.rb +39 -0
- data/lib/backup/configuration/notifier/mail.rb +52 -0
- data/lib/backup/configuration/notifier/twitter.rb +21 -0
- data/lib/backup/configuration/storage/base.rb +18 -0
- data/lib/backup/configuration/storage/cloudfiles.rb +21 -0
- data/lib/backup/configuration/storage/dropbox.rb +29 -0
- data/lib/backup/configuration/storage/ftp.rb +25 -0
- data/lib/backup/configuration/storage/rsync.rb +25 -0
- data/lib/backup/configuration/storage/s3.rb +25 -0
- data/lib/backup/configuration/storage/scp.rb +25 -0
- data/lib/backup/configuration/storage/sftp.rb +25 -0
- data/lib/backup/configuration/syncer/rsync.rb +45 -0
- data/lib/backup/configuration/syncer/s3.rb +33 -0
- data/lib/backup/database/base.rb +33 -0
- data/lib/backup/database/mongodb.rb +137 -0
- data/lib/backup/database/mysql.rb +104 -0
- data/lib/backup/database/postgresql.rb +111 -0
- data/lib/backup/database/redis.rb +105 -0
- data/lib/backup/dependency.rb +84 -0
- data/lib/backup/encryptor/base.rb +17 -0
- data/lib/backup/encryptor/gpg.rb +78 -0
- data/lib/backup/encryptor/open_ssl.rb +67 -0
- data/lib/backup/finder.rb +39 -0
- data/lib/backup/logger.rb +86 -0
- data/lib/backup/model.rb +272 -0
- data/lib/backup/notifier/base.rb +29 -0
- data/lib/backup/notifier/binder.rb +32 -0
- data/lib/backup/notifier/mail.rb +141 -0
- data/lib/backup/notifier/templates/notify_failure.erb +31 -0
- data/lib/backup/notifier/templates/notify_success.erb +16 -0
- data/lib/backup/notifier/twitter.rb +87 -0
- data/lib/backup/storage/base.rb +67 -0
- data/lib/backup/storage/cloudfiles.rb +95 -0
- data/lib/backup/storage/dropbox.rb +87 -0
- data/lib/backup/storage/ftp.rb +114 -0
- data/lib/backup/storage/object.rb +45 -0
- data/lib/backup/storage/rsync.rb +99 -0
- data/lib/backup/storage/s3.rb +108 -0
- data/lib/backup/storage/scp.rb +106 -0
- data/lib/backup/storage/sftp.rb +106 -0
- data/lib/backup/syncer/base.rb +10 -0
- data/lib/backup/syncer/rsync.rb +117 -0
- data/lib/backup/syncer/s3.rb +116 -0
- data/lib/backup/version.rb +43 -0
- data/lib/templates/archive +4 -0
- data/lib/templates/compressor/gzip +4 -0
- data/lib/templates/database/mongodb +10 -0
- data/lib/templates/database/mysql +11 -0
- data/lib/templates/database/postgresql +11 -0
- data/lib/templates/database/redis +10 -0
- data/lib/templates/encryptor/gpg +9 -0
- data/lib/templates/encryptor/openssl +5 -0
- data/lib/templates/notifier/mail +14 -0
- data/lib/templates/notifier/twitter +9 -0
- data/lib/templates/readme +15 -0
- data/lib/templates/storage/cloudfiles +7 -0
- data/lib/templates/storage/dropbox +9 -0
- data/lib/templates/storage/ftp +8 -0
- data/lib/templates/storage/rsync +7 -0
- data/lib/templates/storage/s3 +8 -0
- data/lib/templates/storage/scp +8 -0
- data/lib/templates/storage/sftp +8 -0
- data/lib/templates/syncer/rsync +14 -0
- data/lib/templates/syncer/s3 +12 -0
- data/spec/archive_spec.rb +90 -0
- data/spec/backup_spec.rb +11 -0
- data/spec/compressor/gzip_spec.rb +59 -0
- data/spec/configuration/base_spec.rb +35 -0
- data/spec/configuration/compressor/gzip_spec.rb +28 -0
- data/spec/configuration/database/base_spec.rb +16 -0
- data/spec/configuration/database/mongodb_spec.rb +30 -0
- data/spec/configuration/database/mysql_spec.rb +32 -0
- data/spec/configuration/database/postgresql_spec.rb +32 -0
- data/spec/configuration/database/redis_spec.rb +30 -0
- data/spec/configuration/encryptor/gpg_spec.rb +25 -0
- data/spec/configuration/encryptor/open_ssl_spec.rb +31 -0
- data/spec/configuration/notifier/mail_spec.rb +32 -0
- data/spec/configuration/storage/cloudfiles_spec.rb +34 -0
- data/spec/configuration/storage/dropbox_spec.rb +43 -0
- data/spec/configuration/storage/ftp_spec.rb +40 -0
- data/spec/configuration/storage/rsync_spec.rb +37 -0
- data/spec/configuration/storage/s3_spec.rb +37 -0
- data/spec/configuration/storage/scp_spec.rb +40 -0
- data/spec/configuration/storage/sftp_spec.rb +40 -0
- data/spec/configuration/syncer/rsync_spec.rb +46 -0
- data/spec/configuration/syncer/s3_spec.rb +43 -0
- data/spec/database/base_spec.rb +30 -0
- data/spec/database/mongodb_spec.rb +144 -0
- data/spec/database/mysql_spec.rb +150 -0
- data/spec/database/postgresql_spec.rb +164 -0
- data/spec/database/redis_spec.rb +122 -0
- data/spec/encryptor/gpg_spec.rb +57 -0
- data/spec/encryptor/open_ssl_spec.rb +102 -0
- data/spec/logger_spec.rb +46 -0
- data/spec/model_spec.rb +236 -0
- data/spec/notifier/mail_spec.rb +97 -0
- data/spec/notifier/twitter_spec.rb +86 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/storage/base_spec.rb +33 -0
- data/spec/storage/cloudfiles_spec.rb +102 -0
- data/spec/storage/dropbox_spec.rb +105 -0
- data/spec/storage/ftp_spec.rb +133 -0
- data/spec/storage/object_spec.rb +74 -0
- data/spec/storage/rsync_spec.rb +115 -0
- data/spec/storage/s3_spec.rb +110 -0
- data/spec/storage/scp_spec.rb +129 -0
- data/spec/storage/sftp_spec.rb +125 -0
- data/spec/syncer/rsync_spec.rb +156 -0
- data/spec/syncer/s3_spec.rb +139 -0
- data/spec/version_spec.rb +21 -0
- metadata +217 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# Only load the Dropbox gem when the Backup::Storage::Dropbox class is loaded
|
|
5
|
+
Backup::Dependency.load('dropbox')
|
|
6
|
+
|
|
7
|
+
module Backup
|
|
8
|
+
module Storage
|
|
9
|
+
class Dropbox < Base
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
# Dropbox user credentials
|
|
13
|
+
attr_accessor :email, :password
|
|
14
|
+
|
|
15
|
+
##
|
|
16
|
+
# Dropbox API credentials
|
|
17
|
+
attr_accessor :api_key, :api_secret
|
|
18
|
+
|
|
19
|
+
##
|
|
20
|
+
# Path to where the backups will be stored
|
|
21
|
+
attr_accessor :path
|
|
22
|
+
|
|
23
|
+
##
|
|
24
|
+
# Dropbox connection timeout
|
|
25
|
+
attr_accessor :timeout
|
|
26
|
+
|
|
27
|
+
##
|
|
28
|
+
# Creates a new instance of the Dropbox storage object
|
|
29
|
+
# First it sets the defaults (if any exist) and then evaluates
|
|
30
|
+
# the configuration block which may overwrite these defaults
|
|
31
|
+
def initialize(&block)
|
|
32
|
+
load_defaults!
|
|
33
|
+
|
|
34
|
+
@path ||= 'backups'
|
|
35
|
+
|
|
36
|
+
instance_eval(&block) if block_given?
|
|
37
|
+
|
|
38
|
+
@timeout ||= 300
|
|
39
|
+
@time = TIME
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
##
|
|
43
|
+
# This is the remote path to where the backup files will be stored
|
|
44
|
+
def remote_path
|
|
45
|
+
File.join(path, TRIGGER)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
##
|
|
49
|
+
# Performs the backup transfer
|
|
50
|
+
def perform!
|
|
51
|
+
transfer!
|
|
52
|
+
cycle!
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
##
|
|
58
|
+
# Establishes a connection to Dropbox and returns the Dropbox::Session object.
|
|
59
|
+
# Not doing any instance variable caching because this object gets persisted in YAML
|
|
60
|
+
# format to a file and will issues. This, however has no impact on performance since it only
|
|
61
|
+
# gets invoked once per object for a #transfer! and once for a remove! Backups run in the
|
|
62
|
+
# background anyway so even if it were a bit slower it shouldn't matter.
|
|
63
|
+
def connection
|
|
64
|
+
session = ::Dropbox::Session.new(api_key, api_secret)
|
|
65
|
+
session.mode = :dropbox
|
|
66
|
+
session.authorizing_user = email
|
|
67
|
+
session.authorizing_password = password
|
|
68
|
+
session.authorize!
|
|
69
|
+
session
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
##
|
|
73
|
+
# Transfers the archived file to the specified Dropbox folder
|
|
74
|
+
def transfer!
|
|
75
|
+
Logger.message("#{ self.class } started transferring \"#{ remote_file }\".")
|
|
76
|
+
connection.upload(File.join(local_path, local_file), remote_path, :timeout => timeout)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
##
|
|
80
|
+
# Removes the transferred archive file from the Dropbox folder
|
|
81
|
+
def remove!
|
|
82
|
+
connection.delete(File.join(remote_path, remote_file))
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# Only load the Net::FTP library/gem when the Backup::Storage::FTP class is loaded
|
|
5
|
+
require 'net/ftp'
|
|
6
|
+
|
|
7
|
+
module Backup
|
|
8
|
+
module Storage
|
|
9
|
+
class FTP < Base
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
# Server credentials
|
|
13
|
+
attr_accessor :username, :password
|
|
14
|
+
|
|
15
|
+
##
|
|
16
|
+
# Server IP Address and FTP port
|
|
17
|
+
attr_accessor :ip, :port
|
|
18
|
+
|
|
19
|
+
##
|
|
20
|
+
# Path to store backups to
|
|
21
|
+
attr_accessor :path
|
|
22
|
+
|
|
23
|
+
##
|
|
24
|
+
# Creates a new instance of the FTP storage object
|
|
25
|
+
# First it sets the defaults (if any exist) and then evaluates
|
|
26
|
+
# the configuration block which may overwrite these defaults
|
|
27
|
+
def initialize(&block)
|
|
28
|
+
load_defaults!
|
|
29
|
+
|
|
30
|
+
@port ||= 21
|
|
31
|
+
@path ||= 'backups'
|
|
32
|
+
|
|
33
|
+
instance_eval(&block) if block_given?
|
|
34
|
+
|
|
35
|
+
@time = TIME
|
|
36
|
+
@path = path.sub(/^\~\//, '')
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
##
|
|
40
|
+
# This is the remote path to where the backup files will be stored
|
|
41
|
+
def remote_path
|
|
42
|
+
File.join(path, TRIGGER)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
##
|
|
46
|
+
# Performs the backup transfer
|
|
47
|
+
def perform!
|
|
48
|
+
transfer!
|
|
49
|
+
cycle!
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
##
|
|
55
|
+
# Establishes a connection to the remote server and returns the Net::FTP object.
|
|
56
|
+
# Not doing any instance variable caching because this object gets persisted in YAML
|
|
57
|
+
# format to a file and will issues. This, however has no impact on performance since it only
|
|
58
|
+
# gets invoked once per object for a #transfer! and once for a remove! Backups run in the
|
|
59
|
+
# background anyway so even if it were a bit slower it shouldn't matter.
|
|
60
|
+
#
|
|
61
|
+
# Note *
|
|
62
|
+
# Since the FTP port is defined as a constant in the Net::FTP class, and might be required
|
|
63
|
+
# to change by the user, we dynamically remove and re-add the constant with the provided port value
|
|
64
|
+
def connection
|
|
65
|
+
if defined? Net::FTP::FTP_PORT
|
|
66
|
+
Net::FTP.send(:remove_const, :FTP_PORT)
|
|
67
|
+
end; Net::FTP.send(:const_set, :FTP_PORT, port)
|
|
68
|
+
|
|
69
|
+
Net::FTP.new(ip, username, password)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
##
|
|
73
|
+
# Transfers the archived file to the specified remote server
|
|
74
|
+
def transfer!
|
|
75
|
+
Logger.message("#{ self.class } started transferring \"#{ remote_file }\".")
|
|
76
|
+
create_remote_directories!
|
|
77
|
+
connection.put(
|
|
78
|
+
File.join(local_path, local_file),
|
|
79
|
+
File.join(remote_path, remote_file)
|
|
80
|
+
)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
##
|
|
84
|
+
# Removes the transferred archive file from the server
|
|
85
|
+
def remove!
|
|
86
|
+
begin
|
|
87
|
+
connection.delete(
|
|
88
|
+
File.join(remote_path, remote_file)
|
|
89
|
+
)
|
|
90
|
+
rescue Net::FTPPermError
|
|
91
|
+
Logger.warn "Could not remove file \"#{ File.join(remote_path, remote_file) }\"."
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
##
|
|
96
|
+
# Creates (if they don't exist yet) all the directories on the remote
|
|
97
|
+
# server in order to upload the backup file. Net::FTP does not support
|
|
98
|
+
# paths to directories that don't yet exist when creating new directories.
|
|
99
|
+
# Instead, we split the parts up in to an array (for each '/') and loop through
|
|
100
|
+
# that to create the directories one by one. Net::FTP raises an exception when
|
|
101
|
+
# the directory it's trying ot create already exists, so we have rescue it
|
|
102
|
+
def create_remote_directories!
|
|
103
|
+
path_parts = Array.new
|
|
104
|
+
remote_path.split('/').each do |path_part|
|
|
105
|
+
path_parts << path_part
|
|
106
|
+
begin
|
|
107
|
+
connection.mkdir(path_parts.join('/'))
|
|
108
|
+
rescue Net::FTPPermError; end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Backup
|
|
4
|
+
module Storage
|
|
5
|
+
class Object
|
|
6
|
+
|
|
7
|
+
##
|
|
8
|
+
# Holds the type attribute
|
|
9
|
+
attr_accessor :storage_file
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
# Instantiates a new Backup::Storage::Object and stores the
|
|
13
|
+
# full path to the storage file (yaml) in the @storage_file attribute
|
|
14
|
+
def initialize(type)
|
|
15
|
+
@storage_file = File.join(DATA_PATH, TRIGGER, "#{type}.yml")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
##
|
|
19
|
+
# Tries to load an existing YAML file and returns an
|
|
20
|
+
# array of storage objects. If no file exists, an empty
|
|
21
|
+
# array gets returned
|
|
22
|
+
#
|
|
23
|
+
# If a file is loaded it'll sort the array of objects by @time
|
|
24
|
+
# descending. The newest backup storage object comes in Backup::Storage::Object.load[0]
|
|
25
|
+
# and the oldest in Backup::Storage::Object.load[-1]
|
|
26
|
+
def load
|
|
27
|
+
if File.exist?(storage_file)
|
|
28
|
+
YAML.load_file(storage_file).sort { |a,b| b.time <=> a.time }
|
|
29
|
+
else
|
|
30
|
+
[]
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
##
|
|
35
|
+
# Takes the provided objects and converts it to YAML format.
|
|
36
|
+
# The YAML data gets written to the storage file
|
|
37
|
+
def write(objects)
|
|
38
|
+
File.open(storage_file, 'w') do |file|
|
|
39
|
+
file.write(objects.to_yaml)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# Only load the Net::SSH library when the Backup::Storage::RSync class is loaded
|
|
5
|
+
Backup::Dependency.load('net-ssh')
|
|
6
|
+
|
|
7
|
+
module Backup
|
|
8
|
+
module Storage
|
|
9
|
+
class RSync < Base
|
|
10
|
+
include Backup::CLI
|
|
11
|
+
|
|
12
|
+
##
|
|
13
|
+
# Server credentials
|
|
14
|
+
attr_accessor :username, :password
|
|
15
|
+
|
|
16
|
+
##
|
|
17
|
+
# Server IP Address and SSH port
|
|
18
|
+
attr_accessor :ip, :port
|
|
19
|
+
|
|
20
|
+
##
|
|
21
|
+
# Path to store backups to
|
|
22
|
+
attr_accessor :path
|
|
23
|
+
|
|
24
|
+
##
|
|
25
|
+
# Creates a new instance of the RSync storage object
|
|
26
|
+
# First it sets the defaults (if any exist) and then evaluates
|
|
27
|
+
# the configuration block which may overwrite these defaults
|
|
28
|
+
def initialize(&block)
|
|
29
|
+
load_defaults!
|
|
30
|
+
|
|
31
|
+
@port ||= 22
|
|
32
|
+
@path ||= 'backups'
|
|
33
|
+
|
|
34
|
+
instance_eval(&block) if block_given?
|
|
35
|
+
|
|
36
|
+
@time = TIME
|
|
37
|
+
@path = path.sub(/^\~\//, '')
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
##
|
|
41
|
+
# This is the remote path to where the backup files will be stored
|
|
42
|
+
def remote_path
|
|
43
|
+
File.join(path, TRIGGER)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
##
|
|
47
|
+
# Performs the backup transfer
|
|
48
|
+
def perform!
|
|
49
|
+
transfer!
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
##
|
|
55
|
+
# Establishes a connection to the remote server and returns the Net::SSH object.
|
|
56
|
+
# Not doing any instance variable caching because this object gets persisted in YAML
|
|
57
|
+
# format to a file and will issues. This, however has no impact on performance since it only
|
|
58
|
+
# gets invoked once per object for a #transfer! and once for a remove! Backups run in the
|
|
59
|
+
# background anyway so even if it were a bit slower it shouldn't matter.
|
|
60
|
+
def connection
|
|
61
|
+
Net::SSH.start(ip, username, :password => password, :port => port)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
##
|
|
65
|
+
# Transfers the archived file to the specified remote server
|
|
66
|
+
def transfer!
|
|
67
|
+
Logger.message("#{ self.class } started transferring \"#{ remote_file }\".")
|
|
68
|
+
create_remote_directories!
|
|
69
|
+
run("#{ utility(:rsync) } #{ options } '#{ File.join(local_path, local_file) }' '#{ username }@#{ ip }:#{ File.join(remote_path, remote_file[20..-1]) }'")
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
##
|
|
73
|
+
# Removes the transferred archive file from the server
|
|
74
|
+
def remove!
|
|
75
|
+
response = connection.exec!("rm #{ File.join(remote_path, remote_file) }")
|
|
76
|
+
if response =~ /No such file or directory/
|
|
77
|
+
Logger.warn "Could not remove file \"#{ File.join(remote_path, remote_file) }\"."
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
##
|
|
82
|
+
# Creates (if they don't exist yet) all the directories on the remote
|
|
83
|
+
# server in order to upload the backup file.
|
|
84
|
+
def create_remote_directories!
|
|
85
|
+
connection.exec!("mkdir -p '#{ remote_path }'")
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
##
|
|
89
|
+
# RSync options
|
|
90
|
+
# -z = Compresses the bytes that will be transferred to reduce bandwidth usage
|
|
91
|
+
# --port = the port to connect to through SSH
|
|
92
|
+
# -Phv = debug options
|
|
93
|
+
def options
|
|
94
|
+
"-z --port='#{ port }'"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# Only load the Fog gem when the Backup::Storage::S3 class is loaded
|
|
5
|
+
Backup::Dependency.load('fog')
|
|
6
|
+
|
|
7
|
+
module Backup
|
|
8
|
+
module Storage
|
|
9
|
+
class S3 < Base
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
# Amazon Simple Storage Service (S3) Credentials
|
|
13
|
+
attr_accessor :access_key_id, :secret_access_key
|
|
14
|
+
|
|
15
|
+
##
|
|
16
|
+
# Amazon S3 bucket name and path
|
|
17
|
+
attr_accessor :bucket, :path
|
|
18
|
+
|
|
19
|
+
##
|
|
20
|
+
# Region of the specified S3 bucket
|
|
21
|
+
attr_accessor :region
|
|
22
|
+
|
|
23
|
+
##
|
|
24
|
+
# Creates a new instance of the Amazon S3 storage object
|
|
25
|
+
# First it sets the defaults (if any exist) and then evaluates
|
|
26
|
+
# the configuration block which may overwrite these defaults
|
|
27
|
+
#
|
|
28
|
+
# Currently available regions:
|
|
29
|
+
# eu-west-1, us-east-1, ap-southeast-1, us-west-1
|
|
30
|
+
def initialize(&block)
|
|
31
|
+
load_defaults!
|
|
32
|
+
|
|
33
|
+
@path ||= 'backups'
|
|
34
|
+
|
|
35
|
+
instance_eval(&block) if block_given?
|
|
36
|
+
|
|
37
|
+
@path = path.sub(/^\//, '')
|
|
38
|
+
@time = TIME
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
##
|
|
42
|
+
# This is the remote path to where the backup files will be stored
|
|
43
|
+
def remote_path
|
|
44
|
+
File.join(path, TRIGGER, '/')
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
##
|
|
48
|
+
# This is the provider that Fog uses for the S3 Storage
|
|
49
|
+
def provider
|
|
50
|
+
'AWS'
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
##
|
|
54
|
+
# Performs the backup transfer
|
|
55
|
+
def perform!
|
|
56
|
+
transfer!
|
|
57
|
+
cycle!
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
##
|
|
63
|
+
# Establishes a connection to Amazon S3 and returns the Fog object.
|
|
64
|
+
# Not doing any instance variable caching because this object gets persisted in YAML
|
|
65
|
+
# format to a file and will issues. This, however has no impact on performance since it only
|
|
66
|
+
# gets invoked once per object for a #transfer! and once for a remove! Backups run in the
|
|
67
|
+
# background anyway so even if it were a bit slower it shouldn't matter.
|
|
68
|
+
def connection
|
|
69
|
+
Fog::Storage.new(
|
|
70
|
+
:provider => provider,
|
|
71
|
+
:aws_access_key_id => access_key_id,
|
|
72
|
+
:aws_secret_access_key => secret_access_key,
|
|
73
|
+
:region => region
|
|
74
|
+
)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
##
|
|
78
|
+
# Transfers the archived file to the specified Amazon S3 bucket
|
|
79
|
+
def transfer!
|
|
80
|
+
begin
|
|
81
|
+
Logger.message("#{ self.class } started transferring \"#{ remote_file }\".")
|
|
82
|
+
connection.sync_clock
|
|
83
|
+
connection.put_object(
|
|
84
|
+
bucket,
|
|
85
|
+
File.join(remote_path, remote_file),
|
|
86
|
+
File.open(File.join(local_path, local_file))
|
|
87
|
+
)
|
|
88
|
+
rescue Excon::Errors::SocketError
|
|
89
|
+
puts "\nAn error occurred while trying to transfer the backup."
|
|
90
|
+
puts "Make sure the bucket exists, and that you specified the correct bucket region.\n\n"
|
|
91
|
+
puts "The available regions are:\n\n"
|
|
92
|
+
puts %w[eu-west-1 us-east-1 ap-southeast-1 us-west-1].map{ |region| "\s\s* #{region}" }.join("\n")
|
|
93
|
+
exit
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
##
|
|
98
|
+
# Removes the transferred archive file from the Amazon S3 bucket
|
|
99
|
+
def remove!
|
|
100
|
+
begin
|
|
101
|
+
connection.sync_clock
|
|
102
|
+
connection.delete_object(bucket, File.join(remote_path, remote_file))
|
|
103
|
+
rescue Excon::Errors::SocketError; end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|