Merge lp:~gl-az/percona-xtrabackup/BT23557-2.1-lp1160778 into lp:percona-xtrabackup/2.1

Proposed by George Ormond Lorch III
Status: Merged
Approved by: Alexey Kopytov
Approved revision: no longer in the source branch.
Merged at revision: 649
Proposed branch: lp:~gl-az/percona-xtrabackup/BT23557-2.1-lp1160778
Merge into: lp:percona-xtrabackup/2.1
Diff against target: 420 lines (+152/-144)
5 files modified
innobackupex (+136/-118)
test/t/xb_compress_encrypt.sh (+3/-7)
test/t/xb_encrypt.sh (+8/-6)
test/t/xb_parallel_compress_encrypt.sh (+3/-7)
test/t/xb_parallel_encrypt.sh (+2/-6)
To merge this branch: bzr merge lp:~gl-az/percona-xtrabackup/BT23557-2.1-lp1160778
Reviewer Review Type Date Requested Status
Alexey Kopytov (community) Approve
Vlad Lesin (community) g2 Approve
Review via email: mp+174334@code.launchpad.net

This proposal supersedes a proposal from 2013-06-03.

Description of the change

Fix for lp1160778 : non-InnoDB files are not encrypted.

Refactored some innobackupex to make all files not copied/streamed by xtrabackup binary go through one of two common functions. These new functions handle all of the stream/encryption formatting for non-InnoDB files. This also simplifies and normalizes some code in innobackupex that has just been added onto over time.

Encryption test cases have also been fixed and improved. xb_encrypt.sh will now fail if there are any unencrypted files detected within the backup set.

23557

http://jenkins.percona.com/view/XtraBackup/job/percona-xtrabackup-2.1-param/375/
------

Rebased this MP on current trunk and fixed issues pointed out in last MP. Vlad if you could please re-review and think of it as a fresh review because of the re-basing. I only ran into two small conflicts but still I would like another of your great reviews if possible.

To post a comment you must log in.
Revision history for this message
George Ormond Lorch III (gl-az) wrote : Posted in a previous version of this proposal

I wonder though if we should make xtrabackup_checkpoints not encrypted so that incrementals are a little easier. Otherwise users will have to scrape the "The latest check point (for incremental):" from the innobackupex output and store it somewhere.

Revision history for this message
Stewart Smith (stewart) wrote : Posted in a previous version of this proposal

George Ormond Lorch III <email address hidden> writes:
> I wonder though if we should make xtrabackup_checkpoints not encrypted
> so that incrementals are a little easier. Otherwise users will have to
> scrape the "The latest check point (for incremental):" from the
> innobackupex output and store it somewhere.

I think we should keep everything encrypted. history on the server is
the correct way of better supporting incremental encrypted backups.

--
Stewart Smith

Revision history for this message
George Ormond Lorch III (gl-az) wrote : Posted in a previous version of this proposal

This also raises the question of compression...Should we not be
compressing all non-innodb files as well? Which also leads to parallel
compress/encrypt/copy of non-innodb files too...

On 6/6/2013 7:08 PM, Stewart Smith wrote:
> George Ormond Lorch III <email address hidden> writes:
>> I wonder though if we should make xtrabackup_checkpoints not encrypted
>> so that incrementals are a little easier. Otherwise users will have to
>> scrape the "The latest check point (for incremental):" from the
>> innobackupex output and store it somewhere.
> I think we should keep everything encrypted. history on the server is
> the correct way of better supporting incremental encrypted backups.
>

--
George O. Lorch III
Software Engineer, Percona
+1-888-401-3401 x542 US/Arizona (GMT -7)
skype: george.ormond.lorch.iii

Revision history for this message
Vlad Lesin (vlad-lesin) wrote : Posted in a previous version of this proposal

1) Lines 31-45: I see the logic is changed here because files are not copied if $option_rsync is true in the original code because they are copied earlier in backup()->backup_files() call with rsync. innobackupex:429 - backup_files() copies $buffer_pool_file_name with rsync (lines 2234-2241 includes it in copy-list), but innobackupex:450 copies it again in the case of $option_rsync is on. So it looks like double copying.

