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.
Files changed (137) hide show
  1. data/.gitignore +2 -0
  2. data/.infinity_test +7 -0
  3. data/.rspec +3 -0
  4. data/Gemfile +25 -0
  5. data/Gemfile.lock +101 -0
  6. data/LICENSE.md +24 -0
  7. data/README.md +276 -0
  8. data/backup.gemspec +39 -0
  9. data/bin/backup +260 -0
  10. data/lib/backup.rb +168 -0
  11. data/lib/backup/archive.rb +73 -0
  12. data/lib/backup/cli.rb +50 -0
  13. data/lib/backup/compressor/base.rb +17 -0
  14. data/lib/backup/compressor/gzip.rb +61 -0
  15. data/lib/backup/configuration/base.rb +15 -0
  16. data/lib/backup/configuration/compressor/base.rb +10 -0
  17. data/lib/backup/configuration/compressor/gzip.rb +23 -0
  18. data/lib/backup/configuration/database/base.rb +18 -0
  19. data/lib/backup/configuration/database/mongodb.rb +37 -0
  20. data/lib/backup/configuration/database/mysql.rb +37 -0
  21. data/lib/backup/configuration/database/postgresql.rb +37 -0
  22. data/lib/backup/configuration/database/redis.rb +35 -0
  23. data/lib/backup/configuration/encryptor/base.rb +10 -0
  24. data/lib/backup/configuration/encryptor/gpg.rb +17 -0
  25. data/lib/backup/configuration/encryptor/open_ssl.rb +26 -0
  26. data/lib/backup/configuration/helpers.rb +54 -0
  27. data/lib/backup/configuration/notifier/base.rb +39 -0
  28. data/lib/backup/configuration/notifier/mail.rb +52 -0
  29. data/lib/backup/configuration/notifier/twitter.rb +21 -0
  30. data/lib/backup/configuration/storage/base.rb +18 -0
  31. data/lib/backup/configuration/storage/cloudfiles.rb +21 -0
  32. data/lib/backup/configuration/storage/dropbox.rb +29 -0
  33. data/lib/backup/configuration/storage/ftp.rb +25 -0
  34. data/lib/backup/configuration/storage/rsync.rb +25 -0
  35. data/lib/backup/configuration/storage/s3.rb +25 -0
  36. data/lib/backup/configuration/storage/scp.rb +25 -0
  37. data/lib/backup/configuration/storage/sftp.rb +25 -0
  38. data/lib/backup/configuration/syncer/rsync.rb +45 -0
  39. data/lib/backup/configuration/syncer/s3.rb +33 -0
  40. data/lib/backup/database/base.rb +33 -0
  41. data/lib/backup/database/mongodb.rb +137 -0
  42. data/lib/backup/database/mysql.rb +104 -0
  43. data/lib/backup/database/postgresql.rb +111 -0
  44. data/lib/backup/database/redis.rb +105 -0
  45. data/lib/backup/dependency.rb +84 -0
  46. data/lib/backup/encryptor/base.rb +17 -0
  47. data/lib/backup/encryptor/gpg.rb +78 -0
  48. data/lib/backup/encryptor/open_ssl.rb +67 -0
  49. data/lib/backup/finder.rb +39 -0
  50. data/lib/backup/logger.rb +86 -0
  51. data/lib/backup/model.rb +272 -0
  52. data/lib/backup/notifier/base.rb +29 -0
  53. data/lib/backup/notifier/binder.rb +32 -0
  54. data/lib/backup/notifier/mail.rb +141 -0
  55. data/lib/backup/notifier/templates/notify_failure.erb +31 -0
  56. data/lib/backup/notifier/templates/notify_success.erb +16 -0
  57. data/lib/backup/notifier/twitter.rb +87 -0
  58. data/lib/backup/storage/base.rb +67 -0
  59. data/lib/backup/storage/cloudfiles.rb +95 -0
  60. data/lib/backup/storage/dropbox.rb +87 -0
  61. data/lib/backup/storage/ftp.rb +114 -0
  62. data/lib/backup/storage/object.rb +45 -0
  63. data/lib/backup/storage/rsync.rb +99 -0
  64. data/lib/backup/storage/s3.rb +108 -0
  65. data/lib/backup/storage/scp.rb +106 -0
  66. data/lib/backup/storage/sftp.rb +106 -0
  67. data/lib/backup/syncer/base.rb +10 -0
  68. data/lib/backup/syncer/rsync.rb +117 -0
  69. data/lib/backup/syncer/s3.rb +116 -0
  70. data/lib/backup/version.rb +43 -0
  71. data/lib/templates/archive +4 -0
  72. data/lib/templates/compressor/gzip +4 -0
  73. data/lib/templates/database/mongodb +10 -0
  74. data/lib/templates/database/mysql +11 -0
  75. data/lib/templates/database/postgresql +11 -0
  76. data/lib/templates/database/redis +10 -0
  77. data/lib/templates/encryptor/gpg +9 -0
  78. data/lib/templates/encryptor/openssl +5 -0
  79. data/lib/templates/notifier/mail +14 -0
  80. data/lib/templates/notifier/twitter +9 -0
  81. data/lib/templates/readme +15 -0
  82. data/lib/templates/storage/cloudfiles +7 -0
  83. data/lib/templates/storage/dropbox +9 -0
  84. data/lib/templates/storage/ftp +8 -0
  85. data/lib/templates/storage/rsync +7 -0
  86. data/lib/templates/storage/s3 +8 -0
  87. data/lib/templates/storage/scp +8 -0
  88. data/lib/templates/storage/sftp +8 -0
  89. data/lib/templates/syncer/rsync +14 -0
  90. data/lib/templates/syncer/s3 +12 -0
  91. data/spec/archive_spec.rb +90 -0
  92. data/spec/backup_spec.rb +11 -0
  93. data/spec/compressor/gzip_spec.rb +59 -0
  94. data/spec/configuration/base_spec.rb +35 -0
  95. data/spec/configuration/compressor/gzip_spec.rb +28 -0
  96. data/spec/configuration/database/base_spec.rb +16 -0
  97. data/spec/configuration/database/mongodb_spec.rb +30 -0
  98. data/spec/configuration/database/mysql_spec.rb +32 -0
  99. data/spec/configuration/database/postgresql_spec.rb +32 -0
  100. data/spec/configuration/database/redis_spec.rb +30 -0
  101. data/spec/configuration/encryptor/gpg_spec.rb +25 -0
  102. data/spec/configuration/encryptor/open_ssl_spec.rb +31 -0
  103. data/spec/configuration/notifier/mail_spec.rb +32 -0
  104. data/spec/configuration/storage/cloudfiles_spec.rb +34 -0
  105. data/spec/configuration/storage/dropbox_spec.rb +43 -0
  106. data/spec/configuration/storage/ftp_spec.rb +40 -0
  107. data/spec/configuration/storage/rsync_spec.rb +37 -0
  108. data/spec/configuration/storage/s3_spec.rb +37 -0
  109. data/spec/configuration/storage/scp_spec.rb +40 -0
  110. data/spec/configuration/storage/sftp_spec.rb +40 -0
  111. data/spec/configuration/syncer/rsync_spec.rb +46 -0
  112. data/spec/configuration/syncer/s3_spec.rb +43 -0
  113. data/spec/database/base_spec.rb +30 -0
  114. data/spec/database/mongodb_spec.rb +144 -0
  115. data/spec/database/mysql_spec.rb +150 -0
  116. data/spec/database/postgresql_spec.rb +164 -0
  117. data/spec/database/redis_spec.rb +122 -0
  118. data/spec/encryptor/gpg_spec.rb +57 -0
  119. data/spec/encryptor/open_ssl_spec.rb +102 -0
  120. data/spec/logger_spec.rb +46 -0
  121. data/spec/model_spec.rb +236 -0
  122. data/spec/notifier/mail_spec.rb +97 -0
  123. data/spec/notifier/twitter_spec.rb +86 -0
  124. data/spec/spec_helper.rb +21 -0
  125. data/spec/storage/base_spec.rb +33 -0
  126. data/spec/storage/cloudfiles_spec.rb +102 -0
  127. data/spec/storage/dropbox_spec.rb +105 -0
  128. data/spec/storage/ftp_spec.rb +133 -0
  129. data/spec/storage/object_spec.rb +74 -0
  130. data/spec/storage/rsync_spec.rb +115 -0
  131. data/spec/storage/s3_spec.rb +110 -0
  132. data/spec/storage/scp_spec.rb +129 -0
  133. data/spec/storage/sftp_spec.rb +125 -0
  134. data/spec/syncer/rsync_spec.rb +156 -0
  135. data/spec/syncer/s3_spec.rb +139 -0
  136. data/spec/version_spec.rb +21 -0
  137. metadata +217 -0
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+
3
+ module Backup
4
+ module Notifier
5
+ class Base
6
+ include Backup::Configuration::Helpers
7
+
8
+ ##
9
+ # When set to true, the user will be notified by email
10
+ # when a backup process ends without raising any exceptions
11
+ attr_accessor :on_success
12
+ alias :notify_on_success? :on_success
13
+
14
+ ##
15
+ # When set to true, the user will be notified by email
16
+ # when a backup process raises an exception before finishing
17
+ attr_accessor :on_failure
18
+ alias :notify_on_failure? :on_failure
19
+
20
+ ##
21
+ # Logs a message to the console and log file to inform
22
+ # the client that Backup is notifying about the process
23
+ def log!
24
+ Logger.message "#{ self.class } started notifying about the process."
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+
3
+ module Backup
4
+ module Notifier
5
+ class Binder
6
+
7
+ ##
8
+ # Shortcut to create a new instance of a binder, setting
9
+ # the instance variables using a Hash of key/values and getting
10
+ # the instance's binding. This returns the binding of the new Binder instance
11
+ def self.bind(key_and_values = {})
12
+ Binder.new(key_and_values).get_binding
13
+ end
14
+
15
+ ##
16
+ # Creates a new Backup::Notifier::Binder instance. Loops through the provided
17
+ # Hash to set instance variables
18
+ def initialize(key_and_values)
19
+ key_and_values.each do |key, value|
20
+ instance_variable_set("@#{key}", value)
21
+ end
22
+ end
23
+
24
+ ##
25
+ # Returns the binding (needs a wrapper method because #binding is a private method)
26
+ def get_binding
27
+ binding
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,141 @@
1
+ # encoding: utf-8
2
+
3
+ ##
4
+ # Only load the Mail gem and Erb library when using Mail notifications
5
+ Backup::Dependency.load('mail')
6
+ require 'erb'
7
+
8
+ module Backup
9
+ module Notifier
10
+ class Mail < Base
11
+
12
+ ##
13
+ # Container for the Mail object
14
+ attr_accessor :mail
15
+
16
+ ##
17
+ # Container for the Model object
18
+ attr_accessor :model
19
+
20
+ ##
21
+ # Sender and Receiver email addresses
22
+ # Examples:
23
+ # sender - my.email.address@gmail.com
24
+ # receiver - your.email.address@gmail.com
25
+ attr_accessor :from, :to
26
+
27
+ ##
28
+ # The address to use
29
+ # Example: smtp.gmail.com
30
+ attr_accessor :address
31
+
32
+ ##
33
+ # The port to connect to
34
+ # Example: 587
35
+ attr_accessor :port
36
+
37
+ ##
38
+ # Your domain (if applicable)
39
+ # Example: mydomain.com
40
+ attr_accessor :domain
41
+
42
+ ##
43
+ # Username and Password (sender email's credentials)
44
+ # Examples:
45
+ # user_name - meskyanichi
46
+ # password - my_secret_password
47
+ attr_accessor :user_name, :password
48
+
49
+ ##
50
+ # Authentication type
51
+ # Example: plain
52
+ attr_accessor :authentication
53
+
54
+ ##
55
+ # Automatically set TLS
56
+ # Example: true
57
+ attr_accessor :enable_starttls_auto
58
+
59
+ ##
60
+ # Instantiates a new Backup::Notifier::Mail object
61
+ def initialize(&block)
62
+ load_defaults!
63
+
64
+ instance_eval(&block) if block_given?
65
+
66
+ set_defaults!
67
+ end
68
+
69
+ ##
70
+ # Performs the notification
71
+ # Takes an exception object that might've been created if an exception occurred.
72
+ # If this is the case it'll invoke notify_failure!(exception), otherwise, if no
73
+ # error was raised, it'll go ahead and notify_success!
74
+ #
75
+ # If'll only perform these if on_success is true or on_failure is true
76
+ def perform!(model, exception = false)
77
+ @model = model
78
+
79
+ if notify_on_success? and exception.eql?(false)
80
+ log!
81
+ notify_success!
82
+ elsif notify_on_failure? and not exception.eql?(false)
83
+ log!
84
+ notify_failure!(exception)
85
+ end
86
+ end
87
+
88
+ private
89
+
90
+ ##
91
+ # Sends an email informing the user that the backup operation
92
+ # proceeded without any errors
93
+ def notify_success!
94
+ mail[:subject] = "[Backup::Succeeded] #{model.label} (#{model.trigger})"
95
+ mail[:body] = read_template('notify_success', Binder.bind(:model => @model))
96
+ mail.deliver!
97
+ end
98
+
99
+ ##
100
+ # Sends an email informing the user that the backup operation
101
+ # raised an exception and will send the user the error details
102
+ def notify_failure!(exception)
103
+ mail[:subject] = "[Backup::Failed] #{model.label} (#{model.trigger})"
104
+ mail[:body] = read_template('notify_failure', Binder.bind(:model => @model, :exception => exception))
105
+ mail.deliver!
106
+ end
107
+
108
+ ##
109
+ # Configures the Mail gem by setting the defaults.
110
+ # Instantiates the @mail object with the @to and @from attributes
111
+ def set_defaults!
112
+ defaults = {
113
+ :address => @address,
114
+ :port => @port,
115
+ :domain => @domain,
116
+ :user_name => @user_name,
117
+ :password => @password,
118
+ :authentication => @authentication,
119
+ :enable_starttls_auto => @enable_starttls_auto
120
+ }
121
+
122
+ ::Mail.defaults do
123
+ delivery_method :smtp, defaults
124
+ end
125
+
126
+ @mail = ::Mail.new
127
+ @mail[:from] = @from
128
+ @mail[:to] = @to
129
+ end
130
+
131
+ ##
132
+ # Returns the path to the templates, appended by the passed in argument
133
+ def read_template(file, binder)
134
+ ERB.new(File.read(
135
+ File.join( File.dirname(__FILE__), "templates", "#{file}.erb" )
136
+ )).result(binder)
137
+ end
138
+
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,31 @@
1
+
2
+ There seemed to be a problem backing up <%= @model.label %> (<%= @model.trigger %>).
3
+
4
+ ===========================================================================
5
+ Exception that got raised:
6
+ <%= @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
+ <%= ENV["RUBY_VERSION"] %>
17
+
18
+
19
+ ---------------------------------------------------------------------------
20
+
21
+ View all Backup gem releases here:
22
+ http://rubygems.org/gems/backup
23
+
24
+ View the Backup git repository here:
25
+ https://github.com/meskyanichi/backup
26
+
27
+ View the Backup issues here:
28
+ https://github.com/meskyanichi/backup/issues
29
+
30
+ View the Backup wiki here:
31
+ 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.size > 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