backup 3.0.19 → 3.0.20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (188) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +9 -8
  3. data/Gemfile.lock +19 -1
  4. data/Guardfile +13 -9
  5. data/README.md +93 -31
  6. data/backup.gemspec +3 -3
  7. data/bin/backup +6 -283
  8. data/lib/backup.rb +101 -72
  9. data/lib/backup/archive.rb +21 -9
  10. data/lib/backup/binder.rb +22 -0
  11. data/lib/backup/cleaner.rb +36 -0
  12. data/lib/backup/cli/helpers.rb +103 -0
  13. data/lib/backup/cli/utility.rb +308 -0
  14. data/lib/backup/compressor/base.rb +2 -2
  15. data/lib/backup/compressor/pbzip2.rb +76 -0
  16. data/lib/backup/configuration/compressor/pbzip2.rb +28 -0
  17. data/lib/backup/configuration/database/riak.rb +25 -0
  18. data/lib/backup/configuration/encryptor/open_ssl.rb +6 -0
  19. data/lib/backup/configuration/helpers.rb +5 -18
  20. data/lib/backup/configuration/notifier/base.rb +13 -0
  21. data/lib/backup/configuration/notifier/hipchat.rb +41 -0
  22. data/lib/backup/configuration/notifier/mail.rb +38 -0
  23. data/lib/backup/configuration/notifier/prowl.rb +23 -0
  24. data/lib/backup/configuration/storage/cloudfiles.rb +4 -0
  25. data/lib/backup/configuration/storage/dropbox.rb +8 -4
  26. data/lib/backup/database/base.rb +10 -2
  27. data/lib/backup/database/mongodb.rb +16 -19
  28. data/lib/backup/database/mysql.rb +2 -2
  29. data/lib/backup/database/postgresql.rb +2 -2
  30. data/lib/backup/database/redis.rb +15 -7
  31. data/lib/backup/database/riak.rb +45 -0
  32. data/lib/backup/dependency.rb +21 -7
  33. data/lib/backup/encryptor/base.rb +1 -1
  34. data/lib/backup/encryptor/open_ssl.rb +20 -5
  35. data/lib/backup/errors.rb +124 -0
  36. data/lib/backup/finder.rb +11 -3
  37. data/lib/backup/logger.rb +121 -82
  38. data/lib/backup/model.rb +103 -44
  39. data/lib/backup/notifier/base.rb +50 -0
  40. data/lib/backup/notifier/campfire.rb +32 -52
  41. data/lib/backup/notifier/hipchat.rb +99 -0
  42. data/lib/backup/notifier/mail.rb +100 -61
  43. data/lib/backup/notifier/presently.rb +31 -40
  44. data/lib/backup/notifier/prowl.rb +73 -0
  45. data/lib/backup/notifier/twitter.rb +29 -39
  46. data/lib/backup/packager.rb +25 -0
  47. data/lib/backup/splitter.rb +62 -0
  48. data/lib/backup/storage/base.rb +178 -18
  49. data/lib/backup/storage/cloudfiles.rb +34 -28
  50. data/lib/backup/storage/dropbox.rb +64 -67
  51. data/lib/backup/storage/ftp.rb +48 -40
  52. data/lib/backup/storage/local.rb +33 -28
  53. data/lib/backup/storage/ninefold.rb +40 -26
  54. data/lib/backup/storage/object.rb +8 -6
  55. data/lib/backup/storage/rsync.rb +61 -51
  56. data/lib/backup/storage/s3.rb +29 -27
  57. data/lib/backup/storage/scp.rb +56 -36
  58. data/lib/backup/storage/sftp.rb +49 -33
  59. data/lib/backup/syncer/base.rb +1 -1
  60. data/lib/backup/syncer/rsync.rb +1 -1
  61. data/lib/backup/template.rb +46 -0
  62. data/lib/backup/version.rb +1 -1
  63. data/spec/archive_spec.rb +34 -9
  64. data/spec/backup_spec.rb +1 -1
  65. data/spec/cli/helpers_spec.rb +35 -0
  66. data/spec/cli/utility_spec.rb +38 -0
  67. data/spec/compressor/bzip2_spec.rb +1 -1
  68. data/spec/compressor/gzip_spec.rb +1 -1
  69. data/spec/compressor/lzma_spec.rb +1 -1
  70. data/spec/compressor/pbzip2_spec.rb +63 -0
  71. data/spec/configuration/base_spec.rb +1 -1
  72. data/spec/configuration/compressor/bzip2_spec.rb +1 -1
  73. data/spec/configuration/compressor/gzip_spec.rb +1 -1
  74. data/spec/configuration/compressor/lzma_spec.rb +1 -1
  75. data/spec/configuration/database/base_spec.rb +1 -1
  76. data/spec/configuration/database/mongodb_spec.rb +1 -1
  77. data/spec/configuration/database/mysql_spec.rb +1 -1
  78. data/spec/configuration/database/postgresql_spec.rb +1 -1
  79. data/spec/configuration/database/redis_spec.rb +1 -1
  80. data/spec/configuration/database/riak_spec.rb +31 -0
  81. data/spec/configuration/encryptor/gpg_spec.rb +1 -1
  82. data/spec/configuration/encryptor/open_ssl_spec.rb +4 -1
  83. data/spec/configuration/notifier/campfire_spec.rb +1 -1
  84. data/spec/configuration/notifier/hipchat_spec.rb +43 -0
  85. data/spec/configuration/notifier/mail_spec.rb +34 -22
  86. data/spec/configuration/notifier/presently_spec.rb +1 -1
  87. data/spec/configuration/notifier/prowl_spec.rb +28 -0
  88. data/spec/configuration/notifier/twitter_spec.rb +1 -1
  89. data/spec/configuration/storage/cloudfiles_spec.rb +19 -16
  90. data/spec/configuration/storage/dropbox_spec.rb +1 -1
  91. data/spec/configuration/storage/ftp_spec.rb +1 -1
  92. data/spec/configuration/storage/local_spec.rb +1 -1
  93. data/spec/configuration/storage/ninefold_spec.rb +1 -1
  94. data/spec/configuration/storage/rsync_spec.rb +1 -1
  95. data/spec/configuration/storage/s3_spec.rb +1 -1
  96. data/spec/configuration/storage/scp_spec.rb +1 -1
  97. data/spec/configuration/storage/sftp_spec.rb +1 -1
  98. data/spec/configuration/syncer/rsync_spec.rb +1 -1
  99. data/spec/configuration/syncer/s3_spec.rb +1 -1
  100. data/spec/database/base_spec.rb +10 -1
  101. data/spec/database/mongodb_spec.rb +34 -7
  102. data/spec/database/mysql_spec.rb +8 -7
  103. data/spec/database/postgresql_spec.rb +8 -7
  104. data/spec/database/redis_spec.rb +39 -9
  105. data/spec/database/riak_spec.rb +50 -0
  106. data/spec/encryptor/gpg_spec.rb +1 -1
  107. data/spec/encryptor/open_ssl_spec.rb +77 -20
  108. data/spec/errors_spec.rb +306 -0
  109. data/spec/finder_spec.rb +91 -0
  110. data/spec/logger_spec.rb +254 -33
  111. data/spec/model_spec.rb +120 -15
  112. data/spec/notifier/campfire_spec.rb +127 -52
  113. data/spec/notifier/hipchat_spec.rb +193 -0
  114. data/spec/notifier/mail_spec.rb +290 -74
  115. data/spec/notifier/presently_spec.rb +290 -73
  116. data/spec/notifier/prowl_spec.rb +149 -0
  117. data/spec/notifier/twitter_spec.rb +106 -41
  118. data/spec/spec_helper.rb +8 -2
  119. data/spec/splitter_spec.rb +71 -0
  120. data/spec/storage/base_spec.rb +280 -19
  121. data/spec/storage/cloudfiles_spec.rb +38 -22
  122. data/spec/storage/dropbox_spec.rb +17 -13
  123. data/spec/storage/ftp_spec.rb +145 -55
  124. data/spec/storage/local_spec.rb +6 -6
  125. data/spec/storage/ninefold_spec.rb +70 -29
  126. data/spec/storage/object_spec.rb +44 -44
  127. data/spec/storage/rsync_spec.rb +186 -63
  128. data/spec/storage/s3_spec.rb +23 -24
  129. data/spec/storage/scp_spec.rb +116 -41
  130. data/spec/storage/sftp_spec.rb +124 -46
  131. data/spec/syncer/rsync_spec.rb +3 -3
  132. data/spec/syncer/s3_spec.rb +1 -1
  133. data/spec/version_spec.rb +1 -1
  134. data/templates/cli/utility/archive +13 -0
  135. data/{lib/templates → templates/cli/utility}/compressor/bzip2 +1 -1
  136. data/{lib/templates → templates/cli/utility}/compressor/gzip +1 -1
  137. data/{lib/templates → templates/cli/utility}/compressor/lzma +0 -0
  138. data/templates/cli/utility/compressor/pbzip2 +7 -0
  139. data/templates/cli/utility/config +31 -0
  140. data/{lib/templates → templates/cli/utility}/database/mongodb +1 -1
  141. data/{lib/templates → templates/cli/utility}/database/mysql +1 -1
  142. data/{lib/templates → templates/cli/utility}/database/postgresql +1 -1
  143. data/{lib/templates → templates/cli/utility}/database/redis +1 -1
  144. data/templates/cli/utility/database/riak +8 -0
  145. data/{lib/templates → templates/cli/utility}/encryptor/gpg +1 -1
  146. data/templates/cli/utility/encryptor/openssl +9 -0
  147. data/templates/cli/utility/model.erb +23 -0
  148. data/{lib/templates → templates/cli/utility}/notifier/campfire +2 -1
  149. data/templates/cli/utility/notifier/hipchat +15 -0
  150. data/{lib/templates → templates/cli/utility}/notifier/mail +6 -1
  151. data/{lib/templates → templates/cli/utility}/notifier/presently +1 -0
  152. data/templates/cli/utility/notifier/prowl +11 -0
  153. data/{lib/templates → templates/cli/utility}/notifier/twitter +2 -1
  154. data/templates/cli/utility/splitter +7 -0
  155. data/templates/cli/utility/storage/cloudfiles +12 -0
  156. data/{lib/templates → templates/cli/utility}/storage/dropbox +1 -1
  157. data/{lib/templates → templates/cli/utility}/storage/ftp +0 -0
  158. data/templates/cli/utility/storage/local +7 -0
  159. data/{lib/templates → templates/cli/utility}/storage/ninefold +1 -1
  160. data/templates/cli/utility/storage/rsync +11 -0
  161. data/{lib/templates → templates/cli/utility}/storage/s3 +0 -2
  162. data/templates/cli/utility/storage/scp +11 -0
  163. data/templates/cli/utility/storage/sftp +11 -0
  164. data/{lib/templates → templates/cli/utility}/syncer/rsync +1 -1
  165. data/{lib/templates → templates/cli/utility}/syncer/s3 +1 -1
  166. data/templates/general/links +11 -0
  167. data/templates/general/version.erb +2 -0
  168. data/templates/notifier/mail/failure.erb +9 -0
  169. data/templates/notifier/mail/success.erb +7 -0
  170. data/templates/notifier/mail/warning.erb +9 -0
  171. data/templates/storage/dropbox/authorization_url.erb +6 -0
  172. data/templates/storage/dropbox/authorized.erb +4 -0
  173. data/templates/storage/dropbox/cache_file_written.erb +10 -0
  174. metadata +81 -45
  175. data/lib/backup/cli.rb +0 -110
  176. data/lib/backup/exception/command_failed.rb +0 -8
  177. data/lib/backup/exception/command_not_found.rb +0 -8
  178. data/lib/backup/notifier/binder.rb +0 -32
  179. data/lib/backup/notifier/templates/notify_failure.erb +0 -33
  180. data/lib/backup/notifier/templates/notify_success.erb +0 -16
  181. data/lib/templates/archive +0 -7
  182. data/lib/templates/encryptor/openssl +0 -8
  183. data/lib/templates/readme +0 -15
  184. data/lib/templates/storage/cloudfiles +0 -11
  185. data/lib/templates/storage/local +0 -7
  186. data/lib/templates/storage/rsync +0 -11
  187. data/lib/templates/storage/scp +0 -11
  188. data/lib/templates/storage/sftp +0 -11