2) ib_buffer_pool.sh fails with the following message: "ib_buffer_pool.sh: Buffer pool dump has not been restored", but it passes when the changes are reverted.

review: Needs Fixing (g2)
Revision history for this message
Vlad Lesin (vlad-lesin) :
review: Approve (g2)
Revision history for this message
Alexey Kopytov (akopytov) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'innobackupex'
2--- innobackupex 2013-07-08 09:28:05 +0000
3+++ innobackupex 2013-07-12 04:33:27 +0000
4@@ -330,21 +330,7 @@
5
6 mysql_close(\%mysql);
7
8- if ($option_stream) {
9- open XTRABACKUP_BINARY, "> $option_tmpdir/$xtrabackup_binary_file"
10- || die "Cannot open file $option_tmpdir/$xtrabackup_binary_file: $!\n";
11- } else {
12- open XTRABACKUP_BINARY, "> $backup_dir/$xtrabackup_binary_file"
13- || die "Cannot open file $backup_dir/$xtrabackup_binary_file: $!\n";
14- }
15- print XTRABACKUP_BINARY $option_ibbackup_binary;
16- close XTRABACKUP_BINARY;
17-
18- if ($option_stream) {
19- stream_encrypt_file($option_tmpdir, $xtrabackup_binary_file)
20- && die "Failed to stream $xtrabackup_binary_file: $!";
21- unlink "$option_tmpdir/$xtrabackup_binary_file";
22- }
23+ write_to_backup_file("$work_dir/$xtrabackup_binary_file", "$option_ibbackup_binary");
24 }
25
26 $now = current_time();
27@@ -492,18 +478,9 @@
28 # copy ib_lru_dump
29 # Copy buffer poll dump and/or LRU dump
30 foreach my $dump_name ($buffer_pool_filename, 'ib_lru_dump') {
31- if (-e "$orig_datadir/$dump_name") {
32- if ($option_stream) {
33- print STDERR "$prefix Backing up as tar stream '$dump_name'\n";
34- stream_encrypt_file($orig_datadir, "$dump_name")
35- and Die "Failed to stream '$dump_name': $!";
36- } elsif (!$option_rsync) {
37- my $src_name = escape_path("$orig_datadir/$dump_name");
38- my $dst_name = escape_path("$backup_dir/$dump_name");
39- system("$CP_CMD \"$src_name\" \"$dst_name\"")
40- and Die "Failed to copy file '$dump_name': $!";
41- }
42- }
43+ if (!$option_rsync && -e "$orig_datadir/$dump_name") {
44+ backup_file("$orig_datadir", "$dump_name", "$backup_dir/$dump_name")
45+ }
46 }
47
48 print STDERR "\n$prefix Backup created in directory '$backup_dir'\n";
49@@ -1544,16 +1521,8 @@
50 }
51
52 # write binlog info file
53- open(FILE, ">$binlog_info") || Die "Failed to open file '$binlog_info': $!";
54- print FILE "$filename\t$position\t\t$gtid\n";
55- close(FILE);
56-
57- if ($option_stream) {
58- stream_encrypt_file($option_tmpdir, "xtrabackup_binlog_info")
59- and Die "Failed to stream 'xtrabackup_binlog_info': $!";
60- unlink $binlog_info || Die "Failed to delete '$binlog_info': $!";
61- }
62-
63+ write_to_backup_file("$binlog_info", "$filename\t$position\t\t$gtid\n");
64+
65 $mysql_binlog_position = "filename '$filename', position $position";
66 if ($gtid) {
67 $mysql_binlog_position .= ", gtid_executed $gtid";
68@@ -1588,20 +1557,8 @@
69 return;
70 }
71
72-
73- open(FILE, ">$galera_info") ||
74- Die "Failed to open file '$galera_info': $!";
75-
76- print FILE "$state_uuid:$last_committed\n";
77-
78- close(FILE);
79-
80- if ($option_stream) {
81- stream_encrypt_file($option_tmpdir, "xtrabackup_galera_info")
82- and Die "Failed to stream 'xtrabackup_galera_info': $!";
83- unlink $galera_info || Die "Failed to delete '$galera_info': $!";
84- }
85-
86+ write_to_backup_file("$galera_info", "$state_uuid" .
87+ ":" . "$last_committed" . "\n");
88 }
89
90
91@@ -1640,16 +1597,9 @@
92 }
93
94 # print slave status to a file
95- open(FILE, ">$slave_info") || Die "Failed to open file '$slave_info': $!";
96- print FILE "CHANGE MASTER TO MASTER_LOG_FILE='$filename', MASTER_LOG_POS=$position\n";
97- close(FILE);
98-
99- if ($option_stream) {
100- stream_encrypt_file($option_tmpdir, "xtrabackup_slave_info")
101- and Die "Failed to stream 'xtrabackup_slave_info': $!";
102- unlink $slave_info || Die "Failed to delete '$slave_info': $!";
103- }
104-
105+ write_to_backup_file("$slave_info",
106+ "CHANGE MASTER TO MASTER_LOG_FILE='$filename', MASTER_LOG_POS=$position\n");
107+
108 $mysql_slave_position = "master host '$master', filename '$filename', position $position";
109 }
110
111@@ -2094,8 +2044,6 @@
112 sub write_backup_config_file {
113 my $filename = shift;
114
115- open(FILE, "> $filename") || Die "Failed to open file '$filename': $!";
116-
117 my @option_names = (
118 "innodb_data_file_path",
119 "innodb_log_files_in_group",
120@@ -2125,16 +2073,7 @@
121 'innodb_doublewrite_file')))[-1] . "\n";
122 }
123
124- print FILE $options_dump;
125- close(FILE);
126-
127- if ($option_stream) {
128- my $filename_dir = dirname($filename);
129- my $filename_name = basename($filename);
130- stream_encrypt_file($filename_dir, $filename_name)
131- and Die "Failed to stream '$filename_name': $!";
132- unlink $filename || Die "Failed to delete '$filename': $!";
133- }
134+ write_to_backup_file("$filename", "$options_dump");
135 }
136
137
138@@ -2282,17 +2221,18 @@
139 $stream_cmd = 'tar chf -';
140 } elsif ($option_stream eq 'xbstream') {
141 $stream_cmd = 'xbstream -c';
142- if ($option_encrypt) {
143- $encrypt_cmd = "xbcrypt --encrypt-algo=$option_encrypt";
144- if ($option_encrypt_key) {
145- $encrypt_cmd = $encrypt_cmd . " --encrypt-key=$option_encrypt_key";
146- }
147- if ($option_encrypt_key_file) {
148- $encrypt_cmd = $encrypt_cmd . " --encrypt-key-file=$option_encrypt_key_file";
149- }
150- if ($option_encrypt_chunk_size) {
151- $encrypt_cmd = $encrypt_cmd . " --encrypt-chunk-size=$option_encrypt_chunk_size";
152- }
153+ }
154+
155+ if ($option_encrypt) {
156+ $encrypt_cmd = "xbcrypt --encrypt-algo=$option_encrypt";
157+ if ($option_encrypt_key) {
158+ $encrypt_cmd = $encrypt_cmd . " --encrypt-key=$option_encrypt_key";
159+ }
160+ if ($option_encrypt_key_file) {
161+ $encrypt_cmd = $encrypt_cmd . " --encrypt-key-file=$option_encrypt_key_file";
162+ }
163+ if ($option_encrypt_chunk_size) {
164+ $encrypt_cmd = $encrypt_cmd . " --encrypt-chunk-size=$option_encrypt_chunk_size";
165 }
166 }
167
168@@ -2525,30 +2465,8 @@
169 if (!$prep_mode) {
170 $rsync_files_hash{"$database/$file"} = 1;
171 }
172- } elsif (!$option_stream) {
173- $src_name = escape_path("$source_dir/$database/$file");
174- $dst_name = escape_path("$backup_dir/$database");
175- # Copy the file - If we get an error and the file actually exists, die with error msg
176- copy_if_exists("$src_name", "$dst_name")
177- or Die "Failed to copy file '$file': $!";
178 } else {
179- my $ret = 0;
180- my $file_name = substr($file, rindex($file, '/') + 1);
181- $file_name=~s/([\$\\\" ])/\\$1/g;
182- $ret = stream_encrypt_file($source_dir, "$database/$file_name") >> 8;
183- if ($ret == 1 && $option_stream eq 'tar') {
184- print STDERR "$prefix If you use GNU tar, this warning can be ignored.\n";
185- # Check for non-zero exit code
186- } elsif ($ret != 0) {
187- print STDERR "$prefix $stream_cmd returned with exit code $ret.\n";
188- # Only treat as fatal cases where the file exists
189- if ( -e "$database/$file_name" ) {
190- Die "Failed to stream '$database/$file_name': $!";
191- } else {
192- print STDERR "$prefix Ignoring nonexistent file '$database/$file_name'.\n";
193- }
194-
195- }
196+ backup_file("$source_dir", "$database/$file", "$backup_dir/$database/$file")
197 }
198 }
199 }
200@@ -3166,17 +3084,117 @@
201 return $con->{status}->{Slave_open_temp_tables}->{Value};
202 }
203
204-sub stream_encrypt_file {
205- my $basedir = shift;
206- my $relpath = shift;
207- my $rcode;
208-
209- if ($encrypt_cmd) {
210- $rcode = system("cd $basedir; $stream_cmd $relpath | $encrypt_cmd");
211- } else {
212- $rcode = system("cd $basedir; $stream_cmd $relpath");
213- }
214- return $rcode;
215+#
216+# Streams a file into the backup set,
217+# handles any encryption.
218+# Should not be called directly, only meant to be called from backup_file.
219+#
220+sub backup_file_via_stream {
221+ my $src_path = shift;
222+ my $src_file = shift;
223+ my $ret = 0;
224+
225+ my $filepos = rindex($src_file, '/');
226+ my $file_name = '';
227+ my $rel_path = '';
228+
229+ if ($filepos >= 0) {
230+ $file_name = substr($src_file, $filepos + 1);
231+ $rel_path = substr($src_file, 0, $filepos);
232+ } else {
233+ $file_name = $src_file;
234+ $rel_path = '.';
235+ }
236+ $file_name=~s/([\$\\\" ])/\\$1/g;
237+ if ($encrypt_cmd) {
238+ $ret = system("cd $src_path; $stream_cmd $rel_path/$file_name | $encrypt_cmd") >> 8;
239+ } else {
240+ $ret = system("cd $src_path; $stream_cmd $rel_path/$file_name") >> 8;
241+ }
242+
243+ if ($ret == 1 && $option_stream eq 'tar') {
244+ print STDERR "$prefix If you use GNU tar, this warning can be ignored.\n";
245+ # Check for non-zero exit code
246+ } elsif ($ret != 0) {
247+ if ($encrypt_cmd) {
248+ print STDERR "$prefix '$stream_cmd | $encrypt_cmd' returned with exit code $ret.\n";
249+ } else {
250+ print STDERR "$prefix '$stream_cmd' returned with exit code $ret.\n";
251+ }
252+ # Only treat as fatal cases where the file exists
253+ if ( -e "$src_path/$src_file" ) {
254+ Die "Failed to stream '$src_path/$src_file': $ret";
255+ } else {
256+ print STDERR "$prefix Ignoring nonexistent file '$src_path/$src_file'.\n";
257+ }
258+ }
259+}
260+
261+#
262+# Copies a file into the backup set,
263+# handles any encryption.
264+# Should not be called directly, only meant to be called from backup_file.
265+#
266+sub backup_file_via_copy {
267+ my $src_path = shift;
268+ my $src_file = shift;
269+ my $dst_file = shift;
270+ my $ret = 0;
271+
272+ # Copy the file - If we get an error and the file actually exists, die with error msg
273+ my $src_file_esc = escape_path("$src_path/$src_file");
274+ my $dst_file_esc = escape_path("$dst_file");
275+ if ($encrypt_cmd) {
276+ $dst_file_esc = $dst_file_esc . ".xbcrypt";
277+ $ret = system("$encrypt_cmd -i \"$src_file_esc\" -o \"$dst_file_esc\"");
278+ if ($ret != 0) {
279+ Die "Failed to copy and encrypt file '$src_file': $ret";
280+ }
281+ } elsif ( -e "$src_file_esc" ) {
282+ $ret = system("$CP_CMD \"$src_file_esc\" \"$dst_file_esc\"");
283+ if ($ret != 0) {
284+ Die "Failed to copy file '$src_file': $ret";
285+ }
286+ }
287+}
288+
289+#
290+# Copies or streams a file into the backup set,
291+# handles any streaming and/or encryption.
292+# All files to be placed into the backup set should only be put there
293+# through this call, write_backup_to_file ot xtrabackup itself. If any
294+# other method is used, files may not be properly formatted
295+# (stream, encryption, etc).
296+#
297+sub backup_file {
298+ my $src_path = shift;
299+ my $src_file = shift;
300+ my $dst_file = shift;
301+
302+ if ($option_stream) {
303+ backup_file_via_stream($src_path, $src_file);
304+ } else {
305+ backup_file_via_copy($src_path, $src_file, $dst_file);
306+ }
307+}
308+
309+#
310+# Writes data directly into a file within the root of the backup set,
311+# handles any streaming and/or encryption.
312+#
313+sub write_to_backup_file {
314+ my $file_name = shift;
315+ my $write_data = shift;
316+ my $filepos = rindex($file_name, '/');
317+ my $dst_file = substr($file_name, $filepos + 1);
318+ my $dst_path = substr($file_name, 0, $filepos + 1);
319+
320+ open XTRABACKUP_FH, "> $option_tmpdir/$dst_file"
321+ || die "Cannot open file $option_tmpdir/$dst_file: $!\n";
322+ print XTRABACKUP_FH $write_data;
323+ close XTRABACKUP_FH;
324+ backup_file($option_tmpdir, $dst_file, $file_name);
325+ unlink "$option_tmpdir/$dst_file";
326 }
327
328 #
329
330=== modified file 'test/t/xb_compress_encrypt.sh'
331--- test/t/xb_compress_encrypt.sh 2013-03-11 19:11:29 +0000
332+++ test/t/xb_compress_encrypt.sh 2013-07-12 04:33:27 +0000
333@@ -13,14 +13,10 @@
334
335 innobackupex_options="--compress --compress-threads=4 --compress-chunk-size=8K --encrypt=$encrypt_algo --encrypt-key=$encrypt_key --encrypt-threads=4 --encrypt-chunk-size=8K"
336
337-data_decrypt_cmd="for i in *.xbcrypt; do \
338-xbcrypt -d -a $encrypt_algo -k $encrypt_key < \$i > \${i:0:\${#i}-8}; \
339-rm -f \$i; done; \
340-for i in ./sakila/*.xbcrypt; do \
341-xbcrypt -d -a $encrypt_algo -k $encrypt_key < \$i > \${i:0:\${#i}-8}; \
342+data_decrypt_cmd="for i in \`find \\\`pwd\\\` -name \*.xbcrypt\`; do \
343+xbcrypt -d -a $encrypt_algo -k $encrypt_key -i \$i -o \${i:0:\${#i}-8}; \
344 rm -f \$i; done;"
345
346-data_decompress_cmd="for i in *.qp; do qpress -d \$i ./; done; \
347-for i in sakila/*.qp; do qpress -d \$i sakila/; done"
348+data_decompress_cmd="for i in \`find \\\`pwd\\\` -name \*.qp\`; do qpress -d \$i \`dirname \$i\`; done;"
349
350 . inc/xb_local.sh
351
352=== modified file 'test/t/xb_encrypt.sh'
353--- test/t/xb_encrypt.sh 2013-07-09 15:03:03 +0000
354+++ test/t/xb_encrypt.sh 2013-07-12 04:33:27 +0000
355@@ -9,12 +9,14 @@
356 echo -n $encrypt_key > $encrypt_key_file
357
358 innobackupex_options="--encrypt=$encrypt_algo --encrypt-key-file=$encrypt_key_file --encrypt-threads=4 --encrypt-chunk-size=8K"
359-data_decrypt_cmd="for i in *.xbcrypt; do \
360-xbcrypt -d -a $encrypt_algo -f $encrypt_key_file < \$i > \${i:0:\${#i}-8}; \
361-rm -f \$i; done; \
362-for i in ./sakila/*.xbcrypt; do \
363-xbcrypt -d -a $encrypt_algo -f $encrypt_key_file < \$i > \${i:0:\${#i}-8}; \
364-rm -f \$i; done;"
365+data_decrypt_cmd="if [ -n \"\`find \\\`pwd\\\` -type f \! -name \*.xbcrypt\`\" ]; then \
366+echo \"*********************** UNENCRYPTED FILES FOUND ***********************\"; \
367+for i in \`find \\\`pwd\\\` -type f \! -name \*.xbcrypt\`; do \
368+echo \"UNENCRYPTED: \$i\"; done; \
369+else \
370+for i in \`find \\\`pwd\\\` -name \*.xbcrypt\`; do \
371+xbcrypt -d -a $encrypt_algo -f $encrypt_key_file -i \$i -o \${i:0:\${#i}-8}; \
372+rm -f \$i; done; fi"
373
374 . inc/xb_local.sh
375
376
377=== modified file 'test/t/xb_parallel_compress_encrypt.sh'
378--- test/t/xb_parallel_compress_encrypt.sh 2013-03-11 19:11:29 +0000
379+++ test/t/xb_parallel_compress_encrypt.sh 2013-07-12 04:33:27 +0000
380@@ -12,14 +12,10 @@
381
382 innobackupex_options="--parallel=8 --compress --compress-threads=4 --compress-chunk-size=8K --encrypt=$encrypt_algo --encrypt-key=$encrypt_key --encrypt-threads=4 --encrypt-chunk-size=8K"
383
384-data_decrypt_cmd="for i in *.xbcrypt; do \
385-xbcrypt -d -a $encrypt_algo -k $encrypt_key < \$i > \${i:0:\${#i}-8}; \
386-rm -f \$i; done; \
387-for i in ./sakila/*.xbcrypt; do \
388-xbcrypt -d -a $encrypt_algo -k $encrypt_key < \$i > \${i:0:\${#i}-8}; \
389+data_decrypt_cmd="for i in \`find \\\`pwd\\\` -name \*.xbcrypt\`; do \
390+xbcrypt -d -a $encrypt_algo -k $encrypt_key -i \$i -o \${i:0:\${#i}-8}; \
391 rm -f \$i; done;"
392
393-data_decompress_cmd="for i in *.qp; do qpress -d \$i ./; done; \
394-for i in sakila/*.qp; do qpress -d \$i sakila/; done"
395+data_decompress_cmd="for i in \`find \\\`pwd\\\` -name \*.qp\`; do qpress -d \$i \`dirname \$i\`; done;"
396
397 . inc/xb_local.sh
398
399=== modified file 'test/t/xb_parallel_encrypt.sh'
400--- test/t/xb_parallel_encrypt.sh 2013-03-11 19:11:29 +0000
401+++ test/t/xb_parallel_encrypt.sh 2013-07-12 04:33:27 +0000
402@@ -2,16 +2,12 @@
403 # Test basic local parallel backup with encryption
404 ############################################################################
405
406-
407 encrypt_algo="AES256"
408 encrypt_key="percona_xtrabackup_is_awesome___"
409
410 innobackupex_options="--parallel=4 --encrypt=$encrypt_algo --encrypt-key=$encrypt_key --encrypt-threads=4 --encrypt-chunk-size=8K"
411-data_decrypt_cmd="for i in *.xbcrypt; do \
412-xbcrypt -d -a $encrypt_algo -k $encrypt_key < \$i > \${i:0:\${#i}-8}; \
413-rm -f \$i; done; \
414-for i in ./sakila/*.xbcrypt; do \
415-xbcrypt -d -a $encrypt_algo -k $encrypt_key < \$i > \${i:0:\${#i}-8}; \
416+data_decrypt_cmd="for i in \`find \\\`pwd\\\` -name \*.xbcrypt\`; do \
417+xbcrypt -d -a $encrypt_algo -k $encrypt_key -i \$i -o \${i:0:\${#i}-8}; \
418 rm -f \$i; done;"
419
420 . inc/xb_local.sh

Subscribers

People subscribed via source and target branches