Merge lp:~percona-toolkit-dev/percona-toolkit/pt-online-schema-change--doesnt-honor--ask-pass-1396868 into lp:~percona-toolkit-dev/percona-toolkit/release-2.2.13

Proposed by Frank Cizmich
Status: Merged
Approved by: Daniel Nichter
Approved revision: 614
Merged at revision: 615
Proposed branch: lp:~percona-toolkit-dev/percona-toolkit/pt-online-schema-change--doesnt-honor--ask-pass-1396868
Merge into: lp:~percona-toolkit-dev/percona-toolkit/release-2.2.13
Diff against target: 359 lines (+179/-16)
8 files modified
bin/pt-config-diff (+2/-2)
bin/pt-deadlock-logger (+2/-2)
bin/pt-fk-error-logger (+2/-2)
bin/pt-kill (+2/-2)
bin/pt-online-schema-change (+165/-2)
bin/pt-table-checksum (+2/-2)
bin/pt-upgrade (+2/-2)
lib/Cxn.pm (+2/-2)
To merge this branch: bzr merge lp:~percona-toolkit-dev/percona-toolkit/pt-online-schema-change--doesnt-honor--ask-pass-1396868
Reviewer Review Type Date Requested Status
Daniel Nichter Needs Fixing
Review via email: mp+245162@code.launchpad.net

Description of the change

Cxn for some strange reason did not honor --ask-pass, (since at least 2.2.9) while fat-packed version in tools did.
Fixed Cxn and synced with rest of tools.

Also fixed pt-online-schema problem when pressing ctl+c while being prompted for password.
Terminal would end up in an inconsistent state.
Used Term::ReadKey to restore previous state.

Also made simpler solution to pt-online-schema-change repeated request for password

To post a comment you must log in.
Revision history for this message
Daniel Nichter (daniel-nichter) :
review: Needs Fixing
Revision history for this message
Daniel Nichter (daniel-nichter) :
review: Needs Fixing
614. By Frank Cizmich

used ReadKeyMini. Moved double password logic to Cxn. Removed {ask_pass} from Cxn

Revision history for this message
Frank Cizmich (frank-cizmich) wrote :

- Removed the args{ask_pass} since it's not used. It's the way the module was coded before, which is strange since it doesn't work. So I left it in as a fallback initially just in case it served a purpose. But since it's not used, let's simplify.

- Including ReadKeyMini solved the ctl+c problem by itself. Nice :-)
Called ReadMode explicitly anyway just to ensure it's known to be used within the code.

- Passed double ask-pass handling logic into Cxn, which was how I did it before for pt-osc.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/pt-config-diff'
2--- bin/pt-config-diff 2014-11-11 13:28:27 +0000
3+++ bin/pt-config-diff 2015-01-13 14:19:09 +0000
4@@ -2295,7 +2295,7 @@
5 set => $args{set},
6 NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1,
7 dbh_set => 0,
8- ask_pass => $args{ask_pass},
9+ ask_pass => $o->get('ask-pass'),
10 DSNParser => $dp,
11 is_cluster_node => undef,
12 parent => $args{parent},
13@@ -2311,7 +2311,7 @@
14
15 my $dbh = $self->{dbh};
16 if ( !$dbh || !$dbh->ping() ) {
17- if ( $self->{ask_pass} && !$self->{asked_for_pass} ) {
18+ if ( $self->{ask_pass} && !$self->{asked_for_pass} && !defined $dsn->{p} ) {
19 $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: ");
20 $self->{asked_for_pass} = 1;
21 }
22
23=== modified file 'bin/pt-deadlock-logger'
24--- bin/pt-deadlock-logger 2014-11-11 13:28:27 +0000
25+++ bin/pt-deadlock-logger 2015-01-13 14:19:09 +0000
26@@ -2639,7 +2639,7 @@
27 set => $args{set},
28 NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1,
29 dbh_set => 0,
30- ask_pass => $args{ask_pass},
31+ ask_pass => $o->get('ask-pass'),
32 DSNParser => $dp,
33 is_cluster_node => undef,
34 parent => $args{parent},
35@@ -2655,7 +2655,7 @@
36
37 my $dbh = $self->{dbh};
38 if ( !$dbh || !$dbh->ping() ) {
39- if ( $self->{ask_pass} && !$self->{asked_for_pass} ) {
40+ if ( $self->{ask_pass} && !$self->{asked_for_pass} && !defined $dsn->{p} ) {
41 $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: ");
42 $self->{asked_for_pass} = 1;
43 }
44
45=== modified file 'bin/pt-fk-error-logger'
46--- bin/pt-fk-error-logger 2014-11-11 13:28:27 +0000
47+++ bin/pt-fk-error-logger 2015-01-13 14:19:09 +0000
48@@ -1791,7 +1791,7 @@
49 set => $args{set},
50 NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1,
51 dbh_set => 0,
52- ask_pass => $args{ask_pass},
53+ ask_pass => $o->get('ask-pass'),
54 DSNParser => $dp,
55 is_cluster_node => undef,
56 parent => $args{parent},
57@@ -1807,7 +1807,7 @@
58
59 my $dbh = $self->{dbh};
60 if ( !$dbh || !$dbh->ping() ) {
61- if ( $self->{ask_pass} && !$self->{asked_for_pass} ) {
62+ if ( $self->{ask_pass} && !$self->{asked_for_pass} && !defined $dsn->{p} ) {
63 $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: ");
64 $self->{asked_for_pass} = 1;
65 }
66
67=== modified file 'bin/pt-kill'
68--- bin/pt-kill 2014-11-11 13:28:27 +0000
69+++ bin/pt-kill 2015-01-13 14:19:09 +0000
70@@ -5158,7 +5158,7 @@
71 set => $args{set},
72 NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1,
73 dbh_set => 0,
74- ask_pass => $args{ask_pass},
75+ ask_pass => $o->get('ask-pass'),
76 DSNParser => $dp,
77 is_cluster_node => undef,
78 parent => $args{parent},
79@@ -5174,7 +5174,7 @@
80
81 my $dbh = $self->{dbh};
82 if ( !$dbh || !$dbh->ping() ) {
83- if ( $self->{ask_pass} && !$self->{asked_for_pass} ) {
84+ if ( $self->{ask_pass} && !$self->{asked_for_pass} && !defined $dsn->{p} ) {
85 $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: ");
86 $self->{asked_for_pass} = 1;
87 }
88
89=== modified file 'bin/pt-online-schema-change'
90--- bin/pt-online-schema-change 2014-11-11 13:28:27 +0000
91+++ bin/pt-online-schema-change 2015-01-13 14:19:09 +0000
92@@ -40,6 +40,7 @@
93 HTTP::Micro
94 VersionCheck
95 Percona::XtraDB::Cluster
96+ ReadKeyMini
97 ));
98 }
99
100@@ -3755,7 +3756,7 @@
101 set => $args{set},
102 NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1,
103 dbh_set => 0,
104- ask_pass => $args{ask_pass},
105+ ask_pass => $o->get('ask-pass'),
106 DSNParser => $dp,
107 is_cluster_node => undef,
108 parent => $args{parent},
109@@ -3771,7 +3772,7 @@
110
111 my $dbh = $self->{dbh};
112 if ( !$dbh || !$dbh->ping() ) {
113- if ( $self->{ask_pass} && !$self->{asked_for_pass} ) {
114+ if ( $self->{ask_pass} && !$self->{asked_for_pass} && !defined $dsn->{p} ) {
115 $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: ");
116 $self->{asked_for_pass} = 1;
117 }
118@@ -7758,6 +7759,162 @@
119 # ###########################################################################
120
121 # ###########################################################################
122+# ReadKeyMini package
123+# This package is a copy without comments from the original. The original
124+# with comments and its test file can be found in the Bazaar repository at,
125+# lib/ReadKeyMini.pm
126+# t/lib/ReadKeyMini.t
127+# See https://launchpad.net/percona-toolkit for more information.
128+# ###########################################################################
129+{
130+
131+BEGIN {
132+
133+package ReadKeyMini;
134+BEGIN { $INC{"ReadKeyMini.pm"} ||= 1 }
135+
136+use warnings;
137+use strict;
138+use English qw(-no_match_vars);
139+use constant PTDEBUG => $ENV{PTDEBUG} || 0;
140+
141+use POSIX qw( :termios_h );
142+use Fcntl qw( F_SETFL F_GETFL );
143+
144+use base qw( Exporter );
145+
146+BEGIN {
147+ our @EXPORT_OK = qw( GetTerminalSize ReadMode );
148+ *ReadMode = *Term::ReadKey::ReadMode = \&_ReadMode;
149+ *GetTerminalSize = *Term::ReadKey::GetTerminalSize = \&_GetTerminalSize;
150+}
151+
152+my %modes = (
153+ original => 0,
154+ restore => 0,
155+ normal => 1,
156+ noecho => 2,
157+ cbreak => 3,
158+ raw => 4,
159+ 'ultra-raw' => 5,
160+);
161+
162+{
163+ my $fd_stdin = fileno(STDIN);
164+ my $flags;
165+ unless ( $PerconaTest::DONT_RESTORE_STDIN ) {
166+ $flags = fcntl(STDIN, F_GETFL, 0)
167+ or warn "Error getting STDIN flags with fcntl: $OS_ERROR";
168+ }
169+ my $term = POSIX::Termios->new();
170+ $term->getattr($fd_stdin);
171+ my $oterm = $term->getlflag();
172+ my $echo = ECHO | ECHOK | ICANON;
173+ my $noecho = $oterm & ~$echo;
174+
175+ sub _ReadMode {
176+ my $mode = $modes{ $_[0] };
177+ if ( $mode == $modes{normal} ) {
178+ cooked();
179+ }
180+ elsif ( $mode == $modes{cbreak} || $mode == $modes{noecho} ) {
181+ cbreak( $mode == $modes{noecho} ? $noecho : $oterm );
182+ }
183+ else {
184+ die("ReadMore('$_[0]') not supported");
185+ }
186+ }
187+
188+ sub cbreak {
189+ my ($lflag) = $_[0] || $noecho;
190+ $term->setlflag($lflag);
191+ $term->setcc( VTIME, 1 );
192+ $term->setattr( $fd_stdin, TCSANOW );
193+ }
194+
195+ sub cooked {
196+ $term->setlflag($oterm);
197+ $term->setcc( VTIME, 0 );
198+ $term->setattr( $fd_stdin, TCSANOW );
199+ if ( !$PerconaTest::DONT_RESTORE_STDIN ) {
200+ fcntl(STDIN, F_SETFL, int($flags))
201+ or warn "Error restoring STDIN flags with fcntl: $OS_ERROR";
202+ }
203+ }
204+
205+ END { cooked() }
206+}
207+
208+sub readkey {
209+ my $key = '';
210+ cbreak();
211+ sysread(STDIN, $key, 1);
212+ my $timeout = 0.1;
213+ if ( $key eq "\033" ) {
214+ my $x = '';
215+ STDIN->blocking(0);
216+ sysread(STDIN, $x, 2);
217+ STDIN->blocking(1);
218+ $key .= $x;
219+ redo if $key =~ /\[[0-2](?:[0-9];)?$/
220+ }
221+ cooked();
222+ return $key;
223+}
224+
225+
226+BEGIN {
227+ eval { no warnings; local $^W; require 'sys/ioctl.ph' };
228+ if ( !defined &TIOCGWINSZ ) {
229+ *TIOCGWINSZ = sub () {
230+ $^O eq 'linux' ? 0x005413
231+ : $^O eq 'solaris' ? 0x005468
232+ : 0x40087468;
233+ };
234+ }
235+}
236+
237+sub _GetTerminalSize {
238+ if ( @_ ) {
239+ die "My::Term::ReadKey doesn't implement GetTerminalSize with arguments";
240+ }
241+
242+ my $cols = $ENV{COLUMNS} || 80;
243+ my $rows = $ENV{LINES} || 24;
244+
245+ if ( open( TTY, "+<", "/dev/tty" ) ) { # Got a tty
246+ my $winsize = '';
247+ if ( ioctl( TTY, &TIOCGWINSZ, $winsize ) ) {
248+ ( $rows, $cols, my ( $xpixel, $ypixel ) ) = unpack( 'S4', $winsize );
249+ return ( $cols, $rows, $xpixel, $ypixel );
250+ }
251+ }
252+
253+ if ( $rows = `tput lines 2>/dev/null` ) {
254+ chomp($rows);
255+ chomp($cols = `tput cols`);
256+ }
257+ elsif ( my $stty = `stty -a 2>/dev/null` ) {
258+ ($rows, $cols) = $stty =~ /([0-9]+) rows; ([0-9]+) columns;/;
259+ }
260+ else {
261+ ($cols, $rows) = @ENV{qw( COLUMNS LINES )};
262+ $cols ||= 80;
263+ $rows ||= 24;
264+ }
265+
266+ return ( $cols, $rows );
267+}
268+
269+}
270+
271+1;
272+}
273+# ###########################################################################
274+# End ReadKeyMini package
275+# ###########################################################################
276+
277+# ###########################################################################
278 # This is a combination of modules and programs in one -- a runnable module.
279 # http://www.perl.com/pub/a/2006/07/13/lightning-articles.html?page=last
280 # Or, look it up in the Camel book on pages 642 and 643 in the 3rd edition.
281@@ -10484,6 +10641,12 @@
282 my ( $signal ) = @_;
283 $oktorun = 0; # flag for cleanup tasks
284 print STDERR "# Exiting on SIG$signal.\n";
285+ # restore terminal to normal state in case CTL+C issued while
286+ # asking for password
287+ # https://bugs.launchpad.net/percona-toolkit/+bug/1396870
288+ # note: just including ReadKeyMini seems to solve the bug,
289+ # but lets use it explicitly so we don't forget why we need it
290+ ReadKeyMini::ReadMode 0;
291 exit 1;
292 }
293
294
295=== modified file 'bin/pt-table-checksum'
296--- bin/pt-table-checksum 2014-11-11 13:28:27 +0000
297+++ bin/pt-table-checksum 2015-01-13 14:19:09 +0000
298@@ -3533,7 +3533,7 @@
299 set => $args{set},
300 NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1,
301 dbh_set => 0,
302- ask_pass => $args{ask_pass},
303+ ask_pass => $o->get('ask-pass'),
304 DSNParser => $dp,
305 is_cluster_node => undef,
306 parent => $args{parent},
307@@ -3549,7 +3549,7 @@
308
309 my $dbh = $self->{dbh};
310 if ( !$dbh || !$dbh->ping() ) {
311- if ( $self->{ask_pass} && !$self->{asked_for_pass} ) {
312+ if ( $self->{ask_pass} && !$self->{asked_for_pass} && !defined $dsn->{p} ) {
313 $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: ");
314 $self->{asked_for_pass} = 1;
315 }
316
317=== modified file 'bin/pt-upgrade'
318--- bin/pt-upgrade 2014-11-11 13:28:27 +0000
319+++ bin/pt-upgrade 2015-01-13 14:19:09 +0000
320@@ -2464,7 +2464,7 @@
321 set => $args{set},
322 NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1,
323 dbh_set => 0,
324- ask_pass => $args{ask_pass},
325+ ask_pass => $o->get('ask-pass'),
326 DSNParser => $dp,
327 is_cluster_node => undef,
328 parent => $args{parent},
329@@ -2480,7 +2480,7 @@
330
331 my $dbh = $self->{dbh};
332 if ( !$dbh || !$dbh->ping() ) {
333- if ( $self->{ask_pass} && !$self->{asked_for_pass} ) {
334+ if ( $self->{ask_pass} && !$self->{asked_for_pass} && !defined $dsn->{p} ) {
335 $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: ");
336 $self->{asked_for_pass} = 1;
337 }
338
339=== modified file 'lib/Cxn.pm'
340--- lib/Cxn.pm 2014-11-05 22:21:51 +0000
341+++ lib/Cxn.pm 2015-01-13 14:19:09 +0000
342@@ -108,7 +108,7 @@
343 set => $args{set},
344 NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1,
345 dbh_set => 0,
346- ask_pass => $args{ask_pass},
347+ ask_pass => $o->get('ask-pass'),
348 DSNParser => $dp,
349 is_cluster_node => undef,
350 parent => $args{parent},
351@@ -125,7 +125,7 @@
352 my $dbh = $self->{dbh};
353 if ( !$dbh || !$dbh->ping() ) {
354 # Ask for password once.
355- if ( $self->{ask_pass} && !$self->{asked_for_pass} ) {
356+ if ( $self->{ask_pass} && !$self->{asked_for_pass} && !defined $dsn->{p} ) {
357 $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: ");
358 $self->{asked_for_pass} = 1;
359 }

Subscribers

People subscribed via source and target branches

to all changes: