mirror of
https://github.com/percona/percona-toolkit.git
synced 2025-10-21 18:24:38 +00:00
Validate --max|critical-load early and strongly, and check that the var exists and is defined.
This commit is contained in:
@@ -3701,18 +3701,24 @@ sub new {
|
||||
}
|
||||
|
||||
PTDEBUG && _d('Parsing spec for max thresholds');
|
||||
my $max_val_for = _parse_spec(
|
||||
spec => $args{max_spec},
|
||||
get_status => $args{get_status},
|
||||
threshold_factor => 0.2, # +20%
|
||||
);
|
||||
my $max_val_for = _parse_spec($args{max_spec});
|
||||
if ( $max_val_for ) {
|
||||
_check_and_set_vals(
|
||||
vars => $max_val_for,
|
||||
get_status => $args{get_status},
|
||||
threshold_factor => 0.2, # +20%
|
||||
);
|
||||
}
|
||||
|
||||
PTDEBUG && _d('Parsing spec for critical thresholds');
|
||||
my $critical_val_for = _parse_spec(
|
||||
spec => $args{critical_spec} || [],
|
||||
get_status => $args{get_status},
|
||||
threshold_factor => 1.0, # double (x2; +100%)
|
||||
);
|
||||
my $critical_val_for = _parse_spec($args{critical_spec} || []);
|
||||
if ( $critical_val_for ) {
|
||||
_check_and_set_vals(
|
||||
vars => $critical_val_for,
|
||||
get_status => $args{get_status},
|
||||
threshold_factor => 1.0, # double (x2; +100%)
|
||||
);
|
||||
}
|
||||
|
||||
my $self = {
|
||||
get_status => $args{get_status},
|
||||
@@ -3726,27 +3732,29 @@ sub new {
|
||||
}
|
||||
|
||||
sub _parse_spec {
|
||||
my ( %args ) = @_;
|
||||
my @required_args = qw(spec get_status);
|
||||
foreach my $arg ( @required_args ) {
|
||||
die "I need a $arg argument" unless defined $args{$arg};
|
||||
}
|
||||
my ($spec, $get_status) = @args{@required_args};
|
||||
my ($spec) = @_;
|
||||
|
||||
return unless $spec && scalar @$spec;
|
||||
my $threshold_factor = $args{threshold_factor} || 0.20;
|
||||
|
||||
my %max_val_for;
|
||||
foreach my $var_val ( @$spec ) {
|
||||
die "Empty or undefined spec\n" unless $var_val;
|
||||
$var_val =~ s/^\s+//;
|
||||
$var_val =~ s/\s+$//g;
|
||||
|
||||
my ($var, $val) = split /[:=]/, $var_val;
|
||||
die "Invalid spec: $var_val" unless $var;
|
||||
die "$var_val does not contain a variable\n" unless $var;
|
||||
die "$var is not a variable name\n" unless $var =~ m/^[a-zA-Z_]+$/;
|
||||
|
||||
if ( !$val ) {
|
||||
my $init_val = $get_status->($var);
|
||||
PTDEBUG && _d('Initial', $var, 'value:', $init_val);
|
||||
$val = int(($init_val * $threshold_factor) + $init_val);
|
||||
PTDEBUG && _d('Will get intial value for', $var, 'later');
|
||||
$max_val_for{$var} = undef;
|
||||
}
|
||||
else {
|
||||
die "The value for $var must be a number\n"
|
||||
unless $val =~ m/^[\d\.]+$/;
|
||||
$max_val_for{$var} = $val;
|
||||
}
|
||||
PTDEBUG && _d('Wait if', $var, '>=', $val);
|
||||
$max_val_for{$var} = $val;
|
||||
}
|
||||
|
||||
return \%max_val_for;
|
||||
@@ -3826,6 +3834,34 @@ sub wait {
|
||||
return;
|
||||
}
|
||||
|
||||
sub _check_and_set_vals {
|
||||
my (%args) = @_;
|
||||
my @required_args = qw(vars get_status threshold_factor);
|
||||
foreach my $arg ( @required_args ) {
|
||||
die "I need a $arg argument" unless defined $args{$arg};
|
||||
}
|
||||
my ($vars, $get_status, $threshold_factor) = @args{@required_args};
|
||||
|
||||
PTDEBUG && _d('Checking and setting values');
|
||||
return unless $vars && scalar %$vars;
|
||||
|
||||
foreach my $var ( keys %$vars ) {
|
||||
my $init_val = $get_status->($var);
|
||||
die "Variable $var does not exist or its value is undefined\n"
|
||||
unless defined $init_val;
|
||||
my $val;
|
||||
if ( defined $vars->{$var} ) {
|
||||
$val = $vars->{$var};
|
||||
}
|
||||
else {
|
||||
PTDEBUG && _d('Initial', $var, 'value:', $init_val);
|
||||
$val = int(($init_val * $threshold_factor) + $init_val);
|
||||
$vars->{$var} = $val;
|
||||
}
|
||||
PTDEBUG && _d('Wait if', $var, '>=', $val);
|
||||
}
|
||||
}
|
||||
|
||||
sub _d {
|
||||
my ($package, undef, $line) = caller 0;
|
||||
@_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
|
||||
@@ -4980,12 +5016,14 @@ sub main {
|
||||
$o->set('chunk-time', 0) if $o->got('chunk-size');
|
||||
|
||||
foreach my $opt ( qw(max-load critical-load) ) {
|
||||
next unless $o->has($opt);
|
||||
my $spec = $o->get($opt);
|
||||
eval {
|
||||
MySQLStatusWaiter::_parse_spec($o->get($spec));
|
||||
MySQLStatusWaiter::_parse_spec($o->get($opt));
|
||||
};
|
||||
if ( $EVAL_ERROR ) {
|
||||
$o->save_error("Invalid --$opt: $spec");
|
||||
chomp $EVAL_ERROR;
|
||||
$o->save_error("Invalid --$opt: $EVAL_ERROR");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5236,13 +5274,25 @@ sub main {
|
||||
};
|
||||
}
|
||||
|
||||
$sys_load = new MySQLStatusWaiter(
|
||||
max_spec => $o->get('max-load'),
|
||||
critical_spec => $o->get('critical-load'),
|
||||
get_status => $get_status,
|
||||
oktorun => sub { return $oktorun },
|
||||
sleep => $sleep,
|
||||
);
|
||||
eval {
|
||||
$sys_load = new MySQLStatusWaiter(
|
||||
max_spec => $o->get('max-load'),
|
||||
critical_spec => $o->get('critical-load'),
|
||||
get_status => $get_status,
|
||||
oktorun => sub { return $oktorun },
|
||||
sleep => $sleep,
|
||||
);
|
||||
};
|
||||
if ( $EVAL_ERROR ) {
|
||||
chomp $EVAL_ERROR;
|
||||
die "Error checking --max-load or --critial-load: $EVAL_ERROR. "
|
||||
. "Check that the variables specified for --max-load and "
|
||||
. "--critical-load are spelled correctly and exist in "
|
||||
. "SHOW GLOBAL STATUS. Current values for these options are:\n"
|
||||
. " --max-load " . (join(',', @{$o->get('max-load')})) . "\n"
|
||||
. " --critial-load " . (join(',', @{$o->get('critical-load')}))
|
||||
. "\n";
|
||||
}
|
||||
|
||||
if ( $o->get('progress') ) {
|
||||
$replica_lag_pr = new Progress(
|
||||
|
@@ -46,19 +46,23 @@ sub new {
|
||||
|
||||
PTDEBUG && _d('Parsing spec for max thresholds');
|
||||
my $max_val_for = _parse_spec($args{max_spec});
|
||||
_set_initial_vals(
|
||||
vars => $max_val_for,
|
||||
get_status => $args{get_status},
|
||||
threshold_factor => 0.2, # +20%
|
||||
);
|
||||
if ( $max_val_for ) {
|
||||
_check_and_set_vals(
|
||||
vars => $max_val_for,
|
||||
get_status => $args{get_status},
|
||||
threshold_factor => 0.2, # +20%
|
||||
);
|
||||
}
|
||||
|
||||
PTDEBUG && _d('Parsing spec for critical thresholds');
|
||||
my $critical_val_for = _parse_spec($args{critical_spec} || []);
|
||||
_set_initial_vals(
|
||||
vars => $critical_val_for,
|
||||
get_status => $args{get_status},
|
||||
threshold_factor => 1.0, # double (x2; +100%)
|
||||
);
|
||||
if ( $critical_val_for ) {
|
||||
_check_and_set_vals(
|
||||
vars => $critical_val_for,
|
||||
get_status => $args{get_status},
|
||||
threshold_factor => 1.0, # double (x2; +100%)
|
||||
);
|
||||
}
|
||||
|
||||
my $self = {
|
||||
get_status => $args{get_status},
|
||||
@@ -87,15 +91,21 @@ sub _parse_spec {
|
||||
|
||||
my %max_val_for;
|
||||
foreach my $var_val ( @$spec ) {
|
||||
die "Empty or undefined spec\n" unless $var_val;
|
||||
$var_val =~ s/^\s+//;
|
||||
$var_val =~ s/\s+$//g;
|
||||
|
||||
my ($var, $val) = split /[:=]/, $var_val;
|
||||
die "Invalid spec: $var_val" unless $var;
|
||||
die "$var_val does not contain a variable\n" unless $var;
|
||||
die "$var is not a variable name\n" unless $var =~ m/^[a-zA-Z_]+$/;
|
||||
|
||||
if ( !$val ) {
|
||||
PTDEBUG && _d('Will get intial value for', $var, 'later');
|
||||
$max_val_for{$var} = undef;
|
||||
}
|
||||
else {
|
||||
PTDEBUG && _d('Wait if', $var, '>=', $val);
|
||||
die "The value for $var must be a number\n"
|
||||
unless $val =~ m/^[\d\.]+$/;
|
||||
$max_val_for{$var} = $val;
|
||||
}
|
||||
}
|
||||
@@ -190,7 +200,7 @@ sub wait {
|
||||
return;
|
||||
}
|
||||
|
||||
sub _set_initial_vals {
|
||||
sub _check_and_set_vals {
|
||||
my (%args) = @_;
|
||||
my @required_args = qw(vars get_status threshold_factor);
|
||||
foreach my $arg ( @required_args ) {
|
||||
@@ -198,19 +208,22 @@ sub _set_initial_vals {
|
||||
}
|
||||
my ($vars, $get_status, $threshold_factor) = @args{@required_args};
|
||||
|
||||
PTDEBUG && _d('Setting initial values');
|
||||
PTDEBUG && _d('Checking and setting values');
|
||||
return unless $vars && scalar %$vars;
|
||||
|
||||
foreach my $var ( keys %$vars ) {
|
||||
next if defined $vars->{$var};
|
||||
|
||||
my $init_val = $get_status->($var);
|
||||
PTDEBUG && _d('Initial', $var, 'value:', $init_val);
|
||||
die "Variable does not exist or has undefined value: $var"
|
||||
die "Variable $var does not exist or its value is undefined\n"
|
||||
unless defined $init_val;
|
||||
|
||||
my $val = int(($init_val * $threshold_factor) + $init_val);
|
||||
$vars->{$var} = $val;
|
||||
my $val;
|
||||
if ( defined $vars->{$var} ) {
|
||||
$val = $vars->{$var};
|
||||
}
|
||||
else {
|
||||
PTDEBUG && _d('Initial', $var, 'value:', $init_val);
|
||||
$val = int(($init_val * $threshold_factor) + $init_val);
|
||||
$vars->{$var} = $val;
|
||||
}
|
||||
PTDEBUG && _d('Wait if', $var, '>=', $val);
|
||||
}
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@ BEGIN {
|
||||
use strict;
|
||||
use warnings FATAL => 'all';
|
||||
use English qw(-no_match_vars);
|
||||
use Test::More tests => 14;
|
||||
use Test::More tests => 17;
|
||||
|
||||
use MySQLStatusWaiter;
|
||||
use PerconaTest;
|
||||
@@ -45,20 +45,42 @@ sub sleep {
|
||||
|
||||
throws_ok(
|
||||
sub { new MySQLStatusWaiter(
|
||||
max_spec => '100',
|
||||
max_spec => [qw(100)],
|
||||
get_status => \&get_status,
|
||||
sleep => \&sleep,
|
||||
oktorun => \&oktorun,
|
||||
) },
|
||||
qr/Invalid spec/,
|
||||
"Validate max_spec"
|
||||
qr/100 is not a variable name/,
|
||||
"Catch non-variable name"
|
||||
);
|
||||
|
||||
throws_ok(
|
||||
sub { new MySQLStatusWaiter(
|
||||
max_spec => [qw(foo=bar)],
|
||||
get_status => \&get_status,
|
||||
sleep => \&sleep,
|
||||
oktorun => \&oktorun,
|
||||
) },
|
||||
qr/value for foo must be a number/,
|
||||
"Catch non-number value"
|
||||
);
|
||||
|
||||
throws_ok(
|
||||
sub { new MySQLStatusWaiter(
|
||||
max_spec => [qw(foo)],
|
||||
get_status => \&get_status,
|
||||
sleep => \&sleep,
|
||||
oktorun => \&oktorun,
|
||||
) },
|
||||
qr/foo does not exist/,
|
||||
"Catch non-existent variable"
|
||||
);
|
||||
|
||||
# ############################################################################
|
||||
# Use initial vals + 20%.
|
||||
# ############################################################################
|
||||
@vals = (
|
||||
# initial values
|
||||
# initial check for existence
|
||||
{ Threads_connected => 10, },
|
||||
{ Threads_running => 5, },
|
||||
|
||||
@@ -83,6 +105,8 @@ throws_ok(
|
||||
{ Threads_running => 5, },
|
||||
);
|
||||
|
||||
$oktorun = 1;
|
||||
|
||||
my $sw = new MySQLStatusWaiter(
|
||||
oktorun => \&oktorun,
|
||||
get_status => \&get_status,
|
||||
@@ -142,6 +166,10 @@ is(
|
||||
# Use static vals.
|
||||
# ############################################################################
|
||||
@vals = (
|
||||
# initial check for existence
|
||||
{ Threads_connected => 1, },
|
||||
{ Threads_running => 1, },
|
||||
|
||||
# first check, no wait
|
||||
{ Threads_connected => 1, },
|
||||
{ Threads_running => 1, },
|
||||
@@ -223,6 +251,10 @@ is(
|
||||
# Critical thresholds (with static vals).
|
||||
# ############################################################################
|
||||
@vals = (
|
||||
# initial check for existence
|
||||
{ Threads_running => 1, },
|
||||
{ Threads_running => 9, },
|
||||
|
||||
# first check, no wait
|
||||
{ Threads_running => 1, },
|
||||
{ Threads_running => 9, },
|
||||
|
Reference in New Issue
Block a user