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,106 @@
1
+ # encoding: utf-8
2
+
3
+ ##
4
+ # Only load the Net::SSH and Net::SCP library/gems
5
+ # when the Backup::Storage::SCP class is loaded
6
+ Backup::Dependency.load('net-ssh')
7
+ Backup::Dependency.load('net-scp')
8
+
9
+
10
+ module Backup
11
+ module Storage
12
+ class SCP < Base
13
+
14
+ ##
15
+ # Server credentials
16
+ attr_accessor :username, :password
17
+
18
+ ##
19
+ # Server IP Address and SCP port
20
+ attr_accessor :ip, :port
21
+
22
+ ##
23
+ # Path to store backups to
24
+ attr_accessor :path
25
+
26
+ ##
27
+ # Creates a new instance of the SCP storage object
28
+ # First it sets the defaults (if any exist) and then evaluates
29
+ # the configuration block which may overwrite these defaults
30
+ def initialize(&block)
31
+ load_defaults!
32
+
33
+ @port ||= 22
34
+ @path ||= 'backups'
35
+
36
+ instance_eval(&block) if block_given?
37
+
38
+ @time = TIME
39
+ @path = path.sub(/^\~\//, '')
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 the remote server and returns the Net::SCP 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
+ #
64
+ # We will be using Net::SSH, and use Net::SCP through Net::SSH to transfer backups
65
+ def connection
66
+ Net::SSH.start(ip, username, :password => password, :port => port)
67
+ end
68
+
69
+ ##
70
+ # Transfers the archived file to the specified remote server
71
+ def transfer!
72
+ Logger.message("#{ self.class } started transferring \"#{ remote_file }\".")
73
+ create_remote_directories!
74
+ connection.scp.upload!(
75
+ File.join(local_path, local_file),
76
+ File.join(remote_path, remote_file)
77
+ )
78
+ end
79
+
80
+ ##
81
+ # Removes the transferred archive file from the server
82
+ def remove!
83
+ response = connection.exec!("rm #{ File.join(remote_path, remote_file) }")
84
+ if response =~ /No such file or directory/
85
+ Logger.warn "Could not remove file \"#{ File.join(remote_path, remote_file) }\"."
86
+ end
87
+ end
88
+
89
+ ##
90
+ # Creates (if they don't exist yet) all the directories on the remote
91
+ # server in order to upload the backup file. Net::SCP does not support
92
+ # paths to directories that don't yet exist when creating new directories.
93
+ # Instead, we split the parts up in to an array (for each '/') and loop through
94
+ # that to create the directories one by one. Net::SCP raises an exception when
95
+ # the directory it's trying ot create already exists, so we have rescue it
96
+ def create_remote_directories!
97
+ path_parts = Array.new
98
+ remote_path.split('/').each do |path_part|
99
+ path_parts << path_part
100
+ connection.exec!("mkdir '#{ path_parts.join('/') }'")
101
+ end
102
+ end
103
+
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,106 @@
1
+ # encoding: utf-8
2
+
3
+ ##
4
+ # Only load the Net::SFTP library/gem when the Backup::Storage::SFTP class is loaded
5
+ Backup::Dependency.load('net-sftp')
6
+
7
+ module Backup
8
+ module Storage
9
+ class SFTP < Base
10
+
11
+ ##
12
+ # Server credentials
13
+ attr_accessor :username, :password
14
+
15
+ ##
16
+ # Server IP Address and SFTP 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 SFTP 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 ||= 22
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::SFTP 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::SFTP.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
+ connection.upload!(
70
+ File.join(local_path, local_file),
71
+ File.join(remote_path, remote_file)
72
+ )
73
+ end
74
+
75
+ ##
76
+ # Removes the transferred archive file from the server
77
+ def remove!
78
+ begin
79
+ connection.remove!(
80
+ File.join(remote_path, remote_file)
81
+ )
82
+ rescue Net::SFTP::StatusException
83
+ Logger.warn "Could not remove file \"#{ File.join(remote_path, remote_file) }\"."
84
+ end
85
+ end
86
+
87
+ ##
88
+ # Creates (if they don't exist yet) all the directories on the remote
89
+ # server in order to upload the backup file. Net::SFTP does not support
90
+ # paths to directories that don't yet exist when creating new directories.
91
+ # Instead, we split the parts up in to an array (for each '/') and loop through
92
+ # that to create the directories one by one. Net::SFTP raises an exception when
93
+ # the directory it's trying ot create already exists, so we have rescue it
94
+ def create_remote_directories!
95
+ path_parts = Array.new
96
+ remote_path.split('/').each do |path_part|
97
+ path_parts << path_part
98
+ begin
99
+ connection.mkdir!(path_parts.join('/'))
100
+ rescue Net::SFTP::StatusException; end
101
+ end
102
+ end
103
+
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+
3
+ module Backup
4
+ module Syncer
5
+ class Base
6
+ include Backup::CLI
7
+ include Backup::Configuration::Helpers
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,117 @@
1
+ # encoding: utf-8
2
+
3
+ module Backup
4
+ module Syncer
5
+ class RSync < Base
6
+
7
+ ##
8
+ # Server credentials
9
+ attr_accessor :username, :password
10
+
11
+ ##
12
+ # Server IP Address and SSH port
13
+ attr_accessor :ip
14
+
15
+ ##
16
+ # The SSH port to connect to
17
+ attr_writer :port
18
+
19
+ ##
20
+ # Directories to sync
21
+ attr_writer :directories
22
+
23
+ ##
24
+ # Path to store the synced files/directories to
25
+ attr_accessor :path
26
+
27
+ ##
28
+ # Flag for mirroring the files/directories
29
+ attr_writer :mirror
30
+
31
+ ##
32
+ # Flag for compressing (only compresses for the transfer)
33
+ attr_writer :compress
34
+
35
+ ##
36
+ # Additional options for the rsync cli
37
+ attr_accessor :additional_options
38
+
39
+ ##
40
+ # Instantiates a new RSync Syncer object and sets the default configuration
41
+ # specified in the Backup::Configuration::Syncer::RSync. Then it sets the object
42
+ # defaults if particular properties weren't set. Finally it'll evaluate the users
43
+ # configuration file and overwrite anything that's been defined
44
+ def initialize(&block)
45
+ load_defaults!
46
+
47
+ @directories = Array.new
48
+ @additional_options ||= Array.new
49
+ @path ||= 'backups'
50
+ @port ||= 22
51
+ @mirror ||= false
52
+ @compress ||= false
53
+
54
+ instance_eval(&block) if block_given?
55
+
56
+ @path = path.sub(/^\~\//, '')
57
+ end
58
+
59
+ ##
60
+ # Performs the RSync operation
61
+ # debug options: -vhP
62
+ def perform!
63
+ Logger.message("#{ self.class } started syncing #{ directories }.")
64
+ Logger.silent( run("#{ utility(:rsync) } -vhP #{ options } #{ directories } '#{ username }@#{ ip }:#{ path }'") )
65
+ end
66
+
67
+ ##
68
+ # Returns all the specified Rsync options, concatenated, ready for the CLI
69
+ def options
70
+ ([archive, mirror, compress, port] + additional_options).compact.join("\s")
71
+ end
72
+
73
+ ##
74
+ # Returns Rsync syntax for enabling mirroring
75
+ def mirror
76
+ '--delete' if @mirror
77
+ end
78
+
79
+ ##
80
+ # Returns Rsync syntax for compressing the file transfers
81
+ def compress
82
+ '--compress' if @compress
83
+ end
84
+
85
+ ##
86
+ # Returns Rsync syntax for invoking "archive" mode
87
+ def archive
88
+ '--archive'
89
+ end
90
+
91
+ ##
92
+ # Returns Rsync syntax for defining a port to connect to
93
+ def port
94
+ "--port='#{@port}'"
95
+ end
96
+
97
+ ##
98
+ # If no block has been provided, it'll return the array of @directories.
99
+ # If a block has been provided, it'll evaluate it and add the defined paths to the @directories
100
+ def directories(&block)
101
+ unless block_given?
102
+ return @directories.map do |directory|
103
+ "'#{directory}'"
104
+ end.join("\s")
105
+ end
106
+ instance_eval(&block)
107
+ end
108
+
109
+ ##
110
+ # Adds a path to the @directories array
111
+ def add(path)
112
+ @directories << path
113
+ end
114
+
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,116 @@
1
+ # encoding: utf-8
2
+
3
+ module Backup
4
+ module Syncer
5
+ class S3 < Base
6
+
7
+ ##
8
+ # Amazon Simple Storage Service (S3) Credentials
9
+ attr_accessor :access_key_id, :secret_access_key
10
+
11
+ ##
12
+ # Amazon S3 bucket name and path to sync to
13
+ attr_accessor :bucket, :path
14
+
15
+ ##
16
+ # Directories to sync
17
+ attr_accessor :directories
18
+
19
+ ##
20
+ # Flag to enable mirroring
21
+ attr_accessor :mirror
22
+
23
+ ##
24
+ # Additional options for the s3sync cli
25
+ attr_accessor :additional_options
26
+
27
+ ##
28
+ # Instantiates a new S3 Syncer object and sets the default configuration
29
+ # specified in the Backup::Configuration::Syncer::S3. Then it sets the object
30
+ # defaults if particular properties weren't set. Finally it'll evaluate the users
31
+ # configuration file and overwrite anything that's been defined
32
+ def initialize(&block)
33
+ load_defaults!
34
+
35
+ @path ||= 'backups'
36
+ @directories ||= Array.new
37
+ @mirror ||= false
38
+ @additional_options ||= []
39
+
40
+ instance_eval(&block) if block_given?
41
+
42
+ @path = path.sub(/^\//, '')
43
+ end
44
+
45
+ ##
46
+ # Performs the S3Sync operation
47
+ # First it'll set the Amazon S3 credentials for S3Sync before invoking it,
48
+ # and once it's finished syncing the files and directories to Amazon S3, it'll
49
+ # unset these credentials (back to nil values)
50
+ def perform!
51
+ set_s3sync_credentials!
52
+
53
+ directories.each do |directory|
54
+ Logger.message("#{ self.class } started syncing '#{ directory }'.")
55
+ Logger.silent( run("#{ utility(:s3sync) } #{ options } '#{ directory }' '#{ bucket }:#{ path }'") )
56
+ end
57
+
58
+ unset_s3sync_credentials!
59
+ end
60
+
61
+ ##
62
+ # Returns all the specified S3Sync options, concatenated, ready for the CLI
63
+ def options
64
+ ([verbose, recursive, mirror] + additional_options).compact.join("\s")
65
+ end
66
+
67
+ ##
68
+ # Returns S3Sync syntax for enabling mirroring
69
+ def mirror
70
+ '--delete' if @mirror
71
+ end
72
+
73
+ ##
74
+ # Returns S3Sync syntax for syncing recursively
75
+ def recursive
76
+ '--recursive'
77
+ end
78
+
79
+ ##
80
+ # Returns S3Sync syntax for making output verbose
81
+ def verbose
82
+ '--verbose'
83
+ end
84
+
85
+ ##
86
+ # Syntactical suger for the DSL for adding directories
87
+ def directories(&block)
88
+ return @directories unless block_given?
89
+ instance_eval(&block)
90
+ end
91
+
92
+ ##
93
+ # Adds a path to the @directories array
94
+ def add(path)
95
+ @directories << path
96
+ end
97
+
98
+ ##
99
+ # In order for S3Sync to know what credentials to use, we have to set the
100
+ # AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables, these
101
+ # evironment variables will be used by S3Sync
102
+ def set_s3sync_credentials!
103
+ ENV['AWS_ACCESS_KEY_ID'] = access_key_id
104
+ ENV['AWS_SECRET_ACCESS_KEY'] = secret_access_key
105
+ end
106
+
107
+ ##
108
+ # Sets the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY back to nil
109
+ def unset_s3sync_credentials!
110
+ ENV['AWS_ACCESS_KEY_ID'] = nil
111
+ ENV['AWS_SECRET_ACCESS_KEY'] = nil
112
+ end
113
+
114
+ end
115
+ end
116
+ end