Merge lp:~percona-toolkit-dev/percona-toolkit/pt-agent-fixes into lp:~percona-toolkit-dev/percona-toolkit/release-2.2.6

Proposed by Daniel Nichter
Status: Merged
Approved by: Daniel Nichter
Approved revision: 600
Merged at revision: 597
Proposed branch: lp:~percona-toolkit-dev/percona-toolkit/pt-agent-fixes
Merge into: lp:~percona-toolkit-dev/percona-toolkit/release-2.2.6
Diff against target: 719 lines (+254/-147)
4 files modified
bin/pt-agent (+190/-144)
lib/Cxn.pm (+8/-1)
lib/Percona/Agent/Logger.pm (+2/-2)
t/lib/Cxn.t (+54/-0)
To merge this branch: bzr merge lp:~percona-toolkit-dev/percona-toolkit/pt-agent-fixes
Reviewer Review Type Date Requested Status
Daniel Nichter Approve
Review via email: mp+198493@code.launchpad.net
To post a comment you must log in.
600. By Daniel Nichter

Fix typo causing bug 1251726: --uninstall crashes.

Revision history for this message
Daniel Nichter (daniel-nichter) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/pt-agent'
2--- bin/pt-agent 2013-11-08 03:00:56 +0000
3+++ bin/pt-agent 2013-12-11 04:33:49 +0000
4@@ -3691,7 +3691,7 @@
5
6 sub connect {
7 my ( $self, %opts ) = @_;
8- my $dsn = $self->{dsn};
9+ my $dsn = $opts{dsn} || $self->{dsn};
10 my $dp = $self->{DSNParser};
11
12 my $dbh = $self->{dbh};
13@@ -3710,6 +3710,13 @@
14 }
15
16 $dbh = $self->set_dbh($dbh);
17+ if ( $opts{dsn} ) {
18+ $self->{dsn} = $dsn;
19+ $self->{dsn_name} = $dp->as_string($dsn, [qw(h P S)])
20+ || $dp->as_string($dsn, [qw(F)])
21+ || '';
22+
23+ }
24 PTDEBUG && _d($dbh, 'Connected dbh to', $self->{hostname},$self->{dsn_name});
25 return $dbh;
26 }
27@@ -3873,6 +3880,8 @@
28 return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data
29 && !$args{is_char}; # unless is_char is true
30
31+ return $val if $args{is_float};
32+
33 $val =~ s/(['\\])/\\$1/g;
34 return "'$val'";
35 }
36@@ -5092,7 +5101,7 @@
37 sub debug {
38 my $self = shift;
39 return if $self->online_logging;
40- return $self->_log(0, 'DEBUG', 1, @_);
41+ return $self->_log(0, 'DEBUG', @_);
42 }
43
44 sub info {
45@@ -5128,7 +5137,7 @@
46 }
47
48 sub _log {
49- my ($self, $online, $level, $msg, $offline) = @_;
50+ my ($self, $online, $level, $msg) = @_;
51
52 my $ts = ts(time, 1); # 1=UTC
53 my $level_number = level_number($level);
54@@ -5792,6 +5801,7 @@
55 # Optional args
56 my $_oktorun = $args{oktorun} || sub { return $oktorun };
57 my $actions = $args{actions};
58+ my $quiet = $args{quiet};
59
60 # Update these attribs every time the agent is initialized.
61 # Other optional attribs, like versions, are left to the caller.
62@@ -5802,7 +5812,7 @@
63 # Try to create/update the Agent.
64 my $success = 0;
65 while ( $_oktorun->() && $tries-- ) {
66- if ( !$state->{init_action}++ ) {
67+ if ( !$state->{init_action}++ && !$quiet ) {
68 $logger->info($action eq 'put' ? "Updating agent " . $agent->name
69 : "Creating new agent");
70 }
71@@ -5841,7 +5851,7 @@
72 }
73 }
74 elsif ( !$agent_uri ) {
75- $logger->info("No URI for Agent " . $agent->name);
76+ $logger->warning("No URI for Agent " . $agent->name);
77 }
78 else {
79 # The Agent URI will have been returned in the Location header
80@@ -5868,7 +5878,7 @@
81 delete $state->{init_action};
82 delete $state->{too_many_agents};
83
84- if ( $agent && $success ) {
85+ if ( $agent && $success && !$quiet ) {
86 $logger->info("Agent " . $agent->name . " (" . $agent->uuid . ") is ready");
87 }
88
89@@ -5955,7 +5965,7 @@
90 my $entry_links = $args{entry_links}; # for testing
91 my $logger_client = $args{logger_client}; # for testing
92
93- $logger->info('Starting agent');
94+ # $logger->info('Starting agent');
95
96 # Daemonize first so all output goes to the --log.
97 my $daemon = Daemon->new(
98@@ -6126,8 +6136,9 @@
99 # #######################################################################
100 # Main agent loop
101 # #######################################################################
102+ $state->{need_mysql_version} = 1;
103 $state->{first_config} = 1;
104- my $first_config_interval = 60;
105+ my $first_config_interval = 20;
106 $logger->info("Checking silently every $first_config_interval seconds"
107 . " for the first config");
108
109@@ -6136,38 +6147,6 @@
110 my $config;
111 my $services = {};
112 while ( $_oktorun->() ) {
113- check_if_mysql_restarted(
114- Cxn => $cxn,
115- );
116-
117- if ( $state->{need_mysql_version} ) {
118- my $versions = get_versions(
119- Cxn => $cxn,
120- );
121- if ( $versions->{MySQL} ) {
122- $agent->versions($versions);
123- my $updated_agent;
124- ($agent, $updated_agent) = init_agent(
125- agent => $agent,
126- action => 'put',
127- link => $agent->links->{self},
128- client => $client,
129- interval => sub { return; },
130- tries => 1, # optional
131- );
132- if ( $updated_agent ) {
133- $logger->info("Got MySQL versions");
134- save_agent(
135- agent => $agent,
136- lib_dir => $lib_dir,
137- );
138- }
139- else {
140- $state->{need_mysql_version} = 1;
141- }
142- }
143- }
144-
145 ($config, $lib_dir, $new_daemon, $success) = get_config(
146 link => $agent->links->{config},
147 agent => $agent,
148@@ -6185,6 +6164,7 @@
149 delete $state->{first_config};
150 $logger->info('Agent has been configured');
151 }
152+
153 if ( $new_daemon ) {
154 # NOTE: Daemon objects use DESTROY to auto-remove their pid file
155 # when they lose scope (i.e. ref count goes to zero). This
156@@ -6200,6 +6180,60 @@
157 $daemon = $new_daemon;
158 }
159
160+ # Connect to MySQL, then check stuff.
161+ my $o = new OptionParser();
162+ $o->get_specs();
163+ $o->get_opts();
164+ my $dp = $o->DSNParser();
165+ $dp->prop('set-vars', $o->set_vars());
166+ my $dsn = $dp->parse_options($o);
167+ eval {
168+ $cxn->connect(dsn => $dsn);
169+ };
170+ if ( $EVAL_ERROR ) {
171+ $logger->warning("MySQL connection failure: $EVAL_ERROR");
172+ $state->{have_mysql} = 0;
173+ $state->{need_mysql_version} = 1;
174+ }
175+ else {
176+ if ( !$state->{have_mysql} ) {
177+ $logger->info("MySQL connection OK");
178+ }
179+ $state->{have_mysql} = 1;
180+ check_if_mysql_restarted(
181+ dbh => $cxn->dbh,
182+ );
183+ if ( $state->{need_mysql_version} ) {
184+ $logger->debug("Need MySQL version");
185+ my $versions = get_versions(Cxn => $cxn);
186+ if ( $versions->{MySQL} ) {
187+ $agent->versions($versions);
188+ my $updated_agent;
189+ ($agent, $updated_agent) = init_agent(
190+ agent => $agent,
191+ action => 'put',
192+ link => $agent->links->{self},
193+ client => $client,
194+ tries => 1,
195+ interval => sub { return; },
196+ quiet => 1,
197+ );
198+ if ( $updated_agent ) {
199+ $logger->debug("Got MySQL version");
200+ save_agent(
201+ agent => $agent,
202+ lib_dir => $lib_dir,
203+ );
204+ delete $state->{need_mysql_version};
205+ }
206+ }
207+ else {
208+ $logger->debug("Failed to get MySQL version");
209+ }
210+ }
211+ $cxn->dbh->disconnect();
212+ }
213+
214 # Check the safeguards.
215 my ($disk_space, $disk_space_ok);
216 eval {
217@@ -6341,6 +6375,8 @@
218 $config = $new_config;
219 $success = 1;
220 $logger->info('Config ' . $config->ts . ' applied');
221+
222+ $state->{need_mysql_version} = 1;
223 }
224 else {
225 $success = 1;
226@@ -8319,7 +8355,7 @@
227 );
228 }
229 # Match the first digits, which should be the PID.
230- ($pid) =~ $ps_output =~ m/(\d+)/;
231+ ($pid) = $ps_output =~ m/(\d+)/;
232 }
233
234 if ( !$pid ) {
235@@ -8405,6 +8441,7 @@
236
237 my $agent_my_cnf = '/etc/percona/agent/my.cnf';
238 my $config_file = get_config_file();
239+ my $lib_dir = $o->get('lib');
240
241 my $step_result;
242 my $stepno = 0;
243@@ -8414,6 +8451,7 @@
244 "Verify the user is root",
245 "Check Perl module dependencies",
246 "Check for crontab",
247+ "Verify pt-agent is not installed",
248 "Verify the API key",
249 "Connect to MySQL",
250 "Check if MySQL is a slave",
251@@ -8483,7 +8521,25 @@
252 die "cron is not installed, or crontab is not in your PATH.\n";
253 }
254
255+ # Verify pt-agent is not installed
256+ $next_step->();
257+ my @install_files = ($agent_my_cnf, $config_file, "$lib_dir/agent");
258+ my @have_files;
259+ foreach my $file (@install_files) {
260+ push @have_files, $file if -f $file;
261+ }
262+ if ( scalar @have_files ) {
263+ print "FAIL\n";
264+ die "It looks like pt-agent is already installed because these files exist:\n"
265+ . join("\n", map { " $_" } @have_files)
266+ . "\nRun pt-agent --uninstall to remove these files. To upgrade pt-agent, "
267+ . "install the new version, run pt-agent --stop, then pt-agent --daemonize "
268+ . "to restart pt-agent with the new version.\n";
269+ }
270+
271 # Must have a valid API key.
272+ $next_step->();
273+ my $got_api_key = 0;
274 my $api_key = $o->get('api-key');
275 if ( !$api_key ) {
276 print "\n";
277@@ -8497,19 +8553,22 @@
278 $api_key = '';
279 }
280 }
281- $next_step->(repeat => 1); # repeat
282 }
283 else {
284 die "Please specify your --api-key.\n";
285 }
286+ $got_api_key = 1;
287 }
288+
289 my $client;
290 my $entry_links;
291 if ( $flags->{offline} ) {
292 $skip++;
293 }
294 else {
295- $next_step->();
296+ if ($got_api_key) {
297+ $next_step->(repeat => 1);
298+ }
299 eval {
300 ($client, $entry_links) = get_api_client(
301 api_key => $api_key,
302@@ -8571,30 +8630,13 @@
303 if ( $flags->{force_dangerous_slave_install} ) {
304 create_mysql_user($cxn, $agent_my_cnf);
305 }
306- elsif ( $interactive || -t STDIN ) {
307- print "\nMySQL is a slave and $agent_my_cnf does not exist. "
308- . "To install the agent, please enter the MySQL username and "
309- . "password to use. The MySQL user must have SUPER and USAGE "
310- . "privileges on all databases, for example: "
311- . "GRANT SUPER,USAGE ON *.* TO pt_agent'\@'localhost'. "
312- . "If the agent has been installed on the master, you can use "
313- . "the MySQL username and password in $agent_my_cnf on the "
314- . "master. CTRL-C to abort install.\n";
315- print "MySQL username: ";
316- my $user = <STDIN>;
317- chomp($user) if $user;
318- my $pass = OptionParser::prompt_noecho("MySQL password: ");
319- create_mysql_user($cxn, $agent_my_cnf, $user, $pass);
320- $next_step->(repeat => 1); # repeat
321- }
322 else {
323 die "Sorry, cannot install the agent because MySQL is a slave "
324 . "and $agent_my_cnf does not exist. It is not safe to "
325 . "write to a slave, so a MySQL user for the agent cannot "
326 . "be created. First install the agent on the master, then "
327 . "copy $agent_my_cnf from the master to this server. "
328- . "See --install-options for how to force a dangerous slave "
329- . "install.\n";
330+ . "See SLAVE INSTALL in the docs for more information.\n";
331 }
332 }
333 }
334@@ -8616,7 +8658,7 @@
335 # do it now in case there are problems.
336 $next_step->();
337 init_lib_dir(
338- lib_dir => $o->get('lib'),
339+ lib_dir => $lib_dir,
340 );
341 init_spool_dir(
342 spool_dir => $o->get('spool'),
343@@ -8997,33 +9039,7 @@
344 my (%args) = @_;
345 my $cxn = $args{Cxn};
346 my $tries = $args{tries} || 1;
347- my $interval = $args{interval} || sub { sleep 3; };
348-
349- my $have_mysql = 0;
350- if ( $cxn ) {
351- $logger->debug("Connecting to MySQL");
352- foreach my $tryno ( 1..$tries ) {
353- eval {
354- $cxn->connect();
355- };
356- if ( $EVAL_ERROR ) {
357- $logger->debug("Cannot connect to MySQL: $EVAL_ERROR");
358- }
359- else {
360- $have_mysql = 1;
361- delete $state->{need_mysql_version};
362- last; # success
363- }
364- if ( $tryno < $tries ) {
365- sleep $interval; # failure, try again
366- }
367- else {
368- $state->{need_mysql_version} = 1;
369- $logger->warning("Cannot get MySQL version, will try again later");
370- last; # failure
371- }
372- }
373- }
374+ my $interval = $args{interval} || sub { return; };
375
376 # This is currently the actual response from GET v.percona.com
377 my $fake_response = <<EOL;
378@@ -9032,6 +9048,10 @@
379 Perl;perl_version
380 DBD::mysql;perl_module_version
381 Percona::Toolkit;perl_module_version
382+JSON;perl_module_version
383+LWP;perl_module_version
384+IO::Socket::SSL;perl_module_version
385+DBD::mysql;perl_module_version
386 EOL
387
388 my $items = VersionCheck::parse_server_response(
389@@ -9042,12 +9062,39 @@
390 { name => 'system', id => 0, },
391 ];
392
393+ my $have_mysql = -1;
394+ if ( !$cxn->dbh || !$cxn->dbh->ping() ) {
395+ $logger->debug("Connecting to MySQL");
396+ eval {
397+ $cxn->connect();
398+ };
399+ if ( $EVAL_ERROR ) {
400+ $logger->debug("Cannot connect to MySQL: $EVAL_ERROR");
401+ $have_mysql = 0;
402+ }
403+ else {
404+ $have_mysql = 1;
405+ }
406+ }
407+
408 if ( $have_mysql ) {
409+ $logger->debug("Have MySQL connection");
410 my ($name, $id) = VersionCheck::get_instance_id(
411 { dbh => $cxn->dbh, dsn => $cxn->dsn },
412 );
413 push @$instances,
414 { name => $name, id => $id, dbh => $cxn->dbh, dsn => $cxn->dsn };
415+
416+ # Disconnect MySQL if we connected it.
417+ if ( $have_mysql == 1 ) {
418+ $logger->debug("Disconnecting MySQL");
419+ eval {
420+ $cxn->dbh->disconnect();
421+ };
422+ if ( $EVAL_ERROR ) {
423+ $logger->debug($EVAL_ERROR);
424+ }
425+ }
426 }
427
428 my $versions = VersionCheck::get_versions(
429@@ -9112,47 +9159,21 @@
430 sub check_if_mysql_restarted {
431 my (%args) = @_;
432 have_required_args(\%args, qw(
433- Cxn
434+ dbh
435 )) or die;
436- my $cxn = $args{Cxn};
437+ my $dbh = $args{dbh};
438
439 # Optional args
440 my $uptime = $args{uptime}; # for testing
441 my $margin = $args{margin} || 5;
442
443 if ( !$uptime ) {
444- $logger->debug("Connecting to MySQL");
445- my $t0 = time;
446- my $e;
447- my $tries = 2;
448- my $have_mysql = 0;
449- TRY:
450- foreach my $tryno ( 1..$tries ) {
451- eval {
452- $cxn->connect();
453- };
454- $e = $EVAL_ERROR;
455- if ( $e ) {
456- sleep 3 if $tryno < $tries; # failure, try again
457- }
458- else {
459- $have_mysql = 1;
460- last TRY; # success
461- }
462- }
463- if ( $have_mysql ) {
464- eval {
465- (undef, $uptime) = $cxn->dbh->selectrow_array("SHOW STATUS LIKE 'uptime'");
466- };
467- if ( $EVAL_ERROR ) {
468- $logger->warning("Cannot check if MySQL restarted because "
469- . "SHOW STATUS query failed: $EVAL_ERROR");
470- return;
471- }
472- }
473- else {
474- $logger->warning("Cannot check if MySQL restarted because "
475- . "connection to MySQL failed: $e");
476+ my $sql = "SHOW STATUS LIKE 'uptime'";
477+ eval {
478+ (undef, $uptime) = $dbh->selectrow_array($sql);
479+ };
480+ if ( $EVAL_ERROR ) {
481+ $logger->error("$sql: $EVAL_ERROR");
482 return;
483 }
484 }
485@@ -9174,6 +9195,7 @@
486 . "elapsed=$elapsed_time expected=$exepected_uptime "
487 . "+/- ${margin}s actual=$uptime");
488 $state->{mysql_restarted} = ts(time, 1); # 1=UTC
489+ $state->{need_mysql_version} = 1;
490 }
491 }
492
493@@ -9259,14 +9281,13 @@
494 pt-agent is the client-side agent for Percona Cloud Tools. It is not
495 a general command line tool like other tools in Percona Toolkit, it is
496 configured and controlled through the web at https://cloud.percona.com.
497-Please contact Percona or visit https://cloud.percona.com for more information.
498+Visit https://cloud.percona.com for more information and to sign up.
499
500 =head1 DESCRIPTION
501
502 pt-agent is the client-side agent for Percona Cloud Tools (PCT). It is
503 controlled and configured through the web app at https://cloud.percona.com.
504-An account with Percona is required to use pt-agent. Please contact Percona
505-or visit https://cloud.percona.com for more information.
506+Visit https://cloud.percona.com for more information and to sign up.
507
508 pt-agent, or "the agent", is a single, unique instance of the tool running
509 on a server. Two agents cannot run on the same server (see L<"--pid">).
510@@ -9274,9 +9295,9 @@
511 The agent is a daemon that runs as root. It should be started with
512 L<"--daemonize">. It connects periodically to Percona to update
513 its configuration and services, and it schedules L<"--run-service"> and
514-L<"--send-data"> instances of itself. Other than L<"INSTALLING"> and starting
515-the agent locally, all control and configuration is done through the web
516-at https://cloud.percona.com.
517+L<"--send-data"> instances of itself using cron. Other than L<"INSTALLING">
518+and starting the agent locally, all control and configuration is done through
519+the web at https://cloud.percona.com.
520
521 =head1 INSTALLING
522
523@@ -9295,6 +9316,44 @@
524
525 Please contact Percona if you need help installing the agent.
526
527+=head2 SLAVE INSTALL
528+
529+There are two ways to install pt-agent on a slave. The first and best way
530+is to install the agent on the master so that the L<"MYSQL USER"> is created
531+on the master and replicates to slaves. This is best because it avoids
532+writing to the slave. Then create the C</etc/percona/agent/> directory on
533+the slave and copy in to it C</etc/percona/agent/my.cnf> from the master.
534+Run L<"--install"> on the slave and pt-agent will automatically detect and
535+use the MySQL user and password in C</etc/percona/agent/my.cnf>. Repeat the
536+process for other slaves.
537+
538+The second way to install pt-agent on a slave is not safe because it writes
539+directly to the slave: specify L<"--install-options">
540+C<force_dangerous_slave_install> in addition to L<"--install">. As the
541+install option name implies, this is dangerous, but it forces pt-agent
542+to ignore that MySQL is a slave.
543+
544+=head2 Percona XtraDB Cluster (PXC) INSTALL
545+
546+Installing pt-agent on Percona XtraDB Cluster (PXC) nodes is the same as
547+installing it safely on slaves. First install the agent on any node. This
548+will create the L<"MYSQL USER"> that will replicate to all other nodes.
549+Then create the C</etc/percona/agent/> directory on another node and copy in
550+to it C</etc/percona/agent/my.cnf> from the first node where pt-agent was
551+installed. Run L<"--install"> on the node and pt-agent will automatically
552+detect and use the MySQL user and password in C</etc/percona/agent/my.cnf>.
553+Repeat the process for other nodes.
554+
555+=head1 MYSQL USER
556+
557+During L<"--install">, pt-agent creates the following MySQL user:
558+
559+ GRANT SUPER, USAGE ON *.* TO 'pt_agent'@'localhost' IDENTIFIED BY 'pass'
560+
561+C<pass> is a random string. MySQL options for the agent are stored in
562+C</etc/percona/agent/my.cnf>. The C<SUPER> privilege is required so that
563+the agent can set global MySQL variables like C<long_query_time>.
564+
565 =head1 EXIT STATUS
566
567 pt-agent exists zero if no errors or warnings occurred, else it exits non-zero.
568@@ -9637,7 +9696,7 @@
569
570 =over
571
572-=item * An account with Percona
573+=item * A Percona Cloud Tools account (https://cloud.percona.com)
574
575 =item * Access to https://cloud-api.percona.com
576
577@@ -9688,20 +9747,7 @@
578 =head1 DOWNLOADING
579
580 Visit L<http://www.percona.com/software/percona-toolkit/> to download the
581-latest release of Percona Toolkit. Or, get the latest release from the
582-command line:
583-
584- wget percona.com/get/percona-toolkit.tar.gz
585-
586- wget percona.com/get/percona-toolkit.rpm
587-
588- wget percona.com/get/percona-toolkit.deb
589-
590-You can also get individual tools from the latest release:
591-
592- wget percona.com/get/TOOL
593-
594-Replace C<TOOL> with the name of any tool.
595+latest release of Percona Toolkit.
596
597 =head1 AUTHORS
598
599
600=== modified file 'lib/Cxn.pm'
601--- lib/Cxn.pm 2013-06-17 06:23:11 +0000
602+++ lib/Cxn.pm 2013-12-11 04:33:49 +0000
603@@ -119,7 +119,7 @@
604
605 sub connect {
606 my ( $self, %opts ) = @_;
607- my $dsn = $self->{dsn};
608+ my $dsn = $opts{dsn} || $self->{dsn};
609 my $dp = $self->{DSNParser};
610
611 my $dbh = $self->{dbh};
612@@ -139,6 +139,13 @@
613 }
614
615 $dbh = $self->set_dbh($dbh);
616+ if ( $opts{dsn} ) {
617+ $self->{dsn} = $dsn;
618+ $self->{dsn_name} = $dp->as_string($dsn, [qw(h P S)])
619+ || $dp->as_string($dsn, [qw(F)])
620+ || '';
621+
622+ }
623 PTDEBUG && _d($dbh, 'Connected dbh to', $self->{hostname},$self->{dsn_name});
624 return $dbh;
625 }
626
627=== modified file 'lib/Percona/Agent/Logger.pm'
628--- lib/Percona/Agent/Logger.pm 2013-09-19 20:25:20 +0000
629+++ lib/Percona/Agent/Logger.pm 2013-12-11 04:33:49 +0000
630@@ -250,7 +250,7 @@
631 sub debug {
632 my $self = shift;
633 return if $self->online_logging;
634- return $self->_log(0, 'DEBUG', 1, @_);
635+ return $self->_log(0, 'DEBUG', @_);
636 }
637
638 sub info {
639@@ -287,7 +287,7 @@
640 }
641
642 sub _log {
643- my ($self, $online, $level, $msg, $offline) = @_;
644+ my ($self, $online, $level, $msg) = @_;
645
646 my $ts = ts(time, 1); # 1=UTC
647 my $level_number = level_number($level);
648
649=== modified file 't/lib/Cxn.t'
650--- t/lib/Cxn.t 2013-03-02 20:10:28 +0000
651+++ t/lib/Cxn.t 2013-12-11 04:33:49 +0000
652@@ -24,6 +24,8 @@
653 my $dp = new DSNParser(opts=>$dsn_opts);
654 my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
655 my $master_dbh = $sb->get_dbh_for('master');
656+my $slave1_dbh = $sb->get_dbh_for('slave1');
657+my $slave1_dsn = $sb->dsn_for('slave1');
658
659 if ( !$master_dbh ) {
660 plan skip_all => 'Cannot connect to sandbox master';
661@@ -320,6 +322,58 @@
662 unlink $outfile if -f $outfile;
663
664 # #############################################################################
665+# Re-connect with new DSN.
666+# #############################################################################
667+
668+SKIP: {
669+ skip "Cannot connect to slave1", 4 unless $slave1_dbh;
670+
671+ $cxn = make_cxn(
672+ dsn_string => 'h=127.1,P=12345,u=msandbox,p=msandbox',
673+ );
674+
675+ $cxn->connect();
676+ ok(
677+ $cxn->dbh()->ping(),
678+ "First connect()"
679+ );
680+
681+ ($row) = $cxn->dbh()->selectrow_hashref('SHOW SLAVE STATUS');
682+ ok(
683+ !defined $row,
684+ "First connect() to master"
685+ ) or diag(Dumper($row));
686+
687+ $cxn->dbh->disconnect();
688+ $cxn->connect(dsn => $dp->parse($slave1_dsn));
689+
690+ ok(
691+ $cxn->dbh()->ping(),
692+ "Re-connect connect()"
693+ );
694+
695+ ($row) = $cxn->dbh()->selectrow_hashref('SHOW SLAVE STATUS');
696+ ok(
697+ $row,
698+ "Re-connect connect(slave_dsn) to slave"
699+ ) or diag(Dumper($row));
700+
701+ $cxn->dbh->disconnect();
702+ $cxn->connect();
703+
704+ ok(
705+ $cxn->dbh()->ping(),
706+ "Re-re-connect connect()"
707+ );
708+
709+ ($row) = $cxn->dbh()->selectrow_hashref('SHOW SLAVE STATUS');
710+ ok(
711+ $row,
712+ "Re-re-connect connect() to slave"
713+ ) or diag(Dumper($row));
714+}
715+
716+# #############################################################################
717 # Done.
718 # #############################################################################
719 $master_dbh->disconnect() if $master_dbh;

Subscribers

People subscribed via source and target branches

to all changes: