backup 3.0.14 → 3.0.15
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +2 -0
- data/bin/backup +12 -5
- data/lib/backup/cli.rb +8 -1
- data/lib/backup/configuration/database/mongodb.rb +4 -0
- data/lib/backup/database/mongodb.rb +46 -4
- data/lib/backup/logger.rb +12 -4
- data/lib/backup/storage/rsync.rb +32 -2
- data/lib/backup/syncer/rsync.rb +37 -2
- data/lib/backup/version.rb +1 -1
- data/lib/templates/database/mongodb +1 -0
- data/spec/database/mongodb_spec.rb +37 -0
- data/spec/logger_spec.rb +12 -0
- data/spec/storage/rsync_spec.rb +26 -10
- data/spec/syncer/rsync_spec.rb +43 -4
- metadata +4 -5
data/README.md
CHANGED
@@ -205,6 +205,8 @@ The __Mail__ notifier. I have not provided the SMTP options to use my Gmail acco
|
|
205
205
|
|
206
206
|
The __Twitter__ notifier. You will require your consumer and oauth credentials, which I have also left out of this example.
|
207
207
|
|
208
|
+
MongoDB backup utility (mongodump) by default does not fsync & lock the database, opening a possibility for inconsistent data dump. This is addressed by setting lock = true which causes mongodump to be wrapped with lock&fsync calls (with a lock takedown after the dump). Please check the Wiki on this subject and remember this is a very fresh feature, needing some more real-world testing. Disabled at default.
|
209
|
+
|
208
210
|
Check out the Wiki for more information on all the above subjects.
|
209
211
|
|
210
212
|
### And that's it!
|
data/bin/backup
CHANGED
@@ -31,11 +31,12 @@ class BackupCLI < Thor
|
|
31
31
|
# Performs the backup process. The only required option is the --trigger [-t].
|
32
32
|
# If the other options (--config_file, --data_path, --tmp_path) aren't specified
|
33
33
|
# it'll fallback to the (good) defaults
|
34
|
-
method_option :trigger, :type => :string,
|
35
|
-
method_option :config_file, :type => :string,
|
36
|
-
method_option :data_path, :type => :string,
|
37
|
-
method_option :log_path, :type => :string,
|
34
|
+
method_option :trigger, :type => :string, :aliases => ['-t', '--triggers'], :required => true
|
35
|
+
method_option :config_file, :type => :string, :aliases => '-c'
|
36
|
+
method_option :data_path, :type => :string, :aliases => '-d'
|
37
|
+
method_option :log_path, :type => :string, :aliases => '-l'
|
38
38
|
method_option :tmp_path, :type => :string
|
39
|
+
method_option :quiet, :type => :boolean, :aliases => '-q'
|
39
40
|
desc 'perform', "Performs the backup for the specified trigger.\n" +
|
40
41
|
"You may perform multiple backups by providing multiple triggers, separated by commas.\n\n" +
|
41
42
|
"Example:\n\s\s$ backup perform --triggers backup1,backup2,backup3,backup4\n\n" +
|
@@ -76,6 +77,12 @@ class BackupCLI < Thor
|
|
76
77
|
FileUtils.mkdir_p(path)
|
77
78
|
end
|
78
79
|
|
80
|
+
##
|
81
|
+
# Silence Backup::Logger from printing to STDOUT, if --quiet was specified
|
82
|
+
if options[:quiet]
|
83
|
+
Backup::Logger.send(:const_set, :QUIET, options[:quiet])
|
84
|
+
end
|
85
|
+
|
79
86
|
##
|
80
87
|
# Process each trigger
|
81
88
|
options[:trigger].split(",").map(&:strip).each do |trigger|
|
@@ -257,4 +264,4 @@ end
|
|
257
264
|
|
258
265
|
##
|
259
266
|
# Enable the CLI for the Backup binary
|
260
|
-
BackupCLI.start
|
267
|
+
BackupCLI.start
|
data/lib/backup/cli.rb
CHANGED
@@ -8,6 +8,10 @@ module Backup
|
|
8
8
|
# through a ruby method. This helps with test coverage and
|
9
9
|
# improves readability.
|
10
10
|
#
|
11
|
+
# It'll first remove all prefixing slashes ( / ) by using .gsub(/^\s+/, '')
|
12
|
+
# This allows for the EOS blocks to be indented without actually using any
|
13
|
+
# prefixing spaces. This cleans up the implementation code.
|
14
|
+
#
|
11
15
|
# Every time the Backup::CLI#run method is invoked, it'll invoke
|
12
16
|
# the Backup::CLI#raise_if_command_not_found method after running the
|
13
17
|
# requested command on the OS.
|
@@ -17,6 +21,7 @@ module Backup
|
|
17
21
|
# name (e.g. mongodump, pgdump, etc) from a command like "/usr/local/bin/mongodump <options>"
|
18
22
|
# and pass that in to the Backup::CLI#raise_if_command_not_found
|
19
23
|
def run(command)
|
24
|
+
command.gsub!(/^\s+/, '')
|
20
25
|
%x[#{command}]
|
21
26
|
raise_if_command_not_found!(
|
22
27
|
command.slice(0, command.index(/\s/)).split('/')[-1]
|
@@ -67,7 +72,9 @@ module Backup
|
|
67
72
|
# and notify the user via the built-in notifiers if these are set.
|
68
73
|
def raise_if_command_not_found!(utility)
|
69
74
|
if $?.to_i.eql?(32512)
|
70
|
-
raise Exception::CommandNotFound , "Could not find the utility \"#{utility}\" on \"#{RUBY_PLATFORM}\"
|
75
|
+
raise Exception::CommandNotFound , "Could not find the utility \"#{utility}\" on \"#{RUBY_PLATFORM}\".\n" +
|
76
|
+
"If this is a database utility, try defining the 'utility_path' option in the configuration file.\n" +
|
77
|
+
"See the Database Wiki for more information about the Utility Path option."
|
71
78
|
end
|
72
79
|
end
|
73
80
|
|
@@ -28,6 +28,10 @@ module Backup
|
|
28
28
|
# Additional "mongodump" options
|
29
29
|
attr_accessor :additional_options
|
30
30
|
|
31
|
+
##
|
32
|
+
# 'lock' dump meaning wrapping mongodump with fsync & lock
|
33
|
+
attr_accessor :lock
|
34
|
+
|
31
35
|
##
|
32
36
|
# Creates a new instance of the MongoDB database object
|
33
37
|
def initialize(&block)
|
@@ -36,6 +40,7 @@ module Backup
|
|
36
40
|
@only_collections ||= Array.new
|
37
41
|
@additional_options ||= Array.new
|
38
42
|
@ipv6 ||= false
|
43
|
+
@lock ||= false
|
39
44
|
|
40
45
|
instance_eval(&block)
|
41
46
|
prepare!
|
@@ -109,10 +114,17 @@ module Backup
|
|
109
114
|
def perform!
|
110
115
|
log!
|
111
116
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
117
|
+
begin
|
118
|
+
lock_database if @lock.eql?(true)
|
119
|
+
if collections_to_dump.is_a?(Array) and not collections_to_dump.empty?
|
120
|
+
specific_collection_dump!
|
121
|
+
else
|
122
|
+
dump!
|
123
|
+
end
|
124
|
+
unlock_database if @lock.eql?(true)
|
125
|
+
rescue => exception
|
126
|
+
unlock_database if @lock.eql?(true)
|
127
|
+
raise exception
|
116
128
|
end
|
117
129
|
end
|
118
130
|
|
@@ -132,6 +144,36 @@ module Backup
|
|
132
144
|
end
|
133
145
|
end
|
134
146
|
|
147
|
+
##
|
148
|
+
# Builds the full mongo string based on all attributes
|
149
|
+
def mongo_shell
|
150
|
+
[utility(:mongo), database, credential_options, connectivity_options, ipv6].join(' ')
|
151
|
+
end
|
152
|
+
|
153
|
+
##
|
154
|
+
# Locks and FSyncs the database to bring it up to sync
|
155
|
+
# and ensure no 'write operations' are performed during the
|
156
|
+
# dump process
|
157
|
+
def lock_database
|
158
|
+
lock_command = <<-EOS
|
159
|
+
echo 'use admin
|
160
|
+
db.runCommand({"fsync" : 1, "lock" : 1})' | #{mongo_shell}
|
161
|
+
EOS
|
162
|
+
|
163
|
+
run(lock_command)
|
164
|
+
end
|
165
|
+
|
166
|
+
##
|
167
|
+
# Unlocks the (locked) database
|
168
|
+
def unlock_database
|
169
|
+
unlock_command = <<-EOS
|
170
|
+
echo 'use admin
|
171
|
+
db.$cmd.sys.unlock.findOne()' | #{mongo_shell}
|
172
|
+
EOS
|
173
|
+
|
174
|
+
run(unlock_command)
|
175
|
+
end
|
176
|
+
|
135
177
|
end
|
136
178
|
end
|
137
179
|
end
|
data/lib/backup/logger.rb
CHANGED
@@ -6,21 +6,21 @@ module Backup
|
|
6
6
|
##
|
7
7
|
# Outputs a messages to the console and writes it to the backup.log
|
8
8
|
def self.message(string)
|
9
|
-
puts loggify(:message, string, :green)
|
9
|
+
puts loggify(:message, string, :green) unless quiet?
|
10
10
|
to_file loggify(:message, string)
|
11
11
|
end
|
12
12
|
|
13
13
|
##
|
14
14
|
# Outputs an error to the console and writes it to the backup.log
|
15
15
|
def self.error(string)
|
16
|
-
puts loggify(:error, string, :red)
|
16
|
+
puts loggify(:error, string, :red) unless quiet?
|
17
17
|
to_file loggify(:error, string)
|
18
18
|
end
|
19
19
|
|
20
20
|
##
|
21
21
|
# Outputs a notice to the console and writes it to the backup.log
|
22
22
|
def self.warn(string)
|
23
|
-
puts loggify(:warning, string, :yellow)
|
23
|
+
puts loggify(:warning, string, :yellow) unless quiet?
|
24
24
|
to_file loggify(:warning, string)
|
25
25
|
end
|
26
26
|
|
@@ -28,7 +28,7 @@ module Backup
|
|
28
28
|
# Outputs the data as if it were a regular 'puts' command,
|
29
29
|
# but also logs it to the backup.log
|
30
30
|
def self.normal(string)
|
31
|
-
puts string
|
31
|
+
puts string unless quiet?
|
32
32
|
to_file string
|
33
33
|
end
|
34
34
|
|
@@ -90,5 +90,13 @@ module Backup
|
|
90
90
|
"\e[#{code}m#{string}\e[0m"
|
91
91
|
end
|
92
92
|
|
93
|
+
##
|
94
|
+
# Returns 'true' (boolean) if the QUIET constant is defined
|
95
|
+
# By default it isn't defined, only when initializing Backup using
|
96
|
+
# the '--quite' (or '-q') option in the CLI (e.g. backup perform -t my_backup --quiet)
|
97
|
+
def self.quiet?
|
98
|
+
const_defined?(:QUIET) && QUIET
|
99
|
+
end
|
100
|
+
|
93
101
|
end
|
94
102
|
end
|
data/lib/backup/storage/rsync.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
+
##
|
4
|
+
# Require the tempfile Ruby library when Backup::Storage::RSync is loaded
|
5
|
+
require 'tempfile'
|
6
|
+
|
3
7
|
##
|
4
8
|
# Only load the Net::SSH library when the Backup::Storage::RSync class is loaded
|
5
9
|
Backup::Dependency.load('net-ssh')
|
@@ -32,6 +36,7 @@ module Backup
|
|
32
36
|
@path ||= 'backups'
|
33
37
|
|
34
38
|
instance_eval(&block) if block_given?
|
39
|
+
write_password_file!
|
35
40
|
|
36
41
|
@time = TIME
|
37
42
|
@path = path.sub(/^\~\//, '')
|
@@ -47,6 +52,7 @@ module Backup
|
|
47
52
|
# Performs the backup transfer
|
48
53
|
def perform!
|
49
54
|
transfer!
|
55
|
+
remove_password_file!
|
50
56
|
end
|
51
57
|
|
52
58
|
private
|
@@ -58,7 +64,7 @@ module Backup
|
|
58
64
|
# gets invoked once per object for a #transfer! and once for a remove! Backups run in the
|
59
65
|
# background anyway so even if it were a bit slower it shouldn't matter.
|
60
66
|
def connection
|
61
|
-
Net::SSH.start(ip, username, :password => password, :port => port)
|
67
|
+
Net::SSH.start(ip, username, :password => @password, :port => port)
|
62
68
|
end
|
63
69
|
|
64
70
|
##
|
@@ -66,7 +72,7 @@ module Backup
|
|
66
72
|
def transfer!
|
67
73
|
Logger.message("#{ self.class } started transferring \"#{ remote_file }\".")
|
68
74
|
create_remote_directories!
|
69
|
-
run("#{ utility(:rsync) } #{ options } '#{ File.join(local_path, local_file) }' '#{ username }@#{ ip }:#{ File.join(remote_path, remote_file[20..-1]) }'")
|
75
|
+
run("#{ utility(:rsync) } #{ options } #{ password } '#{ File.join(local_path, local_file) }' '#{ username }@#{ ip }:#{ File.join(remote_path, remote_file[20..-1]) }'")
|
70
76
|
end
|
71
77
|
|
72
78
|
##
|
@@ -94,6 +100,30 @@ module Backup
|
|
94
100
|
"-z --port='#{ port }'"
|
95
101
|
end
|
96
102
|
|
103
|
+
##
|
104
|
+
# Returns Rsync syntax for using a password file
|
105
|
+
def password
|
106
|
+
"--password-file='#{@password_file.path}'" unless @password.nil?
|
107
|
+
end
|
108
|
+
|
109
|
+
##
|
110
|
+
# Writes the provided password to a temporary file so that
|
111
|
+
# the rsync utility can read the password from this file
|
112
|
+
def write_password_file!
|
113
|
+
unless @password.nil?
|
114
|
+
@password_file = Tempfile.new('backup-rsync-password')
|
115
|
+
@password_file.write(@password)
|
116
|
+
@password_file.close
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
##
|
121
|
+
# Removes the previously created @password_file
|
122
|
+
# (temporary file containing the password)
|
123
|
+
def remove_password_file!
|
124
|
+
@password_file.unlink unless @password.nil?
|
125
|
+
end
|
126
|
+
|
97
127
|
end
|
98
128
|
end
|
99
129
|
end
|
data/lib/backup/syncer/rsync.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
+
##
|
4
|
+
# Require the tempfile Ruby library when Backup::Syncer::RSync is loaded
|
5
|
+
require 'tempfile'
|
6
|
+
|
3
7
|
module Backup
|
4
8
|
module Syncer
|
5
9
|
class RSync < Base
|
@@ -52,6 +56,7 @@ module Backup
|
|
52
56
|
@compress ||= false
|
53
57
|
|
54
58
|
instance_eval(&block) if block_given?
|
59
|
+
write_password_file!
|
55
60
|
|
56
61
|
@path = path.sub(/^\~\//, '')
|
57
62
|
end
|
@@ -61,13 +66,17 @@ module Backup
|
|
61
66
|
# debug options: -vhP
|
62
67
|
def perform!
|
63
68
|
Logger.message("#{ self.class } started syncing #{ directories }.")
|
64
|
-
Logger.silent(
|
69
|
+
Logger.silent(
|
70
|
+
run("#{ utility(:rsync) } -vhP #{ options } #{ directories } '#{ username }@#{ ip }:#{ path }'")
|
71
|
+
)
|
72
|
+
|
73
|
+
remove_password_file!
|
65
74
|
end
|
66
75
|
|
67
76
|
##
|
68
77
|
# Returns all the specified Rsync options, concatenated, ready for the CLI
|
69
78
|
def options
|
70
|
-
([archive, mirror, compress, port] + additional_options).compact.join("\s")
|
79
|
+
([archive, mirror, compress, port, password] + additional_options).compact.join("\s")
|
71
80
|
end
|
72
81
|
|
73
82
|
##
|
@@ -94,6 +103,12 @@ module Backup
|
|
94
103
|
"--port='#{@port}'"
|
95
104
|
end
|
96
105
|
|
106
|
+
##
|
107
|
+
# Returns Rsync syntax for setting a password (via a file)
|
108
|
+
def password
|
109
|
+
"--password-file='#{@password_file.path}'" unless @password.nil?
|
110
|
+
end
|
111
|
+
|
97
112
|
##
|
98
113
|
# If no block has been provided, it'll return the array of @directories.
|
99
114
|
# If a block has been provided, it'll evaluate it and add the defined paths to the @directories
|
@@ -112,6 +127,26 @@ module Backup
|
|
112
127
|
@directories << path
|
113
128
|
end
|
114
129
|
|
130
|
+
private
|
131
|
+
|
132
|
+
##
|
133
|
+
# Writes the provided password to a temporary file so that
|
134
|
+
# the rsync utility can read the password from this file
|
135
|
+
def write_password_file!
|
136
|
+
unless @password.nil?
|
137
|
+
@password_file = Tempfile.new('backup-rsync-password')
|
138
|
+
@password_file.write(@password)
|
139
|
+
@password_file.close
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
##
|
144
|
+
# Removes the previously created @password_file
|
145
|
+
# (temporary file containing the password)
|
146
|
+
def remove_password_file!
|
147
|
+
@password_file.unlink unless @password.nil?
|
148
|
+
end
|
149
|
+
|
115
150
|
end
|
116
151
|
end
|
117
152
|
end
|
data/lib/backup/version.rb
CHANGED
@@ -129,6 +129,43 @@ describe Backup::Database::MongoDB do
|
|
129
129
|
db.perform!
|
130
130
|
end
|
131
131
|
|
132
|
+
it 'should lock database before dump if lock mode is enabled' do
|
133
|
+
db.lock = true
|
134
|
+
db.expects(:lock_database)
|
135
|
+
|
136
|
+
db.perform!
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'should not lock database before dump if lock mode is disabled' do
|
140
|
+
db.lock = false
|
141
|
+
db.expects(:lock_database).never
|
142
|
+
|
143
|
+
db.perform!
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'should unlock database after dump if lock mode is enabled' do
|
147
|
+
db.lock = true
|
148
|
+
db.expects(:unlock_database)
|
149
|
+
|
150
|
+
db.perform!
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'should unlock the database if an exception is raised after it was locked' do
|
154
|
+
db.lock = true
|
155
|
+
db.expects(:unlock_database)
|
156
|
+
db.expects(:lock_database).raises(RuntimeError, 'something went wrong')
|
157
|
+
db.expects(:raise)
|
158
|
+
|
159
|
+
db.perform!
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'should not unlock database after dump if lock mode is disabled' do
|
163
|
+
db.lock = false
|
164
|
+
db.expects(:unlock_database).never
|
165
|
+
|
166
|
+
db.perform!
|
167
|
+
end
|
168
|
+
|
132
169
|
it 'should dump only the provided collections' do
|
133
170
|
db.only_collections = %w[users admins profiles]
|
134
171
|
db.expects(:specific_collection_dump!)
|
data/spec/logger_spec.rb
CHANGED
@@ -43,4 +43,16 @@ describe Backup::Logger do
|
|
43
43
|
Backup::Logger.silent "This has been logged."
|
44
44
|
end
|
45
45
|
end
|
46
|
+
|
47
|
+
context 'when quieted' do
|
48
|
+
it do
|
49
|
+
Backup::Logger.send(:const_set, :QUIET, true)
|
50
|
+
Backup::Logger.expects(:puts).never
|
51
|
+
|
52
|
+
Backup::Logger.message "This has been logged."
|
53
|
+
Backup::Logger.error "This has been logged."
|
54
|
+
Backup::Logger.warn "This has been logged."
|
55
|
+
Backup::Logger.normal "This has been logged."
|
56
|
+
end
|
57
|
+
end
|
46
58
|
end
|
data/spec/storage/rsync_spec.rb
CHANGED
@@ -19,11 +19,13 @@ describe Backup::Storage::RSync do
|
|
19
19
|
end
|
20
20
|
|
21
21
|
it 'should have defined the configuration properly' do
|
22
|
-
rsync.username.should
|
23
|
-
rsync.password.should
|
24
|
-
rsync.ip.should
|
25
|
-
rsync.port.should
|
26
|
-
rsync.path.should
|
22
|
+
rsync.username.should == 'my_username'
|
23
|
+
rsync.send(:password).should =~ /backup-rsync-password/
|
24
|
+
rsync.ip.should == '123.45.678.90'
|
25
|
+
rsync.port.should == 22
|
26
|
+
rsync.path.should == 'backups/'
|
27
|
+
|
28
|
+
File.read(rsync.instance_variable_get('@password_file').path).should == 'my_password'
|
27
29
|
end
|
28
30
|
|
29
31
|
it 'should use the defaults if a particular attribute has not been defined' do
|
@@ -38,10 +40,12 @@ describe Backup::Storage::RSync do
|
|
38
40
|
rsync.ip = '123.45.678.90'
|
39
41
|
end
|
40
42
|
|
41
|
-
rsync.username.should
|
42
|
-
rsync.password.should
|
43
|
-
rsync.ip.should
|
44
|
-
rsync.port.should
|
43
|
+
rsync.username.should == 'my_default_username'
|
44
|
+
rsync.send(:password).should =~ /backup-rsync-password/
|
45
|
+
rsync.ip.should == '123.45.678.90'
|
46
|
+
rsync.port.should == 22
|
47
|
+
|
48
|
+
File.read(rsync.instance_variable_get('@password_file').path).should == 'my_password'
|
45
49
|
end
|
46
50
|
|
47
51
|
it 'should have its own defaults' do
|
@@ -72,7 +76,19 @@ describe Backup::Storage::RSync do
|
|
72
76
|
|
73
77
|
rsync.expects(:create_remote_directories!)
|
74
78
|
rsync.expects(:utility).returns('rsync')
|
75
|
-
rsync.expects(:run).with("rsync -z --port='22' '#{ File.join(Backup::TMP_PATH, "#{ Backup::TIME }.#{ Backup::TRIGGER }.tar") }' 'my_username@123.45.678.90:backups/#{ Backup::TRIGGER }/#{ Backup::TRIGGER }.tar'")
|
79
|
+
rsync.expects(:run).with("rsync -z --port='22' --password-file='#{rsync.instance_variable_get('@password_file').path}' '#{ File.join(Backup::TMP_PATH, "#{ Backup::TIME }.#{ Backup::TRIGGER }.tar") }' 'my_username@123.45.678.90:backups/#{ Backup::TRIGGER }/#{ Backup::TRIGGER }.tar'")
|
80
|
+
|
81
|
+
rsync.send(:transfer!)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should not provide the --password-file option' do
|
85
|
+
Backup::Model.new('blah', 'blah') {}
|
86
|
+
file = mock("Backup::Storage::RSync::File")
|
87
|
+
|
88
|
+
rsync.password = nil
|
89
|
+
rsync.expects(:create_remote_directories!)
|
90
|
+
rsync.expects(:utility).returns('rsync')
|
91
|
+
rsync.expects(:run).with("rsync -z --port='22' '#{ File.join(Backup::TMP_PATH, "#{ Backup::TIME }.#{ Backup::TRIGGER }.tar") }' 'my_username@123.45.678.90:backups/#{ Backup::TRIGGER }/#{ Backup::TRIGGER }.tar'")
|
76
92
|
|
77
93
|
rsync.send(:transfer!)
|
78
94
|
end
|
data/spec/syncer/rsync_spec.rb
CHANGED
@@ -28,12 +28,14 @@ describe Backup::Syncer::RSync do
|
|
28
28
|
|
29
29
|
it 'should have defined the configuration properly' do
|
30
30
|
rsync.username.should == 'my_username'
|
31
|
-
rsync.password.should
|
31
|
+
rsync.password.should =~ /backup-rsync-password/
|
32
32
|
rsync.ip.should == '123.45.678.90'
|
33
33
|
rsync.port.should == "--port='22'"
|
34
34
|
rsync.path.should == 'backups/'
|
35
35
|
rsync.mirror.should == "--delete"
|
36
36
|
rsync.compress.should == "--compress"
|
37
|
+
|
38
|
+
File.read(rsync.instance_variable_get('@password_file').path).should == 'my_password'
|
37
39
|
end
|
38
40
|
|
39
41
|
it 'should use the defaults if a particular attribute has not been defined' do
|
@@ -51,11 +53,13 @@ describe Backup::Syncer::RSync do
|
|
51
53
|
end
|
52
54
|
|
53
55
|
rsync.username.should == 'my_default_username'
|
54
|
-
rsync.password.should
|
56
|
+
rsync.password.should =~ /backup-rsync-password/
|
55
57
|
rsync.ip.should == '123.45.678.90'
|
56
58
|
rsync.port.should == "--port='22'"
|
57
59
|
rsync.mirror.should == nil
|
58
60
|
rsync.compress.should == nil
|
61
|
+
|
62
|
+
File.read(rsync.instance_variable_get('@password_file').path).should == 'my_password'
|
59
63
|
end
|
60
64
|
|
61
65
|
it 'should have its own defaults' do
|
@@ -140,7 +144,30 @@ describe Backup::Syncer::RSync do
|
|
140
144
|
|
141
145
|
describe '#options' do
|
142
146
|
it do
|
143
|
-
rsync.options.should == "--archive --delete --compress --port='22'"
|
147
|
+
rsync.options.should == "--archive --delete --compress --port='22' " +
|
148
|
+
"--password-file='#{rsync.instance_variable_get('@password_file').path}'"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
describe '#password' do
|
153
|
+
before do
|
154
|
+
Backup::Logger.stubs(:message)
|
155
|
+
rsync.stubs(:utility).with(:rsync).returns(:rsync)
|
156
|
+
rsync.stubs(:run)
|
157
|
+
end
|
158
|
+
|
159
|
+
it do
|
160
|
+
rsync.password = 'my_password'
|
161
|
+
rsync.expects(:remove_password_file!)
|
162
|
+
|
163
|
+
rsync.perform!
|
164
|
+
end
|
165
|
+
|
166
|
+
it do
|
167
|
+
rsync.password = nil
|
168
|
+
rsync.expects(:remove_password_file!)
|
169
|
+
|
170
|
+
rsync.perform!
|
144
171
|
end
|
145
172
|
end
|
146
173
|
|
@@ -148,7 +175,19 @@ describe Backup::Syncer::RSync do
|
|
148
175
|
it 'should invoke the rsync command to transfer the files and directories' do
|
149
176
|
Backup::Logger.expects(:message).with("Backup::Syncer::RSync started syncing '/some/random/directory' '/another/random/directory'.")
|
150
177
|
rsync.expects(:utility).with(:rsync).returns(:rsync)
|
151
|
-
rsync.expects(:
|
178
|
+
rsync.expects(:remove_password_file!)
|
179
|
+
rsync.expects(:run).with("rsync -vhP --archive --delete --compress --port='22' --password-file='#{rsync.instance_variable_get('@password_file').path}' " +
|
180
|
+
"'/some/random/directory' '/another/random/directory' 'my_username@123.45.678.90:backups/'")
|
181
|
+
rsync.perform!
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'should not pass in the --password-file option' do
|
185
|
+
Backup::Logger.expects(:message).with("Backup::Syncer::RSync started syncing '/some/random/directory' '/another/random/directory'.")
|
186
|
+
rsync.password = nil
|
187
|
+
rsync.expects(:utility).with(:rsync).returns(:rsync)
|
188
|
+
rsync.expects(:remove_password_file!)
|
189
|
+
rsync.expects(:run).with("rsync -vhP --archive --delete --compress --port='22' " +
|
190
|
+
"'/some/random/directory' '/another/random/directory' 'my_username@123.45.678.90:backups/'")
|
152
191
|
rsync.perform!
|
153
192
|
end
|
154
193
|
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: backup
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 3.0.
|
5
|
+
version: 3.0.15
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Michael van Rooijen
|
@@ -10,8 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-
|
14
|
-
default_executable:
|
13
|
+
date: 2011-05-01 00:00:00 Z
|
15
14
|
dependencies:
|
16
15
|
- !ruby/object:Gem::Dependency
|
17
16
|
name: thor
|
@@ -176,7 +175,6 @@ files:
|
|
176
175
|
- spec/syncer/rsync_spec.rb
|
177
176
|
- spec/syncer/s3_spec.rb
|
178
177
|
- spec/version_spec.rb
|
179
|
-
has_rdoc: true
|
180
178
|
homepage: http://rubygems.org/gems/backup
|
181
179
|
licenses: []
|
182
180
|
|
@@ -200,9 +198,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
200
198
|
requirements: []
|
201
199
|
|
202
200
|
rubyforge_project:
|
203
|
-
rubygems_version: 1.
|
201
|
+
rubygems_version: 1.7.2
|
204
202
|
signing_key:
|
205
203
|
specification_version: 3
|
206
204
|
summary: "Backup is a RubyGem (for UNIX-like operating systems: Linux, Mac OSX) that allows you to configure and perform backups in a simple manner using an elegant Ruby DSL. It supports various databases (MySQL, PostgreSQL, MongoDB and Redis), it supports various storage locations (Amazon S3, Rackspace Cloud Files, Dropbox, any remote server through FTP, SFTP, SCP and RSync), it provide Syncers (RSync, S3) for efficient backups, it can archive files and directories, it can cycle backups, it can do incremental backups, it can compress backups, it can encrypt backups (OpenSSL or GPG), it can notify you about successful and/or failed backups (Email, Twitter and Campfire). It is very extensible and easy to add new functionality to. It's easy to use."
|
207
205
|
test_files: []
|
208
206
|
|
207
|
+
has_rdoc:
|