interu-backup 3.0.16
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/Gemfile +31 -0
- data/Gemfile.lock +117 -0
- data/Guardfile +17 -0
- data/LICENSE.md +24 -0
- data/README.md +332 -0
- data/backup.gemspec +31 -0
- data/bin/backup +267 -0
- data/lib/backup.rb +181 -0
- data/lib/backup/archive.rb +73 -0
- data/lib/backup/cli.rb +82 -0
- data/lib/backup/compressor/base.rb +17 -0
- data/lib/backup/compressor/bzip2.rb +64 -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/bzip2.rb +23 -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 +41 -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/campfire.rb +25 -0
- data/lib/backup/configuration/notifier/mail.rb +52 -0
- data/lib/backup/configuration/notifier/presently.rb +25 -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 +179 -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 +96 -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/exception/command_not_found.rb +8 -0
- data/lib/backup/finder.rb +39 -0
- data/lib/backup/logger.rb +102 -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/campfire.rb +194 -0
- data/lib/backup/notifier/mail.rb +141 -0
- data/lib/backup/notifier/presently.rb +105 -0
- data/lib/backup/notifier/templates/notify_failure.erb +33 -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 +91 -0
- data/lib/backup/storage/ftp.rb +114 -0
- data/lib/backup/storage/object.rb +45 -0
- data/lib/backup/storage/rsync.rb +129 -0
- data/lib/backup/storage/s3.rb +180 -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 +152 -0
- data/lib/backup/syncer/s3.rb +118 -0
- data/lib/backup/version.rb +43 -0
- data/lib/templates/archive +7 -0
- data/lib/templates/compressor/bzip2 +7 -0
- data/lib/templates/compressor/gzip +7 -0
- data/lib/templates/database/mongodb +14 -0
- data/lib/templates/database/mysql +14 -0
- data/lib/templates/database/postgresql +14 -0
- data/lib/templates/database/redis +13 -0
- data/lib/templates/encryptor/gpg +12 -0
- data/lib/templates/encryptor/openssl +8 -0
- data/lib/templates/notifier/campfire +11 -0
- data/lib/templates/notifier/mail +17 -0
- data/lib/templates/notifier/presently +12 -0
- data/lib/templates/notifier/twitter +12 -0
- data/lib/templates/readme +15 -0
- data/lib/templates/storage/cloudfiles +10 -0
- data/lib/templates/storage/dropbox +12 -0
- data/lib/templates/storage/ftp +11 -0
- data/lib/templates/storage/rsync +10 -0
- data/lib/templates/storage/s3 +21 -0
- data/lib/templates/storage/scp +11 -0
- data/lib/templates/storage/sftp +11 -0
- data/lib/templates/syncer/rsync +17 -0
- data/lib/templates/syncer/s3 +15 -0
- data/spec/archive_spec.rb +90 -0
- data/spec/backup_spec.rb +11 -0
- data/spec/compressor/bzip2_spec.rb +59 -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/campfire_spec.rb +20 -0
- data/spec/configuration/notifier/mail_spec.rb +32 -0
- data/spec/configuration/notifier/twitter_spec.rb +22 -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 +181 -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 +58 -0
- data/spec/model_spec.rb +236 -0
- data/spec/notifier/campfire_spec.rb +96 -0
- data/spec/notifier/mail_spec.rb +97 -0
- data/spec/notifier/presently_spec.rb +99 -0
- data/spec/notifier/twitter_spec.rb +86 -0
- data/spec/spec_helper.rb +25 -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 +131 -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 +195 -0
- data/spec/syncer/s3_spec.rb +139 -0
- data/spec/version_spec.rb +21 -0
- metadata +231 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
|
|
2
|
+
There seemed to be a problem backing up <%= @model.label %> (<%= @model.trigger %>).
|
|
3
|
+
|
|
4
|
+
===========================================================================
|
|
5
|
+
Exception that got raised:
|
|
6
|
+
<%= @exception.class %> - <%= @exception.to_s %>
|
|
7
|
+
===========================================================================
|
|
8
|
+
<%= @exception.backtrace.join("\n") %>
|
|
9
|
+
===========================================================================
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
You are running Backup version:
|
|
13
|
+
<%= Backup::Version.current %>
|
|
14
|
+
|
|
15
|
+
You are running Ruby version:
|
|
16
|
+
<%= RUBY_VERSION %> (patchlevel <%= RUBY_PATCHLEVEL %>)
|
|
17
|
+
|
|
18
|
+
On platform:
|
|
19
|
+
<%= RUBY_PLATFORM %>
|
|
20
|
+
|
|
21
|
+
---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
View all Backup gem releases here:
|
|
24
|
+
http://rubygems.org/gems/backup
|
|
25
|
+
|
|
26
|
+
View the Backup git repository here:
|
|
27
|
+
https://github.com/meskyanichi/backup
|
|
28
|
+
|
|
29
|
+
View the Backup issues here:
|
|
30
|
+
https://github.com/meskyanichi/backup/issues
|
|
31
|
+
|
|
32
|
+
View the Backup wiki here:
|
|
33
|
+
https://github.com/meskyanichi/backup/wiki
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
|
|
2
|
+
Backup <%= @model.label %> (<%= @model.trigger %>) finished without any errors!
|
|
3
|
+
|
|
4
|
+
---------------------------------------------------------------------------
|
|
5
|
+
|
|
6
|
+
View all Backup gem releases here:
|
|
7
|
+
http://rubygems.org/gems/backup
|
|
8
|
+
|
|
9
|
+
View the Backup git repository here:
|
|
10
|
+
https://github.com/meskyanichi/backup
|
|
11
|
+
|
|
12
|
+
View the Backup issues here:
|
|
13
|
+
https://github.com/meskyanichi/backup/issues
|
|
14
|
+
|
|
15
|
+
View the Backup wiki here:
|
|
16
|
+
https://github.com/meskyanichi/backup/wiki
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# Only load the Twitter gem when using Twitter notifications
|
|
5
|
+
Backup::Dependency.load('twitter')
|
|
6
|
+
|
|
7
|
+
module Backup
|
|
8
|
+
module Notifier
|
|
9
|
+
class Twitter < Base
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
# Container for the Twitter Client object
|
|
13
|
+
attr_accessor :twitter_client
|
|
14
|
+
|
|
15
|
+
##
|
|
16
|
+
# Container for the Model object
|
|
17
|
+
attr_accessor :model
|
|
18
|
+
|
|
19
|
+
##
|
|
20
|
+
# Twitter consumer key credentials
|
|
21
|
+
attr_accessor :consumer_key, :consumer_secret
|
|
22
|
+
|
|
23
|
+
##
|
|
24
|
+
# OAuth credentials
|
|
25
|
+
attr_accessor :oauth_token, :oauth_token_secret
|
|
26
|
+
|
|
27
|
+
##
|
|
28
|
+
# Instantiates a new Backup::Notifier::Twitter object
|
|
29
|
+
def initialize(&block)
|
|
30
|
+
load_defaults!
|
|
31
|
+
|
|
32
|
+
instance_eval(&block) if block_given?
|
|
33
|
+
|
|
34
|
+
set_defaults!
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
##
|
|
38
|
+
# Performs the notification
|
|
39
|
+
# Takes an exception object that might've been created if an exception occurred.
|
|
40
|
+
# If this is the case it'll invoke notify_failure!(exception), otherwise, if no
|
|
41
|
+
# error was raised, it'll go ahead and notify_success!
|
|
42
|
+
#
|
|
43
|
+
# If'll only perform these if on_success is true or on_failure is true
|
|
44
|
+
def perform!(model, exception = false)
|
|
45
|
+
@model = model
|
|
46
|
+
|
|
47
|
+
if notify_on_success? and exception.eql?(false)
|
|
48
|
+
log!
|
|
49
|
+
notify_success!
|
|
50
|
+
elsif notify_on_failure? and not exception.eql?(false)
|
|
51
|
+
log!
|
|
52
|
+
notify_failure!(exception)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
##
|
|
59
|
+
# Sends a tweet informing the user that the backup operation
|
|
60
|
+
# proceeded without any errors
|
|
61
|
+
def notify_success!
|
|
62
|
+
twitter_client.update("[Backup::Succeeded] #{model.label} (#{ File.basename(Backup::Model.file) })")
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
##
|
|
66
|
+
# Sends a tweet informing the user that the backup operation
|
|
67
|
+
# raised an exception
|
|
68
|
+
def notify_failure!(exception)
|
|
69
|
+
twitter_client.update("[Backup::Failed] #{model.label} (#{ File.basename(Backup::Model.file) })")
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
##
|
|
73
|
+
# Configures the Twitter object by passing in the @consumer_key, @consumer_secret
|
|
74
|
+
# @oauth_token and @oauth_token_secret. Instantiates and sets the @twitter_client object
|
|
75
|
+
def set_defaults!
|
|
76
|
+
::Twitter.configure do |config|
|
|
77
|
+
config.consumer_key = @consumer_key
|
|
78
|
+
config.consumer_secret = @consumer_secret
|
|
79
|
+
config.oauth_token = @oauth_token
|
|
80
|
+
config.oauth_token_secret = @oauth_token_secret
|
|
81
|
+
end
|
|
82
|
+
@twitter_client = ::Twitter.client
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Backup
|
|
4
|
+
module Storage
|
|
5
|
+
class Base
|
|
6
|
+
include Backup::Configuration::Helpers
|
|
7
|
+
|
|
8
|
+
##
|
|
9
|
+
# The time when the backup initiated (in format: 2011.02.20.03.29.59)
|
|
10
|
+
attr_accessor :time
|
|
11
|
+
|
|
12
|
+
##
|
|
13
|
+
# Sets the limit to how many backups to keep in the remote location.
|
|
14
|
+
# If the limit exceeds it will remove the oldest backup to make room for the newest
|
|
15
|
+
attr_accessor :keep
|
|
16
|
+
|
|
17
|
+
##
|
|
18
|
+
# Returns the local path
|
|
19
|
+
def local_path
|
|
20
|
+
TMP_PATH
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
##
|
|
24
|
+
# Returns the local archive filename
|
|
25
|
+
def local_file
|
|
26
|
+
@local_file ||= File.basename(Backup::Model.file)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
##
|
|
30
|
+
# Returns the name of the file that's stored on the remote location
|
|
31
|
+
def remote_file
|
|
32
|
+
@remote_file ||= local_file
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
##
|
|
36
|
+
# Provider defaults to false and will be overridden when using
|
|
37
|
+
# a service-based storage such as Amazon S3, Rackspace Cloud Files or Dropbox
|
|
38
|
+
def provider
|
|
39
|
+
false
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
##
|
|
43
|
+
# Checks the persisted storage data by type (S3, CloudFiles, SCP, etc)
|
|
44
|
+
# to see if the amount of stored backups is greater than the amount of
|
|
45
|
+
# backups allowed. If this is the case it'll invoke the #remove! method
|
|
46
|
+
# on each of the oldest backups that exceed the storage limit (specified by @keep).
|
|
47
|
+
# After that it'll re-assign the objects variable with an array of objects that still remain
|
|
48
|
+
# after the removal of the older objects and files (that exceeded the @keep range). And finally
|
|
49
|
+
# these remaining objects will be converted to YAML format and are written back to the YAML file
|
|
50
|
+
def cycle!
|
|
51
|
+
type = self.class.name.split("::").last
|
|
52
|
+
storage_object = Backup::Storage::Object.new(type)
|
|
53
|
+
objects = [self] + storage_object.load
|
|
54
|
+
if keep.is_a?(Integer) and keep > 0 and objects.count > keep
|
|
55
|
+
objects_to_remove = objects[keep..-1]
|
|
56
|
+
objects_to_remove.each do |object|
|
|
57
|
+
Logger.message "#{ self.class } started removing (cycling) \"#{ object.remote_file }\"."
|
|
58
|
+
object.send(:remove!)
|
|
59
|
+
end
|
|
60
|
+
objects = objects - objects_to_remove
|
|
61
|
+
end
|
|
62
|
+
storage_object.write(objects)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# Only load the Fog gem when the Backup::Storage::CloudFiles class is loaded
|
|
5
|
+
Backup::Dependency.load('fog')
|
|
6
|
+
|
|
7
|
+
module Backup
|
|
8
|
+
module Storage
|
|
9
|
+
class CloudFiles < Base
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
# Rackspace Cloud Files Credentials
|
|
13
|
+
attr_accessor :username, :api_key
|
|
14
|
+
|
|
15
|
+
##
|
|
16
|
+
# Rackspace Cloud Files container name and path
|
|
17
|
+
attr_accessor :container, :path
|
|
18
|
+
|
|
19
|
+
##
|
|
20
|
+
# Creates a new instance of the Rackspace Cloud Files storage object
|
|
21
|
+
# First it sets the defaults (if any exist) and then evaluates
|
|
22
|
+
# the configuration block which may overwrite these defaults
|
|
23
|
+
def initialize(&block)
|
|
24
|
+
load_defaults!
|
|
25
|
+
|
|
26
|
+
@path ||= 'backups'
|
|
27
|
+
|
|
28
|
+
instance_eval(&block) if block_given?
|
|
29
|
+
|
|
30
|
+
@time = TIME
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
##
|
|
34
|
+
# This is the remote path to where the backup files will be stored
|
|
35
|
+
def remote_path
|
|
36
|
+
File.join(path, TRIGGER)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
##
|
|
40
|
+
# This is the provider that Fog uses for the Cloud Files Storage
|
|
41
|
+
def provider
|
|
42
|
+
'Rackspace'
|
|
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 Rackspace Cloud Files and returns the Fog 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
|
+
Fog::Storage.new(
|
|
62
|
+
:provider => provider,
|
|
63
|
+
:rackspace_username => username,
|
|
64
|
+
:rackspace_api_key => api_key
|
|
65
|
+
)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
##
|
|
69
|
+
# Transfers the archived file to the specified Cloud Files container
|
|
70
|
+
def transfer!
|
|
71
|
+
begin
|
|
72
|
+
Logger.message("#{ self.class } started transferring \"#{ remote_file }\".")
|
|
73
|
+
connection.put_object(
|
|
74
|
+
container,
|
|
75
|
+
File.join(remote_path, remote_file),
|
|
76
|
+
File.open(File.join(local_path, local_file))
|
|
77
|
+
)
|
|
78
|
+
rescue Excon::Errors::SocketError => e
|
|
79
|
+
puts "\nAn error occurred while trying to transfer the backup."
|
|
80
|
+
puts "Make sure the container exists and try again.\n\n"
|
|
81
|
+
exit
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
##
|
|
86
|
+
# Removes the transferred archive file from the Cloud Files container
|
|
87
|
+
def remove!
|
|
88
|
+
begin
|
|
89
|
+
connection.delete_object(container, File.join(remote_path, remote_file))
|
|
90
|
+
rescue Excon::Errors::SocketError; end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
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
|
+
begin
|
|
83
|
+
connection.delete(File.join(remote_path, remote_file))
|
|
84
|
+
rescue ::Dropbox::FileNotFoundError
|
|
85
|
+
Logger.warn "File \"#{ File.join(remote_path, remote_file) }\" does not exist, skipping removal."
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
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
|