mirror of
https://github.com/MariaDB/server.git
synced 2025-07-08 17:02:21 +03:00
319 lines
7.2 KiB
Perl
319 lines
7.2 KiB
Perl
package NDB::Net::NodeMgmt;
|
|
|
|
use strict;
|
|
use Carp;
|
|
use Symbol;
|
|
|
|
require NDB::Net::Node;
|
|
|
|
use vars qw(@ISA);
|
|
@ISA = qw(NDB::Net::Node);
|
|
|
|
# constructors
|
|
|
|
my $log;
|
|
|
|
sub initmodule {
|
|
$log = NDB::Util::Log->instance;
|
|
}
|
|
|
|
NDB::Net::NodeMgmt->attributes(
|
|
port => sub { s/^\s+|\s+$//g; /^\d+$/ },
|
|
);
|
|
|
|
sub new {
|
|
my $class = shift;
|
|
@_ % 2 == 0 or confess 0+@_;
|
|
my(%attr) = @_;
|
|
my $node = $class->SUPER::new(%attr, type => 'mgmt')
|
|
or $log->push, return undef;
|
|
$node->setport($attr{port})
|
|
or $log->push, return undef;
|
|
return 1;
|
|
}
|
|
|
|
# socket parser methods
|
|
|
|
sub socketcommand {
|
|
my $node = shift;
|
|
my $socket;
|
|
$socket = NDB::Util::SocketINET->new or
|
|
$log->push($node), return undef;
|
|
$socket->settimeout(10);
|
|
$socket->connect($node->getserver->getcanon, $node->getport) or
|
|
$log->push($node), return undef;
|
|
$socket->write("GET STATUS\r\nBYE\r\n") or
|
|
$log->push($node), return undef;
|
|
my $out = "";
|
|
my $data;
|
|
while ($data = $socket->read) {
|
|
$out .= $data;
|
|
}
|
|
$socket->close;
|
|
$out =~ s/\015//g;
|
|
return $out;
|
|
}
|
|
|
|
sub get_status {
|
|
my $node = shift;
|
|
my $out = $node->socketcommand or
|
|
$log->push, return undef;
|
|
my @out = split(/\n/, $out);
|
|
$out[0] =~ /^get\s+status\s+(\d+)/i or
|
|
$log->put("bad line 0: $out[0]"), return undef;
|
|
my $cnt = $1;
|
|
my $ret = {};
|
|
for (my $i = 1; $i <= $cnt; $i++) {
|
|
$out[$i] =~ /^$i\s+(.*)/ or
|
|
$log->put("bad line $i: $out[$i]"), return undef;
|
|
my $text = $1;
|
|
$text =~ s/^\s+|\s+$//g;
|
|
if ($text =~ /^ndb\s+(no_contact)\s+(\d+)$/i) {
|
|
$text = lc "$1";
|
|
} elsif ($text =~ /^ndb\s+(starting)\s+(\d+)$/i) {
|
|
$text = lc "$1/$2";
|
|
} elsif ($text =~ /^ndb\s+(started)\s+(\d+)$/i) {
|
|
$text = lc "$1";
|
|
} elsif ($text =~ /^ndb\s+(shutting_down)\s+(\d+)$/i) {
|
|
$text = lc "$1";
|
|
} elsif ($text =~ /^ndb\s+(restarting)\s+(\d+)$/i) {
|
|
$text = lc "$1";
|
|
} elsif ($text =~ /^ndb\s+(unknown)\s+(\d+)$/i) {
|
|
$text = lc "$1";
|
|
}
|
|
$ret->{node}{$i} = $text;
|
|
}
|
|
return $ret;
|
|
}
|
|
|
|
# run methods
|
|
|
|
sub getautoinifile {
|
|
my $node = shift;
|
|
@_ == 0 or confess 0+@_;
|
|
my $name = "config.txt";
|
|
my $file = $node->getnodedir->getfile($name);
|
|
return $file;
|
|
}
|
|
|
|
sub writeautoinifile {
|
|
my $node = shift;
|
|
@_ == 1 or confess 0+@_;
|
|
my($opts) = @_;
|
|
my $db = $node->getdb;
|
|
my $nodelist = $db->getnodelist('all');
|
|
my $computers = {};
|
|
for my $n (@$nodelist) {
|
|
$computers->{$n->getserver->getid} ||= {
|
|
id => $n->getserver->getid,
|
|
hostname => $n->getserver->getcanon,
|
|
};
|
|
}
|
|
my $section = ""; # e.g. PROCESSES
|
|
my $auto;
|
|
my $edit = sub {
|
|
chomp;
|
|
s/^\s+|\s+$//g;
|
|
if (/^(\w+)$/) {
|
|
$section = uc($1);
|
|
}
|
|
elsif (/^\@loop$/i) {
|
|
$_ = "#$_";
|
|
if ($auto) {
|
|
$log->put("nested \@loop");
|
|
return undef;
|
|
}
|
|
$auto = {};
|
|
}
|
|
elsif (/^\@base\s+(\S+)\s*$/) {
|
|
my $arg = $1;
|
|
$_ = "#$_";
|
|
if (! $auto) {
|
|
$log->put("unexpected \@base");
|
|
return undef;
|
|
}
|
|
if ($arg !~ /^\d+$/) {
|
|
$log->put("non-numerical \@base");
|
|
return undef;
|
|
}
|
|
$auto->{base} = $arg;
|
|
}
|
|
elsif (/^\@end$/i) {
|
|
$_ = "#$_";
|
|
if (! $auto) {
|
|
$log->put("unmatched \@end");
|
|
return undef;
|
|
}
|
|
if ($section eq 'COMPUTERS') {
|
|
for my $id (sort { $a <=> $b } keys %$computers) {
|
|
my $computer = $computers->{$id};
|
|
$_ .= "\n";
|
|
$_ .= "\nId: " . $computer->{id};
|
|
$_ .= "\nHostName: " . $computer->{hostname};
|
|
if ($auto->{list}) {
|
|
$_ .= "\n#defaults";
|
|
for my $s (@{$auto->{list}}) {
|
|
$_ .= "\n$s";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
elsif ($section eq 'PROCESSES') {
|
|
for my $n (@$nodelist) {
|
|
if ($auto->{type} && $n->gettype ne lc($auto->{type})) {
|
|
next;
|
|
}
|
|
$_ .= "\n";
|
|
$_ .= "\nType: " . uc($n->gettype);
|
|
$_ .= "\nId: " . $n->getid;
|
|
$_ .= "\nExecuteOnComputer: " . $n->getserver->getid;
|
|
if ($auto->{list}) {
|
|
$_ .= "\n#defaults";
|
|
for my $s (@{$auto->{list}}) {
|
|
$_ .= "\n$s";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
elsif ($section eq 'CONNECTIONS') {
|
|
if (! $auto->{type}) {
|
|
$log->put("cannot generate CONNECTIONS without type");
|
|
return undef;
|
|
}
|
|
if (! defined($auto->{base})) {
|
|
$log->put("need \@base for CONNECTIONS");
|
|
return undef;
|
|
}
|
|
my $key = $auto->{base};
|
|
for (my $i1 = 0; $i1 <= $#$nodelist; $i1++) {
|
|
for (my $i2 = $i1+1; $i2 <= $#$nodelist; $i2++) {
|
|
my $n1 = $nodelist->[$i1];
|
|
my $n2 = $nodelist->[$i2];
|
|
if ($n1->gettype ne 'db' && $n2->gettype ne 'db') {
|
|
next;
|
|
}
|
|
$_ .= "\n";
|
|
$_ .= "\nType: $auto->{type}";
|
|
$_ .= "\nProcessId1: " . $n1->getid;
|
|
$_ .= "\nProcessId2: " . $n2->getid;
|
|
$key++;
|
|
if ($auto->{type} eq 'TCP') {
|
|
$_ .= "\nPortNumber: $key";
|
|
if (my $list = $opts->{proxy}) {
|
|
my $id1 = $n1->getid;
|
|
my $id2 = $n2->getid;
|
|
if ($list =~ /\b$id1\b.*-.*\b$id2\b/) {
|
|
$key++;
|
|
$_ .= "\nProxy: $key";
|
|
} elsif ($list =~ /\b$id2\b.*-.*\b$id1\b/) {
|
|
$key++;
|
|
$_ .= "\nProxy: $key";
|
|
}
|
|
}
|
|
}
|
|
elsif ($auto->{type} eq 'SHM') {
|
|
$_ .= "\nShmKey: $key";
|
|
}
|
|
else {
|
|
$log->put("cannot handle CONNECTIONS type $auto->{type}");
|
|
return undef;
|
|
}
|
|
if ($auto->{list}) {
|
|
$_ .= "\n#defaults";
|
|
for my $s (@{$auto->{list}}) {
|
|
$_ .= "\n$s";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
$log->put("found \@end in unknown section '$section'");
|
|
return undef;
|
|
}
|
|
undef $auto;
|
|
}
|
|
elsif (/^$/) {
|
|
}
|
|
elsif ($auto) {
|
|
if (/^Type:\s*(\w+)$/i) {
|
|
$auto->{type} = uc($1);
|
|
}
|
|
else {
|
|
$auto->{list} ||= [];
|
|
push(@{$auto->{list}}, $_);
|
|
}
|
|
$_ = "";
|
|
return 1; # no output
|
|
}
|
|
$_ .= "\n";
|
|
return 1;
|
|
};
|
|
$node->getautoinifile->mkdir
|
|
or $log->push, return undef;
|
|
$node->getinifile->copyedit($node->getautoinifile, $edit)
|
|
or $log->push, return undef;
|
|
return 1;
|
|
}
|
|
|
|
sub handleprepare {
|
|
my $node = shift;
|
|
@_ == 1 or confess 0+@_;
|
|
my($opts) = @_;
|
|
my $envdefs = $node->getenvdefs($opts);
|
|
defined($envdefs) or return undef;
|
|
my $nodedir = $node->getnodedir;
|
|
my $shellfile = $node->getshellfile;
|
|
my $port = $node->getport;
|
|
my $lpath = $node->getlocalcfg->getbasename;
|
|
$node->writeautoinifile($opts)
|
|
or $log->push, return undef;
|
|
my $ipath = $node->getautoinifile->getbasename;
|
|
$node->getbincfg->mkdir or $log->push, return undef;
|
|
my $cpath = $node->getbincfg->getbasename;
|
|
my $run;
|
|
if ($^O ne 'MSWin32') {
|
|
$run = "\$NDB_TOP/bin/mgmtsrvr";
|
|
} else {
|
|
$run = "mgmtsrvr";
|
|
}
|
|
my $statport = $port + 1;
|
|
$run .= " -l $lpath -c $ipath";
|
|
if ($node->hasrun) {
|
|
$run = $node->getrun;
|
|
}
|
|
if (defined($opts->{run})) {
|
|
$run = $opts->{run};
|
|
}
|
|
$log->put("run: $run")->push($node)->user;
|
|
if ($^O ne 'MSWin32') {
|
|
$shellfile->puttext(<<END) or $log->push, return undef;
|
|
$envdefs
|
|
cd @{[ $nodedir->getpath ]} || exit 1
|
|
set -x
|
|
exec \$DEBUGGER $run
|
|
END
|
|
} else {
|
|
$shellfile->puttext(<<END) or $log->push, return undef;
|
|
$envdefs
|
|
cd @{[ $nodedir->getpath ]}
|
|
call $run
|
|
END
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
sub cmd_stopnode_fg {
|
|
my $node = shift;
|
|
@_ == 1 or confess 0+@_;
|
|
my($cmd) = @_;
|
|
$log->put("write: quit")->push($node)->user;
|
|
$node->getiow->write("quit\n");
|
|
$node->setstate('stop')
|
|
or log->push($node), return undef;
|
|
return 1;
|
|
}
|
|
|
|
1;
|
|
# vim:set sw=4:
|