backup 3.1.3 → 3.2.0

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.
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Backup
4
- module Logger
4
+ class Logger
5
5
  class Console
6
6
  class Options
7
7
  ##
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Backup
4
- module Logger
4
+ class Logger
5
5
  class Logfile
6
6
  class Options
7
7
  ##
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Backup
4
- module Logger
4
+ class Logger
5
5
  class Syslog
6
6
  class Options
7
7
  ##
@@ -112,7 +112,7 @@ module Backup
112
112
  ##
113
113
  # Adds a syncer method to the array of syncer
114
114
  # methods to use during the backup process
115
- def sync_with(name, &block)
115
+ def sync_with(name, syncer_id = nil, &block)
116
116
  ##
117
117
  # Warn user of DSL changes
118
118
  case name.to_s
@@ -134,7 +134,7 @@ module Backup
134
134
  EOS
135
135
  name = "Cloud::#{ syncer }"
136
136
  end
137
- @syncers << get_class_from_scope(Syncer, name).new(&block)
137
+ @syncers << get_class_from_scope(Syncer, name).new(syncer_id, &block)
138
138
  end
139
139
 
140
140
  ##
@@ -241,7 +241,7 @@ module Backup
241
241
  rescue Exception => err
242
242
  log!(:failure, err)
243
243
  send_failure_notifications
244
- exit(1) unless err.is_a?(StandardError)
244
+ exit(3) unless err.is_a?(StandardError)
245
245
  end
246
246
 
247
247
  private
@@ -10,101 +10,131 @@ module Backup
10
10
 
11
11
  ##
12
12
  # Mail delivery method to be used by the Mail gem.
13
+ #
13
14
  # Supported methods:
14
15
  #
15
- # `:smtp` [::Mail::SMTP] (default)
16
- # : Settings used only by this method:
17
- # : `address`, `port`, `domain`, `user_name`, `password`
18
- # : `authentication`, `enable_starttls_auto`, `openssl_verify_mode`
16
+ # [:smtp - ::Mail::SMTP (default)]
17
+ # Settings used by this method:
18
+ # {#address}, {#port}, {#domain}, {#user_name}, {#password},
19
+ # {#authentication}, {#encryption}, {#openssl_verify_mode}
19
20
  #
20
- # `:sendmail` [::Mail::Sendmail]
21
- # : Settings used only by this method:
22
- # : `sendmail`, `sendmail_args`
21
+ # [:sendmail - ::Mail::Sendmail]
22
+ # Settings used by this method:
23
+ # {#sendmail}, {#sendmail_args}
23
24
  #
24
- # `:exim` [::Mail::Exim]
25
- # : Settings used only by this method:
26
- # : `exim`, `exim_args`
25
+ # [:exim - ::Mail::Exim]
26
+ # Settings used by this method:
27
+ # {#exim}, {#exim_args}
27
28
  #
28
- # `:file` [::Mail::FileDelivery]
29
- # : Settings used only by this method:
30
- # : `mail_folder`
29
+ # [:file - ::Mail::FileDelivery]
30
+ # Settings used by this method:
31
+ # {#mail_folder}
31
32
  #
32
33
  attr_accessor :delivery_method
33
34
 
34
35
  ##
35
- # Sender and Receiver email addresses
36
- # Examples:
37
- # sender - my.email.address@gmail.com
38
- # receiver - your.email.address@gmail.com
39
- attr_accessor :from, :to
36
+ # Sender Email Address
37
+ attr_accessor :from
38
+
39
+ ##
40
+ # Receiver Email Address
41
+ attr_accessor :to
40
42
 
41
43
  ##
42
- # The address to use
43
- # Example: smtp.gmail.com
44
+ # SMTP Server Address
44
45
  attr_accessor :address
45
46
 
46
47
  ##
47
- # The port to connect to
48
- # Example: 587
48
+ # SMTP Server Port
49
49
  attr_accessor :port
50
50
 
51
51
  ##
52
52
  # Your domain (if applicable)
53
- # Example: mydomain.com
54
53
  attr_accessor :domain
55
54
 
56
55
  ##
57
- # Username and Password (sender email's credentials)
58
- # Examples:
59
- # user_name - meskyanichi
60
- # password - my_secret_password
61
- attr_accessor :user_name, :password
56
+ # SMTP Server Username (sender email's credentials)
57
+ attr_accessor :user_name
58
+
59
+ ##
60
+ # SMTP Server Password (sender email's credentials)
61
+ attr_accessor :password
62
62
 
