pxcbackup 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/lib/pxcbackup/application.rb +15 -1
- data/lib/pxcbackup/backup.rb +1 -1
- data/lib/pxcbackup/backupper.rb +54 -76
- data/lib/pxcbackup/command.rb +32 -0
- data/lib/pxcbackup/logger.rb +96 -0
- data/lib/pxcbackup/mysql.rb +4 -1
- data/lib/pxcbackup/remote_repo.rb +7 -5
- data/lib/pxcbackup/repo.rb +1 -1
- data/lib/pxcbackup/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 95db3e154a55db8fe7bd7ea736d2f197a51a7f4f
|
4
|
+
data.tar.gz: 0c8da2018cecf4ee57bb5eb54ed28972a84d713f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2430921b6608a2d59aad06d6ffae4e538a6ba5bceabbe125ae8d8880c929ca4fee29f008de84a4b272cbc935c4f99e5ba0d8e4dc6d004acb99de886e3d7f60bd
|
7
|
+
data.tar.gz: efd83314d29a5c9cb5c21f86fdc0ff33158cc8b8f068f173e31412fc099e0e584fe7deb1f51f563656f901d3392436ecd71a8a7e0ad17c19e63f2368d5b2a3ce
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# PXCBackup
|
2
2
|
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/pxcbackup.svg)](http://badge.fury.io/rb/pxcbackup)
|
4
|
+
|
3
5
|
PXCBackup is a database backup tool meant for [Percona XtraDB Cluster](http://www.percona.com/software/percona-xtradb-cluster) (PXC), although it could also be used on other related systems, like a [MariaDB](https://mariadb.org) [Galera](http://galeracluster.com/products/) cluster using [XtraBackup](http://www.percona.com/software/percona-xtrabackup), for example.
|
4
6
|
|
5
7
|
The `innobackupex` script provided by Percona makes it very easy to create backups, however restoring backups can become quite complicated, since backups might need to be extracted, uncompressed, decrypted, before restoring they need to be prepared, incremental backups need to be applied on top of full backups, indexes might need to be rebuilt for compact backups, etc. Usually, backups need to be restored in stressful emergency situations, where all of these steps can slow you down quite a bit.
|
@@ -2,6 +2,10 @@ require 'optparse'
|
|
2
2
|
require 'time'
|
3
3
|
require 'yaml'
|
4
4
|
|
5
|
+
require 'pxcbackup/backupper'
|
6
|
+
require 'pxcbackup/logger'
|
7
|
+
require 'pxcbackup/version'
|
8
|
+
|
5
9
|
module PXCBackup
|
6
10
|
class Application
|
7
11
|
def initialize(argv)
|
@@ -20,6 +24,7 @@ module PXCBackup
|
|
20
24
|
end
|
21
25
|
|
22
26
|
def run
|
27
|
+
Logger.color_output = ENV['TERM'] && !@options[:no_color]
|
23
28
|
backupper = Backupper.new(@options)
|
24
29
|
|
25
30
|
case @command
|
@@ -46,6 +51,10 @@ module PXCBackup
|
|
46
51
|
opt.separator ''
|
47
52
|
opt.separator 'Options'
|
48
53
|
|
54
|
+
opt.on('--no-color', 'disable color output') do |color_output|
|
55
|
+
@options[:no_color] = true
|
56
|
+
end
|
57
|
+
|
49
58
|
opt.on('-c', '--config', '=CONFIG_FILE', 'config file to use instead of ~/.pxcbackup') do |config_file|
|
50
59
|
@options[:config] = config_file
|
51
60
|
end
|
@@ -71,7 +80,12 @@ module PXCBackup
|
|
71
80
|
end
|
72
81
|
|
73
82
|
opt.on('-v', '--verbose', 'verbose output') do
|
74
|
-
|
83
|
+
Logger.raise_verbosity
|
84
|
+
end
|
85
|
+
|
86
|
+
opt.on('--version', 'print version and exit') do
|
87
|
+
puts "pxcbackup #{VERSION}"
|
88
|
+
exit
|
75
89
|
end
|
76
90
|
|
77
91
|
opt.on('-y', '--yes', 'skip confirmation on backup restore') do
|
data/lib/pxcbackup/backup.rb
CHANGED
data/lib/pxcbackup/backupper.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'fileutils'
|
2
|
-
require 'open3'
|
3
2
|
require 'tmpdir'
|
4
3
|
|
5
4
|
require 'pxcbackup/array'
|
6
5
|
require 'pxcbackup/backup'
|
6
|
+
require 'pxcbackup/command'
|
7
|
+
require 'pxcbackup/logger'
|
7
8
|
require 'pxcbackup/mysql'
|
8
9
|
require 'pxcbackup/path_resolver'
|
9
10
|
require 'pxcbackup/remote_repo'
|
@@ -12,9 +13,10 @@ require 'pxcbackup/repo'
|
|
12
13
|
module PXCBackup
|
13
14
|
class Backupper
|
14
15
|
def initialize(options)
|
15
|
-
@verbose = options[:verbose] || false
|
16
16
|
@threads = options[:threads] || 1
|
17
17
|
@memory = options[:memory] || '100M'
|
18
|
+
|
19
|
+
@defaults_file = options[:defaults_file] || nil
|
18
20
|
@throttle = options[:throttle] || nil
|
19
21
|
@encrypt = options[:encrypt] || nil
|
20
22
|
@encrypt_key = options[:encrypt_key] || nil
|
@@ -78,7 +80,7 @@ module PXCBackup
|
|
78
80
|
|
79
81
|
Dir.mktmpdir('pxcbackup-') do |dir|
|
80
82
|
arguments << dir.shellescape
|
81
|
-
|
83
|
+
Logger.action "Creating backup #{filename}" do
|
82
84
|
innobackupex(arguments, File.join(@local_repo.path, filename))
|
83
85
|
end
|
84
86
|
end
|
@@ -86,7 +88,11 @@ module PXCBackup
|
|
86
88
|
desync_disable
|
87
89
|
rotate(retention)
|
88
90
|
|
89
|
-
|
91
|
+
if @remote_repo
|
92
|
+
Logger.action 'Syncing backups to remote repository' do
|
93
|
+
@remote_repo.sync(@local_repo)
|
94
|
+
end
|
95
|
+
end
|
90
96
|
end
|
91
97
|
|
92
98
|
def restore_backup(time, skip_confirmation = false)
|
@@ -101,7 +107,8 @@ module PXCBackup
|
|
101
107
|
|
102
108
|
full_backup = incremental_backups.shift
|
103
109
|
|
104
|
-
|
110
|
+
Logger.info "[1/#{incremental_backups.size + 1}] Processing #{full_backup.type.to_s} backup from #{full_backup.time}"
|
111
|
+
Logger.increase_indentation
|
105
112
|
with_extracted_backup(full_backup) do |full_backup_path, full_backup_info|
|
106
113
|
raise 'unexpected backup type' unless full_backup_info[:backup_type] == full_backup.type
|
107
114
|
raise 'unexpected start LSN' unless full_backup_info[:from_lsn] == 0
|
@@ -109,22 +116,23 @@ module PXCBackup
|
|
109
116
|
compact = full_backup_info[:compact]
|
110
117
|
|
111
118
|
if full_backup_info[:compress]
|
112
|
-
|
119
|
+
Logger.action 'Decompressing' do
|
113
120
|
innobackupex(['--decompress', full_backup_path.shellescape])
|
114
121
|
end
|
115
122
|
end
|
116
123
|
|
117
124
|
if incremental_backups.any?
|
118
|
-
|
125
|
+
Logger.action "Preparing base backup (LSN #{full_backup_info[:to_lsn]})" do
|
119
126
|
innobackupex(['--apply-log', '--redo-only', full_backup_path.shellescape])
|
120
127
|
end
|
121
128
|
|
122
129
|
current_lsn = full_backup_info[:to_lsn]
|
130
|
+
Logger.decrease_indentation
|
123
131
|
|
124
132
|
index = 2
|
125
133
|
incremental_backups.each do |incremental_backup|
|
126
|
-
|
127
|
-
|
134
|
+
Logger.info "[#{index}/#{incremental_backups.size + 1}] Processing #{incremental_backup.type.to_s} backup from #{incremental_backup.time}"
|
135
|
+
Logger.increase_indentation
|
128
136
|
with_extracted_backup(incremental_backup) do |incremental_backup_path, incremental_backup_info|
|
129
137
|
raise 'unexpected backup type' unless incremental_backup_info[:backup_type] == incremental_backup.type
|
130
138
|
raise 'unexpected start LSN' unless incremental_backup_info[:from_lsn] == current_lsn
|
@@ -132,17 +140,19 @@ module PXCBackup
|
|
132
140
|
compact ||= incremental_backup_info[:compact]
|
133
141
|
|
134
142
|
if incremental_backup_info[:compress]
|
135
|
-
|
143
|
+
Logger.action 'Decompressing' do
|
136
144
|
innobackupex(['--decompress', incremental_backup_path.shellescape])
|
137
145
|
end
|
138
146
|
end
|
139
147
|
|
140
|
-
|
148
|
+
Logger.action "Applying increment (LSN #{incremental_backup_info[:from_lsn]} -> #{incremental_backup_info[:to_lsn]})" do
|
141
149
|
innobackupex(['--apply-log', '--redo-only', full_backup_path.shellescape, "--incremental-dir=#{incremental_backup_path.shellescape}"])
|
142
150
|
end
|
143
151
|
|
144
152
|
current_lsn = incremental_backup_info[:to_lsn]
|
153
|
+
Logger.decrease_indentation
|
145
154
|
end
|
155
|
+
index += 1
|
146
156
|
end
|
147
157
|
end
|
148
158
|
|
@@ -156,12 +166,12 @@ module PXCBackup
|
|
156
166
|
arguments << '--rebuild-indexes'
|
157
167
|
end
|
158
168
|
|
159
|
-
|
169
|
+
Logger.action "#{action}" do
|
160
170
|
arguments << full_backup_path.shellescape
|
161
171
|
innobackupex(arguments)
|
162
172
|
end
|
163
173
|
|
164
|
-
|
174
|
+
Logger.action 'Attempting to restore Galera info' do
|
165
175
|
restore_galera_info(full_backup_path)
|
166
176
|
end
|
167
177
|
|
@@ -194,8 +204,8 @@ module PXCBackup
|
|
194
204
|
raise 'did not confirm restore' unless confirmation == 'yes'
|
195
205
|
end
|
196
206
|
|
197
|
-
|
198
|
-
|
207
|
+
Logger.action 'Stopping MySQL server' do
|
208
|
+
Command.run("#{@which.service.shellescape} mysql stop")
|
199
209
|
end
|
200
210
|
|
201
211
|
stat = File.stat(mysql_datadir)
|
@@ -203,39 +213,33 @@ module PXCBackup
|
|
203
213
|
gid = stat.gid
|
204
214
|
|
205
215
|
mysql_datadir_old = mysql_datadir + '_' + Time.now.strftime('%Y%m%d%H%M%S')
|
206
|
-
|
216
|
+
Logger.action "Moving current datadir to #{mysql_datadir_old}" do
|
207
217
|
File.rename(mysql_datadir, mysql_datadir_old)
|
208
218
|
end
|
209
219
|
|
210
|
-
|
220
|
+
Logger.action "Restoring backup to #{mysql_datadir}" do
|
211
221
|
Dir.mkdir(mysql_datadir)
|
212
222
|
innobackupex(['--move-back', full_backup_path.shellescape])
|
213
223
|
end
|
214
224
|
|
215
|
-
|
225
|
+
Logger.action "Chowning #{mysql_datadir}" do
|
216
226
|
FileUtils.chown_R(uid, gid, mysql_datadir)
|
217
227
|
end
|
218
228
|
|
219
229
|
if @local_repo
|
220
|
-
|
230
|
+
Logger.action "Removing last backup info" do
|
221
231
|
File.delete(File.join(@local_repo.path, 'xtrabackup_checkpoints'))
|
222
232
|
end
|
223
233
|
end
|
224
234
|
|
225
|
-
|
226
|
-
|
235
|
+
Logger.action 'Starting MySQL server' do
|
236
|
+
Command.run("#{@which.service.shellescape} mysql start")
|
227
237
|
end
|
228
238
|
end
|
229
239
|
end
|
230
240
|
|
231
241
|
def list_backups
|
232
|
-
all_backups.each
|
233
|
-
if @verbose
|
234
|
-
puts "#{backup} - #{backup.type.to_s[0..3]} (#{backup.remote? ? 'remote' : 'local'})"
|
235
|
-
else
|
236
|
-
puts backup
|
237
|
-
end
|
238
|
-
end
|
242
|
+
all_backups.each { |backup| puts backup }
|
239
243
|
end
|
240
244
|
|
241
245
|
private
|
@@ -248,61 +252,38 @@ module PXCBackup
|
|
248
252
|
backups.sort
|
249
253
|
end
|
250
254
|
|
251
|
-
def log(text)
|
252
|
-
return unless @verbose
|
253
|
-
previous_stdout = $stdout
|
254
|
-
$stdout = STDOUT
|
255
|
-
puts text if @verbose
|
256
|
-
$stdout = previous_stdout
|
257
|
-
end
|
258
|
-
|
259
|
-
def log_action(text)
|
260
|
-
return yield unless @verbose
|
261
|
-
|
262
|
-
begin
|
263
|
-
print "#{text}... "
|
264
|
-
previous_stdout, previous_stderr = $stdout, $stderr
|
265
|
-
begin
|
266
|
-
$stdout = $stderr = File.new('/dev/null', 'w')
|
267
|
-
t1 = Time.now
|
268
|
-
yield
|
269
|
-
t2 = Time.now
|
270
|
-
ensure
|
271
|
-
$stdout, $stderr = previous_stdout, previous_stderr
|
272
|
-
end
|
273
|
-
rescue => e
|
274
|
-
puts "fail"
|
275
|
-
raise e
|
276
|
-
else
|
277
|
-
puts "done (%.1fs)" % (t2 - t1)
|
278
|
-
end
|
279
|
-
end
|
280
|
-
|
281
255
|
def desync_enable(wait = 60)
|
282
|
-
|
256
|
+
Logger.info 'Setting wsrep_desync=ON'
|
283
257
|
@mysql.set_variable('wsrep_desync', 'ON')
|
284
|
-
|
258
|
+
Logger.action "Waiting for #{wait} seconds" do
|
259
|
+
sleep(wait)
|
260
|
+
end
|
285
261
|
end
|
286
262
|
|
287
263
|
def desync_disable
|
288
|
-
|
289
|
-
|
290
|
-
|
264
|
+
Logger.action 'Waiting until wsrep_local_recv_queue is empty' do
|
265
|
+
sleep(2) until @mysql.get_status('wsrep_local_recv_queue') == '0'
|
266
|
+
end
|
267
|
+
Logger.info 'Setting wsrep_desync=OFF'
|
291
268
|
@mysql.set_variable('wsrep_desync', 'OFF')
|
292
269
|
end
|
293
270
|
|
294
271
|
def rotate(retention)
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
272
|
+
Logger.action 'Checking if we have old backups to remove' do
|
273
|
+
@local_repo.backups.each do |backup|
|
274
|
+
days = (Time.now - backup.time) / 86400
|
275
|
+
break if days < retention && backup.full?
|
276
|
+
Logger.info "Deleting backup from #{backup.time}"
|
277
|
+
backup.delete
|
278
|
+
end
|
301
279
|
end
|
302
280
|
end
|
303
281
|
|
304
282
|
def innobackupex(arguments, output_file = nil)
|
305
283
|
command = @which.innobackupex.shellescape
|
284
|
+
# --defaults-file has to be the first option passed!
|
285
|
+
command << " --defaults-file=#{@defaults_file.shellescape}" if @defaults_file
|
286
|
+
|
306
287
|
arguments += [
|
307
288
|
"--ibbackup=#{@which.xtrabackup.shellescape}",
|
308
289
|
"--parallel=#{@threads}",
|
@@ -315,11 +296,8 @@ module PXCBackup
|
|
315
296
|
|
316
297
|
command << ' ' + arguments.join(' ')
|
317
298
|
command << " > #{output_file.shellescape}" if output_file
|
318
|
-
|
319
|
-
|
320
|
-
end
|
321
|
-
exit_status = $?
|
322
|
-
raise 'something went wrong with innobackupex' unless exit_status.success? && log.lines.to_a.last.match(/: completed OK!$/)
|
299
|
+
result = Command.run(command)
|
300
|
+
raise 'unexpected output from innobackupex' unless result[:stderr].lines.to_a.last.match(/: completed OK!$/)
|
323
301
|
end
|
324
302
|
|
325
303
|
def read_backup_info(file)
|
@@ -359,8 +337,8 @@ module PXCBackup
|
|
359
337
|
when :tar
|
360
338
|
" | #{@which.tar.shellescape} -ixf - -C #{dir.shellescape}"
|
361
339
|
end
|
362
|
-
|
363
|
-
|
340
|
+
Logger.action action do
|
341
|
+
Command.run(command)
|
364
342
|
end
|
365
343
|
|
366
344
|
info = read_backup_info(File.join(dir, 'xtrabackup_checkpoints'))
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
require 'pxcbackup/logger'
|
4
|
+
|
5
|
+
module PXCBackup
|
6
|
+
module Command
|
7
|
+
def self.run(command, ignore_exit_status = false)
|
8
|
+
Logger.debug "# #{command}"
|
9
|
+
captured_stdout = ''
|
10
|
+
captured_stderr = ''
|
11
|
+
Open3.popen3(command) do |stdin, stdout, stderr|
|
12
|
+
stdin.close
|
13
|
+
until stdout.closed? && stderr.closed?
|
14
|
+
sockets = []
|
15
|
+
sockets << stdout unless stdout.closed?
|
16
|
+
sockets << stderr unless stderr.closed?
|
17
|
+
IO.select(sockets).flatten.compact.each do |socket|
|
18
|
+
begin
|
19
|
+
data = socket.readpartial(1024)
|
20
|
+
captured_stdout << data if socket == stdout
|
21
|
+
captured_stderr << data if socket == stderr
|
22
|
+
rescue EOFError
|
23
|
+
socket.close
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
raise 'command "#{command.split.first}" exited with a non-zero status' unless $?.success? || ignore_exception
|
29
|
+
{ :stdout => captured_stdout, :stderr => captured_stderr, :exit_status => $?.exitstatus }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module PXCBackup
|
2
|
+
module Logger
|
3
|
+
@verbosity_level = 0
|
4
|
+
@indentation = 0
|
5
|
+
@color_output = false
|
6
|
+
@partial = false
|
7
|
+
|
8
|
+
def self.raise_verbosity
|
9
|
+
@verbosity_level += 1
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.increase_indentation
|
13
|
+
@indentation += 1
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.decrease_indentation
|
17
|
+
@indentation -= 1
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.color_output=(value)
|
21
|
+
@color_output = value
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.output(message, skip_newline = false)
|
25
|
+
if @partial
|
26
|
+
puts
|
27
|
+
increase_indentation
|
28
|
+
@partial = false
|
29
|
+
end
|
30
|
+
print ' ' * @indentation + message
|
31
|
+
puts unless skip_newline
|
32
|
+
$stdout.flush
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.action_start(message)
|
36
|
+
return unless @verbosity_level >= 1
|
37
|
+
output "#{message}: ", true
|
38
|
+
@partial = true
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.action_end(message)
|
42
|
+
return unless @verbosity_level >= 1
|
43
|
+
if @partial
|
44
|
+
puts message
|
45
|
+
@partial = false
|
46
|
+
else
|
47
|
+
output message
|
48
|
+
decrease_indentation
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.info(message)
|
53
|
+
output message if @verbosity_level >= 1
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.debug(message)
|
57
|
+
output blue(message) if @verbosity_level >= 2
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.action(message)
|
61
|
+
return yield unless @verbosity_level >= 1
|
62
|
+
|
63
|
+
action_start(message)
|
64
|
+
t1 = Time.now
|
65
|
+
begin
|
66
|
+
result = yield
|
67
|
+
rescue => e
|
68
|
+
action_end(red('fail'))
|
69
|
+
raise e
|
70
|
+
end
|
71
|
+
t2 = Time.now
|
72
|
+
action_end(green('done') + ' (%.1fs)' % (t2 - t1))
|
73
|
+
result
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.colorize(text, color_code)
|
77
|
+
@color_output ? "\e[#{color_code}m#{text}\e[0m" : text
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.red(text)
|
81
|
+
colorize(text, 31);
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.green(text)
|
85
|
+
colorize(text, 32)
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.yellow(text)
|
89
|
+
colorize(text, 33);
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.blue(text)
|
93
|
+
colorize(text, 34);
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/lib/pxcbackup/mysql.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'shellwords'
|
2
2
|
|
3
|
+
require 'pxcbackup/command'
|
4
|
+
|
3
5
|
module PXCBackup
|
4
6
|
class MySQL
|
5
7
|
attr_reader :datadir
|
@@ -17,7 +19,8 @@ module PXCBackup
|
|
17
19
|
end
|
18
20
|
|
19
21
|
def exec(query)
|
20
|
-
|
22
|
+
output = Command.run("echo #{query.shellescape} | #{@which.mysql.shellescape} #{auth}", true)
|
23
|
+
lines = output[:stdout].lines.to_a
|
21
24
|
return nil if lines.empty?
|
22
25
|
|
23
26
|
keys = lines.shift.chomp.split("\t")
|
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'shellwords'
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'pxcbackup/backup'
|
4
|
+
require 'pxcbackup/command'
|
5
|
+
require 'pxcbackup/repo'
|
5
6
|
|
6
7
|
module PXCBackup
|
7
8
|
class RemoteRepo < Repo
|
@@ -12,7 +13,8 @@ module PXCBackup
|
|
12
13
|
|
13
14
|
def backups
|
14
15
|
backups = []
|
15
|
-
|
16
|
+
output = Command.run("#{@which.s3cmd.shellescape} ls #{@path.shellescape}")
|
17
|
+
output[:stdout].lines.to_a.each do |line|
|
16
18
|
path = line.chomp.split[3]
|
17
19
|
next unless Backup.regexp.match(path)
|
18
20
|
backups << Backup.new(self, path)
|
@@ -23,12 +25,12 @@ module PXCBackup
|
|
23
25
|
def sync(local_repo)
|
24
26
|
source = File.join(local_repo.path, '/')
|
25
27
|
target = File.join(path, '/')
|
26
|
-
|
28
|
+
Command.run("#{@which.s3cmd.shellescape} sync --no-progress --delete-removed #{source.shellescape} #{target.shellescape}")
|
27
29
|
end
|
28
30
|
|
29
31
|
def delete(backup)
|
30
32
|
verify(backup)
|
31
|
-
|
33
|
+
Command.run("#{@which.s3cmd.shellescape} del #{backup.path.shellescape}")
|
32
34
|
end
|
33
35
|
|
34
36
|
def stream_command(backup)
|
data/lib/pxcbackup/repo.rb
CHANGED
data/lib/pxcbackup/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pxcbackup
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robbert Klarenbeek
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-05-
|
11
|
+
date: 2014-05-10 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Backup tool for Percona XtraDB Cluster
|
14
14
|
email: robbertkl@renbeek.nl
|
@@ -27,6 +27,8 @@ files:
|
|
27
27
|
- lib/pxcbackup/array.rb
|
28
28
|
- lib/pxcbackup/backup.rb
|
29
29
|
- lib/pxcbackup/backupper.rb
|
30
|
+
- lib/pxcbackup/command.rb
|
31
|
+
- lib/pxcbackup/logger.rb
|
30
32
|
- lib/pxcbackup/mysql.rb
|
31
33
|
- lib/pxcbackup/path_resolver.rb
|
32
34
|
- lib/pxcbackup/remote_repo.rb
|