@@ -24,44 +24,42 @@ module Backup
24
24
  # use passive mode?
25
25
  attr_accessor :passive_mode
26
26
 
27
- ##
28
- # Creates a new instance of the FTP 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
- @port ||= 21
35
- @path ||= 'backups'
36
- @passive_mode ||= false
37
-
38
- instance_eval(&block) if block_given?
39
-
40
- @time = TIME
41
- @path = path.sub(/^\~\//, '')
42
- end
43
-
44
27
  ##
45
28
  # This is the remote path to where the backup files will be stored
46
29
  def remote_path
47
- File.join(path, TRIGGER)
30
+ File.join(path, TRIGGER, @time)
48
31
  end
49
32
 
50
33
  ##
51
34
  # Performs the backup transfer
52
35
  def perform!
36
+ super
53
37
  transfer!
54
38
  cycle!
55
39
  end
56
40
 
57
41
  private
58
42
 
43
+ ##
44
+ # Set configuration defaults before evaluating configuration block,
45
+ # after setting defaults from Storage::Base
46
+ def pre_configure
47
+ super
48
+ @port ||= 21
49
+ @path ||= 'backups'
50
+ @passive_mode ||= false
51
+ end
52
+
53
+ ##
54
+ # Adjust configuration after evaluating configuration block,
55
+ # after adjustments from Storage::Base
56
+ def post_configure
57
+ super
58
+ @path = path.sub(/^\~\//, '')
59
+ end
60
+
59
61
  ##
60
62
  # Establishes a connection to the remote server and returns the Net::FTP object.
61
- # Not doing any instance variable caching because this object gets persisted in YAML
62
- # format to a file and will issues. This, however has no impact on performance since it only
63
- # gets invoked once per object for a #transfer! and once for a remove! Backups run in the
64
- # background anyway so even if it were a bit slower it shouldn't matter.
65
63
  #
66
64
  # Note *
67
65
  # Since the FTP port is defined as a constant in the Net::FTP class, and might be required
@@ -71,31 +69,41 @@ module Backup
71
69
  Net::FTP.send(:remove_const, :FTP_PORT)
72
70
  end; Net::FTP.send(:const_set, :FTP_PORT, port)
73
71
 
74
- ftp = Net::FTP.new(ip, username, password)
75
- ftp.passive = true if passive_mode
76
- ftp
72
+ Net::FTP.open(ip, username, password) do |ftp|
73
+ ftp.passive = true if passive_mode
74
+ yield ftp
75
+ end
77
76
  end
78
77
 
79
78
  ##
80
79
  # Transfers the archived file to the specified remote server
81
80
  def transfer!
82
- Logger.message("#{ self.class } started transferring \"#{ remote_file }\".")
83
- create_remote_directories!
84
- connection.put(
85
- File.join(local_path, local_file),
86
- File.join(remote_path, remote_file)
87
- )
81
+ connection do |ftp|
82
+ create_remote_directories(ftp)
83
+
84
+ files_to_transfer do |local_file, remote_file|
85
+ Logger.message "#{storage_name} started transferring " +
86
+ "'#{ local_file }' to '#{ ip }'."
87
+ ftp.put(
88
+ File.join(local_path, local_file),
89
+ File.join(remote_path, remote_file)
90
+ )
91
+ end
92
+ end
88
93
  end
89
94
 
90
95
  ##
91
96
  # Removes the transferred archive file from the server
92
97
  def remove!
93
- begin
94
- connection.delete(
95
- File.join(remote_path, remote_file)
96
- )
97
- rescue Net::FTPPermError
98
- Logger.warn "Could not remove file \"#{ File.join(remote_path, remote_file) }\"."
98
+ connection do |ftp|
99
+ transferred_files do |local_file, remote_file|
100
+ Logger.message "#{storage_name} started removing " +
101
+ "'#{ local_file }' from '#{ ip }'."
102
+
103
+ ftp.delete(File.join(remote_path, remote_file))
104
+ end
105
+
106
+ ftp.rmdir(remote_path)
99
107
  end
100
108
  end
101
109
 
@@ -105,13 +113,13 @@ module Backup
105
113
  # paths to directories that don't yet exist when creating new directories.
106
114
  # Instead, we split the parts up in to an array (for each '/') and loop through
107
115
  # that to create the directories one by one. Net::FTP raises an exception when
108
- # the directory it's trying ot create already exists, so we have rescue it
109
- def create_remote_directories!
116
+ # the directory it's trying to create already exists, so we have rescue it
117
+ def create_remote_directories(ftp)
110
118
  path_parts = Array.new
111
119
  remote_path.split('/').each do |path_part|
112
120
  path_parts << path_part
113
121
  begin
114
- connection.mkdir(path_parts.join('/'))
122
+ ftp.mkdir(path_parts.join('/'))
115
123
  rescue Net::FTPPermError; end
116
124
  end
117
125
  end
@@ -12,53 +12,64 @@ module Backup
12
12
  # Path to store backups to
13
13
  attr_accessor :path
14
14
 
15
- ##
16
- # Creates a new instance of the Local storage object
17
- # First it sets the defaults (if any exist) and then evaluates
18
- # the configuration block which may overwrite these defaults
19
- def initialize(&block)
20
- load_defaults!
21
-
22
- @path ||= "#{ENV['HOME']}/backups"
23
-
24
- instance_eval(&block) if block_given?
25
-
26
- @time = TIME
27
- fix_path!
28
- end
29
-
30
15
  ##
31
16
  # This is the remote path to where the backup files will be stored.
32
17
  # Eventhough it says "remote", it's actually the "local" path, but
33
18
  # the naming is necessary for compatibility reasons
34
19
  def remote_path
35
- File.join(path, TRIGGER)
20
+ File.join(path, TRIGGER, @time)
36
21
  end
37
22
 
38
23
  ##
39
24
  # Performs the backup transfer
40
25
  def perform!
26
+ super
41
27
  transfer!
42
28
  cycle!
43
29
  end
44
30
 
45
31
  private
46
32
 
33
+ ##
34
+ # Set configuration defaults before evaluating configuration block,
35
+ # after setting defaults from Storage::Base
36
+ def pre_configure
37
+ super
38
+ @path ||= "#{ENV['HOME']}/backups"
39
+ end
40
+
41
+ ##
42
+ # Adjust configuration after evaluating configuration block,
43
+ # after adjustments from Storage::Base
44
+ def post_configure
45
+ super
46
+ @path = File.expand_path(path)
47
+ end
48
+
47
49
  ##
48
50
  # Transfers the archived file to the specified local path
49
51
  def transfer!
50
- Logger.message("#{ self.class } started transferring \"#{ remote_file }\".")
51
52
  create_local_directories!
52
- FileUtils.cp(
53
- File.join(local_path, local_file),
54
- File.join(remote_path, remote_file)
55
- )
53
+
54
+ files_to_transfer do |local_file, remote_file|
55
+ Logger.message "#{storage_name} started transferring '#{ local_file }'."
56
+ FileUtils.cp(
57
+ File.join(local_path, local_file),
58
+ File.join(remote_path, remote_file)
59
+ )
60
+ end
56
61
  end
57
62
 
58
63
  ##
59
64
  # Removes the transferred archive file from the local path
60
65
  def remove!
61
- FileUtils.rm(File.join(remote_path, remote_file))
66
+ messages = []
67
+ transferred_files do |local_file, remote_file|
68
+ messages << "#{storage_name} started removing '#{ local_file }'."
69
+ end
70
+ Logger.message messages.join("\n")
71
+
72
+ FileUtils.rm_r(remote_path)
62
73
  end
63
74
 
64
75
  ##
@@ -67,12 +78,6 @@ module Backup
67
78
  FileUtils.mkdir_p(remote_path)
68
79
  end
69
80
 
70
- ##
71
- # Replaces ~/ with the full path to the users $HOME directory
72
- def fix_path!
73
- @path = path.sub(/^\~\//, "#{ENV['HOME']}/")
74
- end
75
-
76
81
  end
77
82
  end
78
83
  end
@@ -16,25 +16,10 @@ module Backup
16
16
  # Ninefold directory path
17
17
  attr_accessor :path
18
18
 
19
- ##
20
- # Creates a new instance of the Ninefold storage object
21
- # First it sets the defaults (if any exist) and then evaluates
22
- # the configuration block which may overwrite these defaults
23
- #
24
- def initialize(&block)
25
- load_defaults!
26
-
27
- @path ||= 'backups'
28
-
29
- instance_eval(&block) if block_given?
30
-
31
- @time = TIME
32
- end
33
-
34
19
  ##
35
20
  # This is the remote path to where the backup files will be stored
36
21
  def remote_path
37
- File.join(path, TRIGGER).sub(/^\//, '')
22
+ File.join(path, TRIGGER, @time).sub(/^\//, '')
38
23
  end
39
24
 
40
25
  ##
@@ -46,12 +31,28 @@ module Backup
46
31
  ##
47
32
  # Performs the backup transfer
48
33
  def perform!
34
+ super
49
35
  transfer!
50
36
  cycle!
51
37
  end
52
38
 
53
39
  private
54
40
 
41
+ ##
42
+ # Set configuration defaults before evaluating configuration block,
43
+ # after setting defaults from Storage::Base
44
+ def pre_configure
45
+ super
46
+ @path ||= 'backups'
47
+ end
48
+
49
+ ##
50
+ # Adjust configuration after evaluating configuration block,
51
+ # after adjustments from Storage::Base
52
+ def post_configure
53
+ super
54
+ end
55
+
55
56
  ##
56
57
  # Establishes a connection to Amazon S3 and returns the Fog object.
57
58
  # Not doing any instance variable caching because this object gets persisted in YAML
@@ -59,7 +60,7 @@ module Backup
59
60
  # gets invoked once per object for a #transfer! and once for a remove! Backups run in the
60
61
  # background anyway so even if it were a bit slower it shouldn't matter.
61
62
  def connection
62
- Fog::Storage.new(
63
+ @connection ||= Fog::Storage.new(
63
64
  :provider => provider,
64
65
  :ninefold_storage_token => storage_token,
65
66
  :ninefold_storage_secret => storage_secret
@@ -69,26 +70,39 @@ module Backup
69
70
  ##
70
71
  # Transfers the archived file to the specified directory
71
72
  def transfer!
72
- begin
73
- Logger.message("#{ self.class } started transferring \"#{ remote_file }\".")
74
- directory = connection.directories.get remote_path
73
+ files_to_transfer do |local_file, remote_file|
74
+ Logger.message "#{storage_name} started transferring '#{ local_file }'."
75
+ directory = connection.directories.get(remote_path)
75
76
  directory ||= connection.directories.create(:key => remote_path)
76
77
  directory.files.create(
77
78
  :key => remote_file,
78
79
  :body => File.open(File.join(local_path, local_file))
79
80
  )
80
- rescue Excon::Errors::NotFound
81
- raise "An error occurred while trying to transfer the file."
82
81
  end
83
82
  end
84
83
 
85
84
  ##
86
85
  # Removes the transferred archive file from the Amazon S3 bucket
87
86
  def remove!
88
- begin
89
- directory = connection.directories.get remote_path
90
- directory.files.get(remote_file).destroy
91
- rescue Excon::Errors::SocketError; end
87
+ if directory = connection.directories.get(remote_path)
88
+ transferred_files do |local_file, remote_file|
89
+ Logger.message "#{storage_name} started removing " +
90
+ "'#{ local_file }' from Ninefold.'"
91
+
92
+ if file = directory.files.get(remote_file)
93
+ file.destroy
94
+ else
95
+ # Note: Fog-0.11.0 will return nil if remote_file is not found
96
+ raise Errors::Storage::Ninefold::NotFoundError,
97
+ "'#{remote_file}' not found in '#{remote_path}'", caller(1)
98
+ end
99
+ end
100
+ directory.destroy
101
+ else
102
+ # Note: Fog-0.11.0 will return nil if remote_path is not found
103
+ raise Errors::Storage::Ninefold::NotFoundError,
104
+ "Directory at '#{remote_path}' not found", caller(1)
105
+ end
92
106
  end
93
107
 
94
108
  end
@@ -11,8 +11,10 @@ module Backup
11
11
  ##
12
12
  # Instantiates a new Backup::Storage::Object and stores the
13
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")
14
+ def initialize(type, storage_id)
15
+ suffix = storage_id.to_s.strip.gsub(/[\W\s]/, '_')
16
+ filename = suffix.empty? ? type : "#{type}-#{suffix}"
17
+ @storage_file = File.join(DATA_PATH, TRIGGER, "#{filename}.yml")
16
18
  end
17
19
 
18
20
  ##
@@ -24,11 +26,11 @@ module Backup
24
26
  # descending. The newest backup storage object comes in Backup::Storage::Object.load[0]
25
27
  # and the oldest in Backup::Storage::Object.load[-1]
26
28
  def load
27
- if File.exist?(storage_file)
28
- YAML.load_file(storage_file).sort { |a,b| b.time <=> a.time }
29
- else
30
- []
29
+ objects = []
30
+ if File.exist?(storage_file) and not File.zero?(storage_file)
31
+ objects = YAML.load_file(storage_file).sort { |a,b| b.time <=> a.time }
31
32
  end
33
+ objects
32
34
  end
33
35
 
34
36
  ##
@@ -11,7 +11,7 @@ Backup::Dependency.load('net-ssh')
11
11
  module Backup
12
12
  module Storage
13
13
  class RSync < Base
14
- include Backup::CLI
14
+ include Backup::CLI::Helpers
15
15
 
16
16
  ##
17
17
  # Server credentials
@@ -29,24 +29,6 @@ module Backup
29
29
  # Flag to use local backups
30
30
  attr_accessor :local
31
31
 
32
- ##
33
- # Creates a new instance of the RSync storage object
34
- # First it sets the defaults (if any exist) and then evaluates
35
- # the configuration block which may overwrite these defaults
36
- def initialize(&block)
37
- load_defaults!
38
-
39
- @port ||= 22
40
- @path ||= 'backups'
41
- @local ||= false
42
-
43
- instance_eval(&block) if block_given?
44
- write_password_file!
45
-
46
- @time = TIME
47
- @path = path.sub(/^\~\//, '')
48
- end
49
-
50
32
  ##
51
33
  # This is the remote path to where the backup files will be stored
52
34
  def remote_path
@@ -56,60 +38,67 @@ module Backup
56
38
  ##
57
39
  # Performs the backup transfer
58
40
  def perform!
41
+ super
42
+ write_password_file!
59
43
  transfer!
44
+ ensure
60
45
  remove_password_file!
61
46
  end
62
47
 
63
- ##
64
- # Returns Rsync syntax for defining a port to connect to
65
- def port
66
- "-e 'ssh -p #{@port}'"
67
- end
48
+ private
68
49
 
69
50
  ##
70
- # Returns Rsync syntax for using a password file
71
- def password
72
- "--password-file='#{@password_file.path}'" unless @password.nil?
51
+ # Set configuration defaults before evaluating configuration block,
52
+ # after setting defaults from Storage::Base
53
+ def pre_configure
54
+ super
55
+ @port ||= 22
56
+ @path ||= 'backups'
57
+ @local ||= false
73
58
  end
74
59
 
75
60
  ##
76
- # RSync options
77
- # -z = Compresses the bytes that will be transferred to reduce bandwidth usage
78
- def options
79
- "-z"
61
+ # Adjust configuration after evaluating configuration block,
62
+ # after adjustments from Storage::Base
63
+ def post_configure
64
+ super
65
+ @path = path.sub(/^\~\//, '')
80
66
  end
81
67
 
82
- private
83
-
84
68
  ##
85
69
  # Establishes a connection to the remote server and returns the Net::SSH object.
86
- # Not doing any instance variable caching because this object gets persisted in YAML
87
- # format to a file and will issues. This, however has no impact on performance since it only
88
- # gets invoked once per object for a #transfer! and once for a remove! Backups run in the
89
- # background anyway so even if it were a bit slower it shouldn't matter.
90
70
  def connection
91
- Net::SSH.start(ip, username, :password => @password, :port => @port)
71
+ Net::SSH.start(ip, username, :password => password, :port => port) do |ssh|
72
+ yield ssh
73
+ end
92
74
  end
93
75
 
94
76
  ##
95
77
  # Transfers the archived file to the specified remote server
96
78
  def transfer!
97
- Logger.message("#{ self.class } started transferring \"#{ remote_file }\".")
98
79
  create_remote_directories!
99
- if @local
100
- run("#{ utility(:rsync) } '#{ File.join(local_path, local_file) }' '#{ File.join(remote_path, TIME+'.'+remote_file[20..-1]) }'")
80
+
81
+ Logger.message "#{storage_name} started transferring " +
82
+ "'#{ filename }' to '#{ ip }'."
83
+
84
+ if local
85
+ run(
86
+ "#{ utility(:rsync) } '#{ File.join(local_path, filename) }' " +
87
+ "'#{ File.join(remote_path, filename[20..-1]) }'"
88
+ )
101
89
  else
102
- run("#{ utility(:rsync) } #{ options } #{ port } #{ password } '#{ File.join(local_path, local_file) }' '#{ username }@#{ ip }:#{ File.join(remote_path, remote_file[20..-1]) }'")
90
+ run(
91
+ "#{ utility(:rsync) } #{ rsync_options } #{ rsync_port } " +
92
+ "#{ rsync_password_file } '#{ File.join(local_path, filename) }' " +
93
+ "'#{ username }@#{ ip }:#{ File.join(remote_path, filename[20..-1]) }'"
94
+ )
103
95
  end
104
96
  end
105
97
 
106
98
  ##
107
- # Removes the transferred archive file from the server
99
+ # Note: RSync::Storage doesn't cycle
108
100
  def remove!
109
- response = connection.exec!("rm #{ File.join(remote_path, remote_file) }")
110
- if response =~ /No such file or directory/
111
- Logger.warn "Could not remove file \"#{ File.join(remote_path, remote_file) }\"."
112
- end
101
+ nil
113
102
  end
114
103
 
115
104
  ##
@@ -119,7 +108,9 @@ module Backup
119
108
  if @local
120
109
  mkdir(remote_path)
121
110
  else
122
- connection.exec!("mkdir -p '#{ remote_path }'")
111
+ connection do |ssh|
112
+ ssh.exec!("mkdir -p '#{ remote_path }'")
113
+ end
123
114
  end
124
115
  end
125
116
 
@@ -127,9 +118,9 @@ module Backup
127
118
  # Writes the provided password to a temporary file so that
128
119
  # the rsync utility can read the password from this file
129
120
  def write_password_file!
130
- unless @password.nil?
121
+ unless password.nil?
131
122
  @password_file = Tempfile.new('backup-rsync-password')
132
- @password_file.write(@password)
123
+ @password_file.write(password)
133
124
  @password_file.close
134
125
  end
135
126
  end
@@ -138,7 +129,26 @@ module Backup
138
129
  # Removes the previously created @password_file
139
130
  # (temporary file containing the password)
140
131
  def remove_password_file!
141
- @password_file.unlink unless @password.nil?
132
+ @password_file.delete if @password_file
133
+ end
134
+
135
+ ##
136
+ # Returns Rsync syntax for using a password file
137
+ def rsync_password_file
138
+ "--password-file='#{@password_file.path}'" if @password_file
139
+ end
140
+
141
+ ##
142
+ # Returns Rsync syntax for defining a port to connect to
143
+ def rsync_port
144
+ "-e 'ssh -p #{port}'"
145
+ end
146
+
147
+ ##
148
+ # RSync options
149
+ # -z = Compresses the bytes that will be transferred to reduce bandwidth usage
150
+ def rsync_options
151
+ "-z"
142
152
  end
143
153
 
144
154
  end