63
63
  ##
64
64
  # Authentication type
65
- # Example: plain
65
+ #
66
+ # Acceptable values: +:plain+, +:login+, +:cram_md5+
66
67
  attr_accessor :authentication
67
68
 
68
69
  ##
69
- # Automatically set TLS
70
- # Example: true
71
- attr_accessor :enable_starttls_auto
70
+ # Set the method of encryption to be used for the +SMTP+ connection.
71
+ #
72
+ # [:none (default)]
73
+ # No encryption will be used.
74
+ #
75
+ # [:starttls]
76
+ # Use +STARTTLS+ to upgrade the connection to a +SSL/TLS+ connection.
77
+ #
78
+ # [:tls or :ssl]
79
+ # Use a +SSL/TLS+ connection.
80
+ attr_accessor :encryption
81
+
82
+ attr_deprecate :enable_starttls_auto, :version => '3.2.0',
83
+ :message => "Use #encryption instead.\n" +
84
+ 'e.g. mail.encryption = :starttls',
85
+ :action => lambda {|klass, val|
86
+ klass.encryption = val ? :starttls : :none
87
+ }
72
88
 
73
89
  ##
74
90
  # OpenSSL Verify Mode
75
- # Example: none - Only use this option for a self-signed and/or wildcard certificate
91
+ #
92
+ # Valid modes: +:none+, +:peer+, +:client_once+, +:fail_if_no_peer_cert+
93
+ # See +OpenSSL::SSL+ for details.
94
+ #
95
+ # Use +:none+ for a self-signed and/or wildcard certificate
76
96
  attr_accessor :openssl_verify_mode
77
97
 
78
98
  ##
99
+ # Path to `sendmail` (if needed)
100
+ #
79
101
  # When using the `:sendmail` `delivery_method` option,
80
- # this may be used to specify the absolute path to `sendmail` (if needed)
102
+ # this may be used to specify the absolute path to `sendmail`
103
+ #
81
104
  # Example: '/usr/sbin/sendmail'
82
105
  attr_accessor :sendmail
83
106
 
84
107
  ##
85
108
  # Optional arguments to pass to `sendmail`
109
+ #
86
110
  # Note that this will override the defaults set by the Mail gem (currently: '-i -t')
87
111
  # So, if set here, be sure to set all the arguments you require.
112
+ #
88
113
  # Example: '-i -t -X/tmp/traffic.log'
89
114
  attr_accessor :sendmail_args
90
115
 
91
116
  ##
117
+ # Path to `exim` (if needed)
118
+ #
92
119
  # When using the `:exim` `delivery_method` option,
93
- # this may be used to specify the absolute path to `exim` (if needed)
120
+ # this may be used to specify the absolute path to `exim`
121
+ #
94
122
  # Example: '/usr/sbin/exim'
95
123
  attr_accessor :exim
96
124
 
97
125
  ##
98
126
  # Optional arguments to pass to `exim`
127
+ #
99
128
  # Note that this will override the defaults set by the Mail gem (currently: '-i -t')
100
129
  # So, if set here, be sure to set all the arguments you require.
130
+ #
101
131
  # Example: '-i -t -X/tmp/traffic.log'
102
132
  attr_accessor :exim_args
103
133
 
104
134
  ##
105
135
  # Folder where mail will be kept when using the `:file` `delivery_method` option.
136
+ #
106
137
  # Default location is '$HOME/Backup/emails'
107
- # Example: '/tmp/test-mails'
108
138
  attr_accessor :mail_folder
109
139
 
110
140
  def initialize(model, &block)
@@ -117,22 +147,23 @@ module Backup
117
147
 
118
148
  ##
119
149
  # Notify the user of the backup operation results.
150
+ #
120
151
  # `status` indicates one of the following:
121
152
  #
122
- # `:success`
123
- # : The backup completed successfully.
124
- # : Notification will be sent if `on_success` was set to `true`
153
+ # [:success]
154
+ # The backup completed successfully.
155
+ # Notification will be sent if `on_success` was set to `true`
125
156
  #
126
- # `:warning`
127
- # : The backup completed successfully, but warnings were logged
128
- # : Notification will be sent, including a copy of the current
129
- # : backup log, if `on_warning` was set to `true`
157
+ # [:warning]
158
+ # The backup completed successfully, but warnings were logged
159
+ # Notification will be sent, including a copy of the current
160
+ # backup log, if `on_warning` was set to `true`
130
161
  #
