polardbxengine/storage/ndb/tools/ndb_error_reporter.pl

238 lines
6.9 KiB
Perl

#!/usr/bin/perl -w
# Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2.0,
# as published by the Free Software Foundation.
#
# This program is also distributed with certain software (including
# but not limited to OpenSSL) that is licensed under separate terms,
# as designated in a particular file or component or in included license
# documentation. The authors of MySQL hereby grant you an additional
# permission to link the program and your derivative works with the
# separately licensed software that they have included with MySQL.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License, version 2.0, for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
use strict;
use Getopt::Long;
sub usage
{
print STDERR "Usage:\n";
print STDERR "\tndb_error_reporter config.ini [username] [--fs] [--connection-timeout=#] [--skip-nodegroup=#] [--dry-scp] [--help]\n\n";
print STDERR "\tusername is a user that you can use to ssh into\n";
print STDERR "\t all of your nodes with.\n\n";
print STDERR "\t--fs means include the filesystems in the report\n";
print STDERR "\t WARNING: This may require a lot of disk space.\n";
print STDERR "\t Only use this option when asked to.\n\n";
print STDERR "\t--connection-timeout is the timeout in seconds\n";
print STDERR "\t to connect to a node\n\n";
print STDERR "\t--skip-nodegroup allows you to skip all the nodes\n";
print STDERR "\t belonging to a specific nodegroup\n\n";
print STDERR "\t--dry-scp allows running the script for testing without\n";
print STDERR "\t scp from the remote hosts\n\n";
print STDERR "\t--help prints this message and exits\n\n";
exit(1);
}
my $config_get_fs= 0;
my $config_connect_timeout;
my @config_skip_nodegroups;
my $config_dry_scp= 0;
my $config_help= 0;
my %options= (
"--fs" => \$config_get_fs,
"--connection-timeout=i" => \$config_connect_timeout,
"--skip-nodegroup=i@" => \@config_skip_nodegroups,
"--dry-scp" => \$config_dry_scp,
"--help|usage|?" => \$config_help,
);
GetOptions(%options) or usage();
# If --help provided, print usage and exit
if($config_help)
{
print STDERR "This program creates an archive from data node and management node files.\n\n";
usage();
}
# At least one positional argument must be given
# but never more than 2
if(@ARGV < 1 || @ARGV > 2)
{
usage();
}
# First positional argument is name of the config file
my $config_file= $ARGV[0];
if(!stat($config_file))
{
print STDERR "Cannot open configuration file.\n\n";
usage();
}
# Second positional argument may contain scp username
my $config_scp_user= '';
if(defined($ARGV[1]))
{
$config_scp_user.= $ARGV[1].'@';
}
use File::Basename;
my $dirname= dirname(__FILE__);
my $ndb_config= "$dirname/ndb_config";
my $config_query = "$ndb_config --config-file=$config_file --nodes --query=nodeid ";
my $ndbd_query_cmd = "$config_query --type=ndbd";
my $mgmd_query_cmd = "$config_query --type=ndb_mgmd";
# Check config parsing sanity with dry-run
if (system("$ndbd_query_cmd > /dev/null") != 0 ||
system("$mgmd_query_cmd > /dev/null") != 0)
{
print STDERR "Configuration file parsing failed.\n\n";
exit(1);
}
my @nodes= split ' ',`$ndbd_query_cmd`;
my $ndbd_count = @nodes;
push @nodes, split ' ',`$mgmd_query_cmd`;
my $mgmd_count = @nodes - $ndbd_count;
if($ndbd_count == 0 ||
$mgmd_count == 0)
{
print STDERR "Error extracting mgmd and data node ids from config file.";
exit(1);
}
sub config {
my $nodeid= shift;
my $query= shift;
my $res= `$ndb_config --config-file=$config_file --nodeid=$nodeid --query=$query`;
chomp $res;
$res;
}
my @t= localtime();
my $reportdir= sprintf('ndb_error_report_%u%02u%02u%02u%02u%02u',
($t[5]+1900),($t[4]+1),$t[3],$t[2],$t[1],$t[0]);
if(stat($reportdir) || stat($reportdir.'tar.bz2'))
{
print STDERR "It looks like another ndb_error_report process is running.\n";
print STDERR "If that is not the case, remove the ndb_error_report directory";
print STDERR " and run ndb_error_report again.\n\n";
exit(1);
}
mkdir($reportdir);
sub scp
{
my ($host, $from_dir, $to_dir, $recurse) = @_;
my $scp_options = '';
$scp_options .= ' -p '; # Preserve times from original
if (defined($config_connect_timeout))
{
$scp_options .= " -o ConnectTimeout=$config_connect_timeout ";
}
if ($recurse)
{
$scp_options .= ' -r ';
}
my $cmd = "scp $scp_options $config_scp_user$host:$from_dir $to_dir";
if ($config_dry_scp)
{
# --dry-scp just prints the scp command
print $cmd, "\n";
return;
}
system($cmd);
}
sub skip_nodegroup
{
my $nodegroup= shift;
foreach my $skip_nodegroup(@config_skip_nodegroups)
{
if($nodegroup eq $skip_nodegroup)
{
return 1;
}
}
return 0;
}
foreach my $node (@nodes)
{
my $nodegroup= config($node, 'nodegroup');
if(skip_nodegroup($nodegroup))
{
print("\n\n Node $node belongs to nodegroup $nodegroup: skipping.");
next;
}
print "\n\n Copying data from node $node".
(($config_get_fs)?" with filesystem":"").
"\n\n";
my $from_path = "ndb_$node*"; # Copy everything starting with ndb_<nodeid>
my $datadir = config($node,'datadir');
if ($datadir)
{
# Prepend datadir
$from_path = "$datadir/$from_path";
}
scp(config($node,'host'), $from_path,
"$reportdir/", $config_get_fs);
# Extract cluster log name from LogDestination(if any)
foreach my $file_handler (grep(s/^FILE://i, split(/;/, config($node, 'LogDestination'))))
{
foreach my $file_name (grep(s/^filename=//i, split(/,/, $file_handler)))
{
# Check whether the file has an absolute path - otherwise the file
# will be located in $datadir
if (substr($file_name, 0, 1) ne '/')
{
$file_name = $datadir.'/'.$file_name;
}
print " Copying cluster log from '$file_name' on node $node...\n";
scp(config($node,'host'),
"$file_name*",
"$reportdir/", 0);
}
}
}
print "\n\n Copying configuration file...\n\n\t$config_file\n\n";
system "cp -p $config_file $reportdir/";
my $r = system 'bzip2 2>&1 > /dev/null < /dev/null';
my $outfile;
if($r==0)
{
$outfile= "$reportdir.tar.bz2";
system "tar cf - $reportdir|bzip2 > $outfile";
}
else
{
$outfile= "$reportdir.tar.gz";
system "tar cf - $reportdir|gzip > $outfile";
}
system "rm -rf $reportdir";
print "\n\nPlease attach $outfile to your error report\n\n";