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
=== modified file 'bin/pt-agent'
--- bin/pt-agent 2013-11-08 03:00:56 +0000
+++ bin/pt-agent 2013-12-11 04:33:49 +0000
@@ -3691,7 +3691,7 @@
36913691
3692sub connect {3692sub connect {
3693 my ( $self, %opts ) = @_;3693 my ( $self, %opts ) = @_;
3694 my $dsn = $self->{dsn};3694 my $dsn = $opts{dsn} || $self->{dsn};
3695 my $dp = $self->{DSNParser};3695 my $dp = $self->{DSNParser};
36963696
3697 my $dbh = $self->{dbh};3697 my $dbh = $self->{dbh};
@@ -3710,6 +3710,13 @@
3710 }3710 }
37113711
3712 $dbh = $self->set_dbh($dbh);3712 $dbh = $self->set_dbh($dbh);
3713 if ( $opts{dsn} ) {
3714 $self->{dsn} = $dsn;
3715 $self->{dsn_name} = $dp->as_string($dsn, [qw(h P S)])
3716 || $dp->as_string($dsn, [qw(F)])
3717 || '';
3718
3719 }
3713 PTDEBUG && _d($dbh, 'Connected dbh to', $self->{hostname},$self->{dsn_name});3720 PTDEBUG && _d($dbh, 'Connected dbh to', $self->{hostname},$self->{dsn_name});
3714 return $dbh;3721 return $dbh;
3715}3722}
@@ -3873,6 +3880,8 @@
3873 return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data3880 return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data
3874 && !$args{is_char}; # unless is_char is true3881 && !$args{is_char}; # unless is_char is true
38753882
3883 return $val if $args{is_float};
3884
3876 $val =~ s/(['\\])/\\$1/g;3885 $val =~ s/(['\\])/\\$1/g;
3877 return "'$val'";3886 return "'$val'";
3878}3887}
@@ -5092,7 +5101,7 @@
5092sub debug {5101sub debug {
5093 my $self = shift;5102 my $self = shift;
5094 return if $self->online_logging;5103 return if $self->online_logging;
5095 return $self->_log(0, 'DEBUG', 1, @_);5104 return $self->_log(0, 'DEBUG', @_);
5096}5105}
50975106
5098sub info {5107sub info {
@@ -5128,7 +5137,7 @@
5128}5137}
51295138
5130sub _log {5139sub _log {
5131 my ($self, $online, $level, $msg, $offline) = @_;5140 my ($self, $online, $level, $msg) = @_;
51325141
5133 my $ts = ts(time, 1); # 1=UTC5142 my $ts = ts(time, 1); # 1=UTC
5134 my $level_number = level_number($level);5143 my $level_number = level_number($level);
@@ -5792,6 +5801,7 @@
5792 # Optional args5801 # Optional args
5793 my $_oktorun = $args{oktorun} || sub { return $oktorun };5802 my $_oktorun = $args{oktorun} || sub { return $oktorun };
5794 my $actions = $args{actions};5803 my $actions = $args{actions};
5804 my $quiet = $args{quiet};
57955805
5796 # Update these attribs every time the agent is initialized.5806 # Update these attribs every time the agent is initialized.
5797 # Other optional attribs, like versions, are left to the caller.5807 # Other optional attribs, like versions, are left to the caller.
@@ -5802,7 +5812,7 @@
5802 # Try to create/update the Agent.5812 # Try to create/update the Agent.
5803 my $success = 0;5813 my $success = 0;
5804 while ( $_oktorun->() && $tries-- ) {5814 while ( $_oktorun->() && $tries-- ) {
5805 if ( !$state->{init_action}++ ) {5815 if ( !$state->{init_action}++ && !$quiet ) {
5806 $logger->info($action eq 'put' ? "Updating agent " . $agent->name5816 $logger->info($action eq 'put' ? "Updating agent " . $agent->name
5807 : "Creating new agent");5817 : "Creating new agent");
5808 }5818 }
@@ -5841,7 +5851,7 @@
5841 }5851 }
5842 }5852 }
5843 elsif ( !$agent_uri ) {5853 elsif ( !$agent_uri ) {
5844 $logger->info("No URI for Agent " . $agent->name);5854 $logger->warning("No URI for Agent " . $agent->name);
5845 }5855 }
5846 else {5856 else {
5847 # The Agent URI will have been returned in the Location header5857 # The Agent URI will have been returned in the Location header
@@ -5868,7 +5878,7 @@
5868 delete $state->{init_action};5878 delete $state->{init_action};
5869 delete $state->{too_many_agents};5879 delete $state->{too_many_agents};
58705880
5871 if ( $agent && $success ) {5881 if ( $agent && $success && !$quiet ) {
5872 $logger->info("Agent " . $agent->name . " (" . $agent->uuid . ") is ready");5882 $logger->info("Agent " . $agent->name . " (" . $agent->uuid . ") is ready");
5873 }5883 }
58745884
@@ -5955,7 +5965,7 @@
5955 my $entry_links = $args{entry_links}; # for testing5965 my $entry_links = $args{entry_links}; # for testing
5956 my $logger_client = $args{logger_client}; # for testing5966 my $logger_client = $args{logger_client}; # for testing
59575967
5958 $logger->info('Starting agent');5968 # $logger->info('Starting agent');
59595969
5960 # Daemonize first so all output goes to the --log.5970 # Daemonize first so all output goes to the --log.
5961 my $daemon = Daemon->new(5971 my $daemon = Daemon->new(
@@ -6126,8 +6136,9 @@
6126 # #######################################################################6136 # #######################################################################
6127 # Main agent loop6137 # Main agent loop
6128 # #######################################################################6138 # #######################################################################
6139 $state->{need_mysql_version} = 1;
6129 $state->{first_config} = 1;6140 $state->{first_config} = 1;
6130 my $first_config_interval = 60;6141 my $first_config_interval = 20;
6131 $logger->info("Checking silently every $first_config_interval seconds"6142 $logger->info("Checking silently every $first_config_interval seconds"
6132 . " for the first config");6143 . " for the first config");
61336144
@@ -6136,38 +6147,6 @@
6136 my $config;6147 my $config;
6137 my $services = {};6148 my $services = {};
6138 while ( $_oktorun->() ) {6149 while ( $_oktorun->() ) {
6139 check_if_mysql_restarted(
6140 Cxn => $cxn,
6141 );
6142
6143 if ( $state->{need_mysql_version} ) {
6144 my $versions = get_versions(
6145 Cxn => $cxn,
6146 );
6147 if ( $versions->{MySQL} ) {
6148 $agent->versions($versions);
6149 my $updated_agent;
6150 ($agent, $updated_agent) = init_agent(
6151 agent => $agent,
6152 action => 'put',
6153 link => $agent->links->{self},
6154 client => $client,
6155 interval => sub { return; },
6156 tries => 1, # optional
6157 );
6158 if ( $updated_agent ) {
6159 $logger->info("Got MySQL versions");
6160 save_agent(
6161 agent => $agent,
6162 lib_dir => $lib_dir,
6163 );
6164 }
6165 else {
6166 $state->{need_mysql_version} = 1;
6167 }
6168 }
6169 }
6170
6171 ($config, $lib_dir, $new_daemon, $success) = get_config(6150 ($config, $lib_dir, $new_daemon, $success) = get_config(
6172 link => $agent->links->{config},6151 link => $agent->links->{config},
6173 agent => $agent,6152 agent => $agent,
@@ -6185,6 +6164,7 @@
6185 delete $state->{first_config};6164 delete $state->{first_config};
6186 $logger->info('Agent has been configured');6165 $logger->info('Agent has been configured');
6187 }6166 }
6167
6188 if ( $new_daemon ) {6168 if ( $new_daemon ) {
6189 # NOTE: Daemon objects use DESTROY to auto-remove their pid file6169 # NOTE: Daemon objects use DESTROY to auto-remove their pid file
6190 # when they lose scope (i.e. ref count goes to zero). This6170 # when they lose scope (i.e. ref count goes to zero). This
@@ -6200,6 +6180,60 @@
6200 $daemon = $new_daemon;6180 $daemon = $new_daemon;
6201 }6181 }
62026182
6183 # Connect to MySQL, then check stuff.
6184 my $o = new OptionParser();
6185 $o->get_specs();
6186 $o->get_opts();
6187 my $dp = $o->DSNParser();
6188 $dp->prop('set-vars', $o->set_vars());
6189 my $dsn = $dp->parse_options($o);
6190 eval {
6191 $cxn->connect(dsn => $dsn);
6192 };
6193 if ( $EVAL_ERROR ) {
6194 $logger->warning("MySQL connection failure: $EVAL_ERROR");
6195 $state->{have_mysql} = 0;
6196 $state->{need_mysql_version} = 1;
6197 }
6198 else {
6199 if ( !$state->{have_mysql} ) {
6200 $logger->info("MySQL connection OK");
6201 }
6202 $state->{have_mysql} = 1;
6203 check_if_mysql_restarted(
6204 dbh => $cxn->dbh,
6205 );
6206 if ( $state->{need_mysql_version} ) {
6207 $logger->debug("Need MySQL version");
6208 my $versions = get_versions(Cxn => $cxn);
6209 if ( $versions->{MySQL} ) {
6210 $agent->versions($versions);
6211 my $updated_agent;
6212 ($agent, $updated_agent) = init_agent(
6213 agent => $agent,
6214 action => 'put',
6215 link => $agent->links->{self},
6216 client => $client,
6217 tries => 1,
6218 interval => sub { return; },
6219 quiet => 1,
6220 );
6221 if ( $updated_agent ) {
6222 $logger->debug("Got MySQL version");
6223 save_agent(
6224 agent => $agent,
6225 lib_dir => $lib_dir,
6226 );
6227 delete $state->{need_mysql_version};
6228 }
6229 }
6230 else {
6231 $logger->debug("Failed to get MySQL version");
6232 }
6233 }
6234 $cxn->dbh->disconnect();
6235 }
6236
6203 # Check the safeguards.6237 # Check the safeguards.
6204 my ($disk_space, $disk_space_ok);6238 my ($disk_space, $disk_space_ok);
6205 eval {6239 eval {
@@ -6341,6 +6375,8 @@
6341 $config = $new_config;6375 $config = $new_config;
6342 $success = 1;6376 $success = 1;
6343 $logger->info('Config ' . $config->ts . ' applied');6377 $logger->info('Config ' . $config->ts . ' applied');
6378
6379 $state->{need_mysql_version} = 1;
6344 }6380 }
6345 else {6381 else {
6346 $success = 1;6382 $success = 1;
@@ -8319,7 +8355,7 @@
8319 );8355 );
8320 }8356 }
8321 # Match the first digits, which should be the PID.8357 # Match the first digits, which should be the PID.
8322 ($pid) =~ $ps_output =~ m/(\d+)/;8358 ($pid) = $ps_output =~ m/(\d+)/;
8323 }8359 }
83248360
8325 if ( !$pid ) {8361 if ( !$pid ) {
@@ -8405,6 +8441,7 @@
84058441
8406 my $agent_my_cnf = '/etc/percona/agent/my.cnf';8442 my $agent_my_cnf = '/etc/percona/agent/my.cnf';
8407 my $config_file = get_config_file();8443 my $config_file = get_config_file();
8444 my $lib_dir = $o->get('lib');
84088445
8409 my $step_result;8446 my $step_result;
8410 my $stepno = 0;8447 my $stepno = 0;
@@ -8414,6 +8451,7 @@
8414 "Verify the user is root",8451 "Verify the user is root",
8415 "Check Perl module dependencies",8452 "Check Perl module dependencies",
8416 "Check for crontab",8453 "Check for crontab",
8454 "Verify pt-agent is not installed",
8417 "Verify the API key",8455 "Verify the API key",
8418 "Connect to MySQL",8456 "Connect to MySQL",
8419 "Check if MySQL is a slave",8457 "Check if MySQL is a slave",
@@ -8483,7 +8521,25 @@
8483 die "cron is not installed, or crontab is not in your PATH.\n";8521 die "cron is not installed, or crontab is not in your PATH.\n";
8484 }8522 }
84858523
8524 # Verify pt-agent is not installed
8525 $next_step->();
8526 my @install_files = ($agent_my_cnf, $config_file, "$lib_dir/agent");
8527 my @have_files;
8528 foreach my $file (@install_files) {
8529 push @have_files, $file if -f $file;
8530 }
8531 if ( scalar @have_files ) {
8532 print "FAIL\n";
8533 die "It looks like pt-agent is already installed because these files exist:\n"
8534 . join("\n", map { " $_" } @have_files)
8535 . "\nRun pt-agent --uninstall to remove these files. To upgrade pt-agent, "
8536 . "install the new version, run pt-agent --stop, then pt-agent --daemonize "
8537 . "to restart pt-agent with the new version.\n";
8538 }
8539
8486 # Must have a valid API key.8540 # Must have a valid API key.
8541 $next_step->();
8542 my $got_api_key = 0;
8487 my $api_key = $o->get('api-key');8543 my $api_key = $o->get('api-key');
8488 if ( !$api_key ) {8544 if ( !$api_key ) {
8489 print "\n";8545 print "\n";
@@ -8497,19 +8553,22 @@
8497 $api_key = '';8553 $api_key = '';
8498 }8554 }
8499 }8555 }
8500 $next_step->(repeat => 1); # repeat
8501 }8556 }
8502 else {8557 else {
8503 die "Please specify your --api-key.\n";8558 die "Please specify your --api-key.\n";
8504 }8559 }
8560 $got_api_key = 1;
8505 }8561 }
8562
8506 my $client;8563 my $client;
8507 my $entry_links;8564 my $entry_links;
8508 if ( $flags->{offline} ) {8565 if ( $flags->{offline} ) {
8509 $skip++;8566 $skip++;
8510 }8567 }
8511 else {8568 else {
8512 $next_step->();8569 if ($got_api_key) {
8570 $next_step->(repeat => 1);
8571 }
8513 eval {8572 eval {
8514 ($client, $entry_links) = get_api_client(8573 ($client, $entry_links) = get_api_client(
8515 api_key => $api_key,8574 api_key => $api_key,
@@ -8571,30 +8630,13 @@
8571 if ( $flags->{force_dangerous_slave_install} ) {8630 if ( $flags->{force_dangerous_slave_install} ) {
8572 create_mysql_user($cxn, $agent_my_cnf);8631 create_mysql_user($cxn, $agent_my_cnf);
8573 }8632 }
8574 elsif ( $interactive || -t STDIN ) {
8575 print "\nMySQL is a slave and $agent_my_cnf does not exist. "
8576 . "To install the agent, please enter the MySQL username and "
8577 . "password to use. The MySQL user must have SUPER and USAGE "
8578 . "privileges on all databases, for example: "
8579 . "GRANT SUPER,USAGE ON *.* TO pt_agent'\@'localhost'. "
8580 . "If the agent has been installed on the master, you can use "
8581 . "the MySQL username and password in $agent_my_cnf on the "
8582 . "master. CTRL-C to abort install.\n";
8583 print "MySQL username: ";
8584 my $user = <STDIN>;
8585 chomp($user) if $user;
8586 my $pass = OptionParser::prompt_noecho("MySQL password: ");
8587 create_mysql_user($cxn, $agent_my_cnf, $user, $pass);
8588 $next_step->(repeat => 1); # repeat
8589 }
8590 else {8633 else {
8591 die "Sorry, cannot install the agent because MySQL is a slave "8634 die "Sorry, cannot install the agent because MySQL is a slave "
8592 . "and $agent_my_cnf does not exist. It is not safe to "8635 . "and $agent_my_cnf does not exist. It is not safe to "
8593 . "write to a slave, so a MySQL user for the agent cannot "8636 . "write to a slave, so a MySQL user for the agent cannot "
8594 . "be created. First install the agent on the master, then "8637 . "be created. First install the agent on the master, then "
8595 . "copy $agent_my_cnf from the master to this server. "8638 . "copy $agent_my_cnf from the master to this server. "
8596 . "See --install-options for how to force a dangerous slave "8639 . "See SLAVE INSTALL in the docs for more information.\n";
8597 . "install.\n";
8598 }8640 }
8599 }8641 }
8600 }8642 }
@@ -8616,7 +8658,7 @@
8616 # do it now in case there are problems. 8658 # do it now in case there are problems.
8617 $next_step->();8659 $next_step->();
8618 init_lib_dir(8660 init_lib_dir(
8619 lib_dir => $o->get('lib'),8661 lib_dir => $lib_dir,
8620 );8662 );
8621 init_spool_dir(8663 init_spool_dir(
8622 spool_dir => $o->get('spool'),8664 spool_dir => $o->get('spool'),
@@ -8997,33 +9039,7 @@
8997 my (%args) = @_;9039 my (%args) = @_;
8998 my $cxn = $args{Cxn};9040 my $cxn = $args{Cxn};
8999 my $tries = $args{tries} || 1;9041 my $tries = $args{tries} || 1;
9000 my $interval = $args{interval} || sub { sleep 3; };9042 my $interval = $args{interval} || sub { return; };
9001
9002 my $have_mysql = 0;
9003 if ( $cxn ) {
9004 $logger->debug("Connecting to MySQL");
9005 foreach my $tryno ( 1..$tries ) {
9006 eval {
9007 $cxn->connect();
9008 };
9009 if ( $EVAL_ERROR ) {
9010 $logger->debug("Cannot connect to MySQL: $EVAL_ERROR");
9011 }
9012 else {
9013 $have_mysql = 1;
9014 delete $state->{need_mysql_version};
9015 last; # success
9016 }
9017 if ( $tryno < $tries ) {
9018 sleep $interval; # failure, try again
9019 }
9020 else {
9021 $state->{need_mysql_version} = 1;
9022 $logger->warning("Cannot get MySQL version, will try again later");
9023 last; # failure
9024 }
9025 }
9026 }
90279043
9028 # This is currently the actual response from GET v.percona.com9044 # This is currently the actual response from GET v.percona.com
9029 my $fake_response = <<EOL;9045 my $fake_response = <<EOL;
@@ -9032,6 +9048,10 @@
9032Perl;perl_version9048Perl;perl_version
9033DBD::mysql;perl_module_version9049DBD::mysql;perl_module_version
9034Percona::Toolkit;perl_module_version9050Percona::Toolkit;perl_module_version
9051JSON;perl_module_version
9052LWP;perl_module_version
9053IO::Socket::SSL;perl_module_version
9054DBD::mysql;perl_module_version
9035EOL9055EOL
90369056
9037 my $items = VersionCheck::parse_server_response(9057 my $items = VersionCheck::parse_server_response(
@@ -9042,12 +9062,39 @@
9042 { name => 'system', id => 0, },9062 { name => 'system', id => 0, },
9043 ];9063 ];
90449064
9065 my $have_mysql = -1;
9066 if ( !$cxn->dbh || !$cxn->dbh->ping() ) {
9067 $logger->debug("Connecting to MySQL");
9068 eval {
9069 $cxn->connect();
9070 };
9071 if ( $EVAL_ERROR ) {
9072 $logger->debug("Cannot connect to MySQL: $EVAL_ERROR");
9073 $have_mysql = 0;
9074 }
9075 else {
9076 $have_mysql = 1;
9077 }
9078 }
9079
9045 if ( $have_mysql ) {9080 if ( $have_mysql ) {
9081 $logger->debug("Have MySQL connection");
9046 my ($name, $id) = VersionCheck::get_instance_id(9082 my ($name, $id) = VersionCheck::get_instance_id(
9047 { dbh => $cxn->dbh, dsn => $cxn->dsn },9083 { dbh => $cxn->dbh, dsn => $cxn->dsn },
9048 );9084 );
9049 push @$instances,9085 push @$instances,
9050 { name => $name, id => $id, dbh => $cxn->dbh, dsn => $cxn->dsn };9086 { name => $name, id => $id, dbh => $cxn->dbh, dsn => $cxn->dsn };
9087
9088 # Disconnect MySQL if we connected it.
9089 if ( $have_mysql == 1 ) {
9090 $logger->debug("Disconnecting MySQL");
9091 eval {
9092 $cxn->dbh->disconnect();
9093 };
9094 if ( $EVAL_ERROR ) {
9095 $logger->debug($EVAL_ERROR);
9096 }
9097 }
9051 }9098 }
90529099
9053 my $versions = VersionCheck::get_versions(9100 my $versions = VersionCheck::get_versions(
@@ -9112,47 +9159,21 @@
9112sub check_if_mysql_restarted {9159sub check_if_mysql_restarted {
9113 my (%args) = @_;9160 my (%args) = @_;
9114 have_required_args(\%args, qw(9161 have_required_args(\%args, qw(
9115 Cxn9162 dbh
9116 )) or die;9163 )) or die;
9117 my $cxn = $args{Cxn};9164 my $dbh = $args{dbh};
91189165
9119 # Optional args9166 # Optional args
9120 my $uptime = $args{uptime}; # for testing9167 my $uptime = $args{uptime}; # for testing
9121 my $margin = $args{margin} || 5;9168 my $margin = $args{margin} || 5;
91229169
9123 if ( !$uptime ) {9170 if ( !$uptime ) {
9124 $logger->debug("Connecting to MySQL");9171 my $sql = "SHOW STATUS LIKE 'uptime'";
9125 my $t0 = time;9172 eval {
9126 my $e;9173 (undef, $uptime) = $dbh->selectrow_array($sql);
9127 my $tries = 2;9174 };
9128 my $have_mysql = 0;9175 if ( $EVAL_ERROR ) {
9129 TRY:9176 $logger->error("$sql: $EVAL_ERROR");
9130 foreach my $tryno ( 1..$tries ) {
9131 eval {
9132 $cxn->connect();
9133 };
9134 $e = $EVAL_ERROR;
9135 if ( $e ) {
9136 sleep 3 if $tryno < $tries; # failure, try again
9137 }
9138 else {
9139 $have_mysql = 1;
9140 last TRY; # success
9141 }
9142 }
9143 if ( $have_mysql ) {
9144 eval {
9145 (undef, $uptime) = $cxn->dbh->selectrow_array("SHOW STATUS LIKE 'uptime'");
9146 };
9147 if ( $EVAL_ERROR ) {
9148 $logger->warning("Cannot check if MySQL restarted because "
9149 . "SHOW STATUS query failed: $EVAL_ERROR");
9150 return;
9151 }
9152 }
9153 else {
9154 $logger->warning("Cannot check if MySQL restarted because "
9155 . "connection to MySQL failed: $e");
9156 return;9177 return;
9157 }9178 }
9158 }9179 }
@@ -9174,6 +9195,7 @@
9174 . "elapsed=$elapsed_time expected=$exepected_uptime "9195 . "elapsed=$elapsed_time expected=$exepected_uptime "
9175 . "+/- ${margin}s actual=$uptime");9196 . "+/- ${margin}s actual=$uptime");
9176 $state->{mysql_restarted} = ts(time, 1); # 1=UTC9197 $state->{mysql_restarted} = ts(time, 1); # 1=UTC
9198 $state->{need_mysql_version} = 1;
9177 }9199 }
9178 }9200 }
91799201
@@ -9259,14 +9281,13 @@
9259pt-agent is the client-side agent for Percona Cloud Tools. It is not9281pt-agent is the client-side agent for Percona Cloud Tools. It is not
9260a general command line tool like other tools in Percona Toolkit, it is9282a general command line tool like other tools in Percona Toolkit, it is
9261configured and controlled through the web at https://cloud.percona.com.9283configured and controlled through the web at https://cloud.percona.com.
9262Please contact Percona or visit https://cloud.percona.com for more information.9284Visit https://cloud.percona.com for more information and to sign up.
92639285
9264=head1 DESCRIPTION9286=head1 DESCRIPTION
92659287
9266pt-agent is the client-side agent for Percona Cloud Tools (PCT). It is9288pt-agent is the client-side agent for Percona Cloud Tools (PCT). It is
9267controlled and configured through the web app at https://cloud.percona.com.9289controlled and configured through the web app at https://cloud.percona.com.
9268An account with Percona is required to use pt-agent. Please contact Percona9290Visit https://cloud.percona.com for more information and to sign up.
9269or visit https://cloud.percona.com for more information.
92709291
9271pt-agent, or "the agent", is a single, unique instance of the tool running9292pt-agent, or "the agent", is a single, unique instance of the tool running
9272on a server. Two agents cannot run on the same server (see L<"--pid">).9293on a server. Two agents cannot run on the same server (see L<"--pid">).
@@ -9274,9 +9295,9 @@
9274The agent is a daemon that runs as root. It should be started with9295The agent is a daemon that runs as root. It should be started with
9275L<"--daemonize">. It connects periodically to Percona to update9296L<"--daemonize">. It connects periodically to Percona to update
9276its configuration and services, and it schedules L<"--run-service"> and9297its configuration and services, and it schedules L<"--run-service"> and
9277L<"--send-data"> instances of itself. Other than L<"INSTALLING"> and starting9298L<"--send-data"> instances of itself using cron. Other than L<"INSTALLING">
9278the agent locally, all control and configuration is done through the web9299and starting the agent locally, all control and configuration is done through
9279at https://cloud.percona.com.9300the web at https://cloud.percona.com.
92809301
9281=head1 INSTALLING9302=head1 INSTALLING
92829303
@@ -9295,6 +9316,44 @@
92959316
9296Please contact Percona if you need help installing the agent.9317Please contact Percona if you need help installing the agent.
92979318
9319=head2 SLAVE INSTALL
9320
9321There are two ways to install pt-agent on a slave. The first and best way
9322is to install the agent on the master so that the L<"MYSQL USER"> is created
9323on the master and replicates to slaves. This is best because it avoids
9324writing to the slave. Then create the C</etc/percona/agent/> directory on
9325the slave and copy in to it C</etc/percona/agent/my.cnf> from the master.
9326Run L<"--install"> on the slave and pt-agent will automatically detect and
9327use the MySQL user and password in C</etc/percona/agent/my.cnf>. Repeat the
9328process for other slaves.
9329
9330The second way to install pt-agent on a slave is not safe because it writes
9331directly to the slave: specify L<"--install-options">
9332C<force_dangerous_slave_install> in addition to L<"--install">. As the
9333install option name implies, this is dangerous, but it forces pt-agent
9334to ignore that MySQL is a slave.
9335
9336=head2 Percona XtraDB Cluster (PXC) INSTALL
9337
9338Installing pt-agent on Percona XtraDB Cluster (PXC) nodes is the same as
9339installing it safely on slaves. First install the agent on any node. This
9340will create the L<"MYSQL USER"> that will replicate to all other nodes.
9341Then create the C</etc/percona/agent/> directory on another node and copy in
9342to it C</etc/percona/agent/my.cnf> from the first node where pt-agent was
9343installed. Run L<"--install"> on the node and pt-agent will automatically
9344detect and use the MySQL user and password in C</etc/percona/agent/my.cnf>.
9345Repeat the process for other nodes.
9346
9347=head1 MYSQL USER
9348
9349During L<"--install">, pt-agent creates the following MySQL user:
9350
9351 GRANT SUPER, USAGE ON *.* TO 'pt_agent'@'localhost' IDENTIFIED BY 'pass'
9352
9353C<pass> is a random string. MySQL options for the agent are stored in
9354C</etc/percona/agent/my.cnf>. The C<SUPER> privilege is required so that
9355the agent can set global MySQL variables like C<long_query_time>.
9356
9298=head1 EXIT STATUS9357=head1 EXIT STATUS
92999358
9300pt-agent exists zero if no errors or warnings occurred, else it exits non-zero.9359pt-agent exists zero if no errors or warnings occurred, else it exits non-zero.
@@ -9637,7 +9696,7 @@
96379696
9638=over9697=over
96399698
9640=item * An account with Percona9699=item * A Percona Cloud Tools account (https://cloud.percona.com)
96419700
9642=item * Access to https://cloud-api.percona.com9701=item * Access to https://cloud-api.percona.com
96439702
@@ -9688,20 +9747,7 @@
9688=head1 DOWNLOADING9747=head1 DOWNLOADING
96899748
9690Visit L<http://www.percona.com/software/percona-toolkit/> to download the9749Visit L<http://www.percona.com/software/percona-toolkit/> to download the
9691latest release of Percona Toolkit. Or, get the latest release from the9750latest release of Percona Toolkit.
9692command line:
9693
9694 wget percona.com/get/percona-toolkit.tar.gz
9695
9696 wget percona.com/get/percona-toolkit.rpm
9697
9698 wget percona.com/get/percona-toolkit.deb
9699
9700You can also get individual tools from the latest release:
9701
9702 wget percona.com/get/TOOL
9703
9704Replace C<TOOL> with the name of any tool.
97059751
9706=head1 AUTHORS9752=head1 AUTHORS
97079753
97089754
=== modified file 'lib/Cxn.pm'
--- lib/Cxn.pm 2013-06-17 06:23:11 +0000
+++ lib/Cxn.pm 2013-12-11 04:33:49 +0000
@@ -119,7 +119,7 @@
119119
120sub connect {120sub connect {
121 my ( $self, %opts ) = @_;121 my ( $self, %opts ) = @_;
122 my $dsn = $self->{dsn};122 my $dsn = $opts{dsn} || $self->{dsn};
123 my $dp = $self->{DSNParser};123 my $dp = $self->{DSNParser};
124124
125 my $dbh = $self->{dbh};125 my $dbh = $self->{dbh};
@@ -139,6 +139,13 @@
139 }139 }
140140
141 $dbh = $self->set_dbh($dbh);141 $dbh = $self->set_dbh($dbh);
142 if ( $opts{dsn} ) {
143 $self->{dsn} = $dsn;
144 $self->{dsn_name} = $dp->as_string($dsn, [qw(h P S)])
145 || $dp->as_string($dsn, [qw(F)])
146 || '';
147
148 }
142 PTDEBUG && _d($dbh, 'Connected dbh to', $self->{hostname},$self->{dsn_name});149 PTDEBUG && _d($dbh, 'Connected dbh to', $self->{hostname},$self->{dsn_name});
143 return $dbh;150 return $dbh;
144}151}
145152
=== modified file 'lib/Percona/Agent/Logger.pm'
--- lib/Percona/Agent/Logger.pm 2013-09-19 20:25:20 +0000
+++ lib/Percona/Agent/Logger.pm 2013-12-11 04:33:49 +0000
@@ -250,7 +250,7 @@
250sub debug {250sub debug {
251 my $self = shift;251 my $self = shift;
252 return if $self->online_logging;252 return if $self->online_logging;
253 return $self->_log(0, 'DEBUG', 1, @_);253 return $self->_log(0, 'DEBUG', @_);
254}254}
255255
256sub info {256sub info {
@@ -287,7 +287,7 @@
287}287}
288288
289sub _log {289sub _log {
290 my ($self, $online, $level, $msg, $offline) = @_;290 my ($self, $online, $level, $msg) = @_;
291291
292 my $ts = ts(time, 1); # 1=UTC292 my $ts = ts(time, 1); # 1=UTC
293 my $level_number = level_number($level);293 my $level_number = level_number($level);
294294
=== modified file 't/lib/Cxn.t'
--- t/lib/Cxn.t 2013-03-02 20:10:28 +0000
+++ t/lib/Cxn.t 2013-12-11 04:33:49 +0000
@@ -24,6 +24,8 @@
24my $dp = new DSNParser(opts=>$dsn_opts);24my $dp = new DSNParser(opts=>$dsn_opts);
25my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);25my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
26my $master_dbh = $sb->get_dbh_for('master');26my $master_dbh = $sb->get_dbh_for('master');
27my $slave1_dbh = $sb->get_dbh_for('slave1');
28my $slave1_dsn = $sb->dsn_for('slave1');
2729
28if ( !$master_dbh ) {30if ( !$master_dbh ) {
29 plan skip_all => 'Cannot connect to sandbox master';31 plan skip_all => 'Cannot connect to sandbox master';
@@ -320,6 +322,58 @@
320unlink $outfile if -f $outfile;322unlink $outfile if -f $outfile;
321323
322# #############################################################################324# #############################################################################
325# Re-connect with new DSN.
326# #############################################################################
327
328SKIP: {
329 skip "Cannot connect to slave1", 4 unless $slave1_dbh;
330
331 $cxn = make_cxn(
332 dsn_string => 'h=127.1,P=12345,u=msandbox,p=msandbox',
333 );
334
335 $cxn->connect();
336 ok(
337 $cxn->dbh()->ping(),
338 "First connect()"
339 );
340
341 ($row) = $cxn->dbh()->selectrow_hashref('SHOW SLAVE STATUS');
342 ok(
343 !defined $row,
344 "First connect() to master"
345 ) or diag(Dumper($row));
346
347 $cxn->dbh->disconnect();
348 $cxn->connect(dsn => $dp->parse($slave1_dsn));
349
350 ok(
351 $cxn->dbh()->ping(),
352 "Re-connect connect()"
353 );
354
355 ($row) = $cxn->dbh()->selectrow_hashref('SHOW SLAVE STATUS');
356 ok(
357 $row,
358 "Re-connect connect(slave_dsn) to slave"
359 ) or diag(Dumper($row));
360
361 $cxn->dbh->disconnect();
362 $cxn->connect();
363
364 ok(
365 $cxn->dbh()->ping(),
366 "Re-re-connect connect()"
367 );
368
369 ($row) = $cxn->dbh()->selectrow_hashref('SHOW SLAVE STATUS');
370 ok(
371 $row,
372 "Re-re-connect connect() to slave"
373 ) or diag(Dumper($row));
374}
375
376# #############################################################################
323# Done.377# Done.
324# #############################################################################378# #############################################################################
325$master_dbh->disconnect() if $master_dbh;379$master_dbh->disconnect() if $master_dbh;

Subscribers

People subscribed via source and target branches

to all changes: