Merge lp:~percona-toolkit-dev/percona-toolkit/pt-agent-fixes into lp:~percona-toolkit-dev/percona-toolkit/release-2.2.6
- pt-agent-fixes
- Merge into release-2.2.6
Proposed by
Daniel Nichter
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Daniel Nichter | Approve | ||
Review via email: mp+198493@code.launchpad.net |
Commit message
Description of the change
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; |