131
- # `:failure`
132
- # : The backup operation failed.
133
- # : Notification will be sent, including the Exception which caused
134
- # : the failure, the Exception's backtrace, a copy of the current
135
- # : backup log and other information if `on_failure` was set to `true`
162
+ # [:failure]
163
+ # The backup operation failed.
164
+ # Notification will be sent, including the Exception which caused
165
+ # the failure, the Exception's backtrace, a copy of the current
166
+ # backup log and other information if `on_failure` was set to `true`
136
167
  #
137
168
  def notify!(status)
138
169
  name, send_log =
@@ -173,8 +204,11 @@ module Backup
173
204
  :user_name => @user_name,
174
205
  :password => @password,
175
206
  :authentication => @authentication,
176
- :enable_starttls_auto => @enable_starttls_auto,
177
- :openssl_verify_mode => @openssl_verify_mode }
207
+ :enable_starttls_auto => @encryption == :starttls,
208
+ :openssl_verify_mode => @openssl_verify_mode,
209
+ :ssl => @encryption == :ssl,
210
+ :tls => @encryption == :tls
211
+ }
178
212
  when 'sendmail'
179
213
  opts = {}
180
214
  opts.merge!(:location => File.expand_path(@sendmail)) if @sendmail
@@ -11,23 +11,19 @@ module Backup
11
11
  attr_accessor :keep
12
12
 
13
13
  ##
14
- # (Optional)
15
14
  # User-defined string used to uniquely identify multiple storages of the
16
- # same type. This will be appended to the YAML storage file used for
17
- # cycling backups.
18
- attr_accessor :storage_id
15
+ # same type. If multiple storages of the same type are added to a single
16
+ # backup model, then this identifier must be set. This will be appended
17
+ # to the YAML storage file used for cycling backups.
18
+ attr_reader :storage_id
19
19
 
20
- ##
21
- # Creates a new instance of the storage object
22
- # * Called with super(model, storage_id) from each subclass
23
20
  def initialize(model, storage_id = nil)
24
- load_defaults!
25
21
  @model = model
26
22
  @storage_id = storage_id
23
+
24
+ load_defaults!
27
25
  end
28
26
 
29
- ##
30
- # Performs the backup transfer
31
27
  def perform!
32
28
  @package = @model.package
33
29
  transfer!
@@ -50,8 +46,8 @@ module Backup
50
46
  ##
51
47
  # Return the storage name, with optional storage_id
52
48
  def storage_name
53
- self.class.to_s.sub('Backup::', '') +
54
- (storage_id ? " (#{storage_id})" : '')
49
+ @storage_name ||= self.class.to_s.sub('Backup::', '') +
50
+ (storage_id ? " (#{ storage_id })" : '')
55
51
  end
56
52
 
57
53
  ##
@@ -71,9 +67,9 @@ module Backup
71
67
  ##
72
68
  # Yields two arguments to the given block: "local_file, remote_file"
73
69
  # The local_file is the full file name:
74
- # e.g. "2011.08.30.11.00.02.backup.tar.enc"
70
+ # e.g. "2011.08.30.11.00.02.trigger.tar.enc"
75
71
  # The remote_file is the full file name, minus the timestamp:
76
- # e.g. "backup.tar.enc"
72
+ # e.g. "trigger.tar.enc"
77
73
  def files_to_transfer_for(package)
78
74
  package.filenames.each do |filename|
79
75
  yield filename, filename[20..-1]
@@ -1,149 +1,289 @@
1
1
  # encoding: utf-8
2
2
 
3
- ##
4
- # Only load the Net::SSH library when the Backup::Storage::RSync class is loaded
5
- Backup::Dependency.load('net-ssh')
6
-
7
3
  module Backup
8
4
  module Storage
9
5
  class RSync < Base
10
6
  include Backup::Utilities::Helpers
11
7
 
12
8
  ##
13
- # Server credentials
14
- attr_accessor :username, :password
9
+ # Mode of operation
10
+ #
11
+ # [:ssh (default)]
12
+ # Connects to the remote via SSH.
13
+ # Does not use an rsync daemon on the remote.
14
+ #
15
+ # [:ssh_daemon]
16
+ # Connects to the remote via SSH.
17
+ # Spawns a single-use daemon on the remote, which allows certain
18
+ # daemon features (like modules) to be used.
19
+ #
20
+ # [:rsync_daemon]
21
+ # Connects directly to an rsync daemon via TCP.
22
+ # Data transferred is not encrypted.
23
+ #
24
+ attr_accessor :mode
15
25
 
16
26
  ##
17
- # Server IP Address and SSH port
18
- attr_accessor :ip, :port
27
+ # Server Address
28
+ #
29
+ # If not specified, the storage operation will be local.
30
+ attr_accessor :host
19
31
 
20
32
  ##
21
- # Path to store backups to
22
- attr_accessor :path
33
+ # SSH or RSync port
34
+ #
35
+ # For `:ssh` or `:ssh_daemon` mode, this specifies the SSH port to use
36
+ # and defaults to 22.
37
+ #
38
+ # For `:rsync_daemon` mode, this specifies the TCP port to use
39
+ # and defaults to 873.
40
+ attr_accessor :port
23
41
 
24
42
  ##
25
- # Flag to use local backups
26
- attr_accessor :local
43
+ # SSH User
44
+ #
45
+ # If the user running the backup is not the same user that needs to
46
+ # authenticate with the remote server, specify the user here.
47
+ #
48
+ # The user must have SSH keys setup for passphrase-less access to the
49
+ # remote. If the SSH User does not have passphrase-less keys, or no
50
+ # default keys in their `~/.ssh` directory, you will need to use the
51
+ # `-i` option in `:additional_ssh_options` to specify the
52
+ # passphrase-less key to use.
53
+ #
54
+ # Used only for `:ssh` and `:ssh_daemon` modes.
55
+ attr_accessor :ssh_user
27
56
 
28
57
  ##
29
- # Creates a new instance of the storage object
30
- def initialize(model, storage_id = nil, &block)
31
- super(model, storage_id)
58
+ # Additional SSH Options
59
+ #
60
+ # Used to supply a String or Array of options to be passed to the SSH
61
+ # command in `:ssh` and `:ssh_daemon` modes.
62
+ #
63
+ # For example, if you need to supply a specific SSH key for the `ssh_user`,
64
+ # you would set this to: "-i '/path/to/id_rsa'". Which would produce:
65
+ #
66
+ # rsync -e "ssh -p 22 -i '/path/to/id_rsa'"
67
+ #
68
+ # Arguments may be single-quoted, but should not contain any double-quotes.
69
+ #
70
+ # Used only for `:ssh` and `:ssh_daemon` modes.
71
+ attr_accessor :additional_ssh_options
32
72
 
33
- @port ||= 22
34
- @path ||= 'backups'
35
- @local ||= false
73
+ ##
74
+ # RSync User
75
+ #
76
+ # If the user running the backup is not the same user that needs to
77
+ # authenticate with the rsync daemon, specify the user here.
78
+ #
79
+ # Used only for `:ssh_daemon` and `:rsync_daemon` modes.
80
+ attr_accessor :rsync_user
36
81
 
37
- instance_eval(&block) if block_given?
82
+ ##
83
+ # RSync Password
84
+ #
85
+ # If specified, Backup will write the password to a temporary file and
86
+ # use it with rsync's `--password-file` option for daemon authentication.
87
+ #
88
+ # Note that setting this will override `rsync_password_file`.
89
+ #
90
+ # Used only for `:ssh_daemon` and `:rsync_daemon` modes.
91
+ attr_accessor :rsync_password
38
92
 
39
- @path = path.sub(/^\~\//, '')
40
- end
93
+ ##
94
+ # RSync Password File
95
+ #
96
+ # If specified, this path will be passed to rsync's `--password-file`
97
+ # option for daemon authentication.
98
+ #
99
+ # Used only for `:ssh_daemon` and `:rsync_daemon` modes.
100
+ attr_accessor :rsync_password_file
41
101
 
42
- private
102
+ ##
103
+ # Additional String or Array of options for the rsync cli
104
+ attr_accessor :additional_rsync_options
43
105
 
44
106
  ##
45
- # This is the remote path to where the backup files will be stored
46
- #
47
- # Note: This overrides the superclass' method
48
- def remote_path_for(package)
49
- File.join(path, package.trigger)
50
- end
107
+ # Flag for compressing (only compresses for the transfer)
108
+ attr_accessor :compress
51
109
 
52
110
  ##
53
- # Establishes a connection to the remote server
54
- def connection
55
- Net::SSH.start(
56
- ip, username, :password => password, :port => port
57
- ) {|ssh| yield ssh }
111
+ # Path to store the synced backup package file(s) to.
112
+ #
113
+ # If no +host+ is specified, then +path+ will be local, and the only
114
+ # other used option would be +additional_rsync_options+.
115
+ # +path+ will be expanded, so '~/my_path' will expand to '$HOME/my_path'.
116
+ #
117
+ # If a +host+ is specified, this will be a path on the host.
118
+ # If +mode+ is `:ssh` (default), then any relative path, or path starting
119
+ # with '~/' will be relative to the directory the ssh_user is logged
120
+ # into. For `:ssh_daemon` or `:rsync_daemon` modes, this would reference
121
+ # an rsync module/path.
122
+ #
123
+ # In :ssh_daemon and :rsync_daemon modes, the files will be stored
124
+ # directly to the +path+ given. The path (or path defined by your rsync
125
+ # module) must already exist.
126
+ # Note that no additional `<trigger>` directory will be added to this path.
127
+ #
128
+ # In :ssh mode or local operation (no +host+ specified), the actual
129
+ # destination path will be `<path>/<trigger>/`. This path will be created
130
+ # if needed - either locally, or on the remote for :ssh mode.
131
+ # This behavior will change in v4.0, when :ssh mode and local operations
132
+ # will also store the files directly in the +path+ given.
133
+ attr_accessor :path
134
+
135
+ def initialize(model, storage_id = nil, &block)
136
+ super
137
+ instance_eval(&block) if block_given?
138
+
139
+ @mode ||= :ssh
140
+ @port ||= mode == :rsync_daemon ? 873 : 22
141
+ @compress ||= false
142
+ @path ||= '~/backups'
58
143
  end
59
144
 
60
- ##
61
- # Transfers the archived file to the specified remote server
62
- def transfer!
63
- write_password_file! unless local
145
+ private
64
146
 
65
- remote_path = remote_path_for(@package)
147
+ def transfer!
148
+ Logger.info "#{ storage_name } Started..."
66
149
 
67
- create_remote_path!(remote_path)
150
+ write_password_file!
151
+ create_dest_path!
68
152
 
69
153
  files_to_transfer_for(@package) do |local_file, remote_file|
70
- if local
71
- Logger.info "#{storage_name} started transferring " +
72
- "'#{ local_file }' to '#{ remote_path }'."
73
- run(
74
- "#{ utility(:rsync) } '#{ File.join(local_path, local_file) }' " +
75
- "'#{ File.join(remote_path, remote_file) }'"
76
- )
77
- else
78
- Logger.info "#{storage_name} started transferring " +
79
- "'#{ local_file }' to '#{ ip }'."
80
- run(
81
- "#{ utility(:rsync) } #{ rsync_options } #{ rsync_port } " +
82
- "#{ rsync_password_file } '#{ File.join(local_path, local_file) }' " +
83
- "'#{ username }@#{ ip }:#{ File.join(remote_path, remote_file) }'"
84
- )
85
- end
154
+ src = "'#{ File.join(local_path, local_file) }'"
155
+ dest = "#{ host_options }'#{ File.join(dest_path, remote_file) }'"
156
+ Logger.info "Syncing to #{ dest }..."
157
+ run("#{ rsync_command } #{ src } #{ dest }")
86
158
  end
87
159
 
160
+ Logger.info "#{ storage_name } Finished!"
88
161
  ensure
89
- remove_password_file! unless local
162
+ remove_password_file!
90
163
  end
91
164
 
92
165
  ##
93
- # Note: Storage::RSync doesn't cycle
94
- def remove!; end
166
+ # Storage::RSync doesn't cycle
167
+ def cycle!; end
95
168
 
96
169
  ##
97
- # Creates (if they don't exist yet) all the directories on the remote
98
- # server in order to upload the backup file.
99
- def create_remote_path!(remote_path)
100
- if @local
101
- FileUtils.mkdir_p(remote_path)
102
- else
103
- connection do |ssh|
104
- ssh.exec!("mkdir -p '#{ remote_path }'")
170
+ # Other storages use #remote_path_for to set the dest_path,
171
+ # which adds an additional timestamp directory to the path.
172
+ # This is not desired here, since we need to transfer the package files
173
+ # to the same location each time.
174
+ #
175
+ # Note: In v4.0, the additional trigger directory will to be dropped
176
+ # from dest_path for both local and :ssh mode, so the package files will
177
+ # be stored directly in #path.
178
+ def dest_path
179
+ @dest_path ||= begin
180
+ if host
181
+ if mode == :ssh
182
+ File.join(path.sub(/^~\//, ''), @package.trigger)
183
+ else
184
+ path.sub(/^~\//, '').sub(/\/$/, '')
185
+ end
186
+ else
187
+ File.join(File.expand_path(path), @package.trigger)
105
188
  end
106
189
  end
107
190
  end
108
191
 
109
192
  ##
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
193
+ # Runs a 'mkdir -p' command on the host (or locally) to ensure the
194
+ # dest_path exists. This is used because we're transferring a single
195
+ # file, and rsync won't attempt to create the intermediate directories.
196
+ #
197
+ # This is only applicable locally and in :ssh mode.
198
+ # In :ssh_daemon and :rsync_daemon modes the `path` would include a
199
+ # module name that must define a path on the remote that already exists.
200
+ def create_dest_path!
201
+ if host
202
+ run("#{ utility(:ssh) } #{ ssh_transport_args } #{ host } " +
203
+ %Q["mkdir -p '#{ dest_path }'"]) if mode == :ssh
204
+ else
205
+ FileUtils.mkdir_p dest_path
117
206
  end
118
207
  end
119
208
 
120
- ##
121
- # Removes the previously created @password_file
122
- # (temporary file containing the password)
123
- def remove_password_file!
124
- @password_file.delete if @password_file
125
- @password_file = nil
209
+ def host_options
210
+ @host_options ||= begin
211
+ if !host
212
+ ''
213
+ elsif mode == :ssh
214
+ "#{ host }:"
215
+ else
216
+ user = "#{ rsync_user }@" if rsync_user
217
+ "#{ user }#{ host }::"
218
+ end
219
+ end
126
220
  end
127
221
 
128
- ##
129
- # Returns Rsync syntax for using a password file
130
- def rsync_password_file
131
- "--password-file='#{@password_file.path}'" if @password_file
222
+ def rsync_command
223
+ @rsync_command ||= begin
224
+ cmd = utility(:rsync) << ' --archive' <<
225
+ " #{ Array(additional_rsync_options).join(' ') }".rstrip
226
+ cmd << compress_option << password_option << transport_options if host
227
+ cmd
228
+ end
132
229
  end
133
230
 
134
- ##
135
- # Returns Rsync syntax for defining a port to connect to
136
- def rsync_port
137
- "-e 'ssh -p #{port}'"
231
+ def compress_option
232
+ compress ? ' --compress' : ''
138
233
  end
139
234
 
140
- ##
141
- # RSync options
142
- # -z = Compresses the bytes that will be transferred to reduce bandwidth usage
143
- def rsync_options
144
- "-z"
235
+ def password_option
236
+ return '' if mode == :ssh
237
+
238
+ path = @password_file ? @password_file.path : rsync_password_file
239
+ path ? " --password-file='#{ File.expand_path(path) }'" : ''
240
+ end
241
+
242
+ def transport_options
243
+ if mode == :rsync_daemon
244
+ " --port #{ port }"
245
+ else
246
+ %Q[ -e "#{ utility(:ssh) } #{ ssh_transport_args }"]
247
+ end
248
+ end
249
+
250
+ def ssh_transport_args
251
+ args = "-p #{ port } "
252
+ args << "-l #{ ssh_user } " if ssh_user
253
+ args << Array(additional_ssh_options).join(' ')
254
+ args.rstrip
255
+ end
256
+
257
+ def write_password_file!
258
+ return unless host && rsync_password && mode != :ssh
259
+
260
+ @password_file = Tempfile.new('backup-rsync-password')
261
+ @password_file.write(rsync_password)
262
+ @password_file.close
145
263
  end
146
264
 
265
+ def remove_password_file!
266
+ @password_file.delete if @password_file
267
+ end
268
+
269
+ attr_deprecate :local, :version => '3.2.0',
270
+ :message => "If 'host' is not set, the operation will be local."
271
+
272
+ attr_deprecate :username, :version => '3.2.0',
273
+ :message => 'Use #ssh_user instead.',
274
+ :action => lambda {|klass, val|
275
+ klass.ssh_user = val
276
+ }
277
+ attr_deprecate :password, :version => '3.2.0',
278
+ :message => 'Use #rsync_password instead.',
279
+ :action => lambda {|klass, val|
280
+ klass.rsync_password = val
281
+ }
282
+ attr_deprecate :ip, :version => '3.2.0',
283
+ :message => 'Use #host instead.',
284
+ :action => lambda {|klass, val|
285
+ klass.host = val
286
+ }
147
287
  end
148
288
  end
149
289
  end