mirror of
https://github.com/percona/percona-toolkit.git
synced 2025-09-28 17:15:44 +00:00
Implement and test pt-agent --run-service.
This commit is contained in:
166
bin/pt-agent
166
bin/pt-agent
@@ -4679,6 +4679,7 @@ sub run_agent {
|
||||
# write the new one to disk, then apply it.
|
||||
if ( resource_diff($config, $new_config) ) {
|
||||
_info('New config');
|
||||
|
||||
write_config(
|
||||
config => $new_config,
|
||||
file => $config_file,
|
||||
@@ -4694,9 +4695,10 @@ sub run_agent {
|
||||
|
||||
# Apply new config, i.e. update the current, running config.
|
||||
$config = $new_config;
|
||||
_info('Config updated successfully');
|
||||
}
|
||||
else {
|
||||
_info("Config has not changed");
|
||||
_info('Config has not changed');
|
||||
}
|
||||
};
|
||||
if ( $EVAL_ERROR ) {
|
||||
@@ -4718,18 +4720,24 @@ sub run_agent {
|
||||
# write the new ones to disk, then schedule them.
|
||||
if ( resource_diff($services, $new_services) ) {
|
||||
_info('New services');
|
||||
|
||||
write_services(
|
||||
services => $new_services,
|
||||
lib_dir => $lib_dir,
|
||||
);
|
||||
|
||||
schedule_services(
|
||||
services => $new_services,
|
||||
lib_dir => $lib_dir,
|
||||
);
|
||||
|
||||
$services = $new_services;
|
||||
_info('Services updated successfully: '
|
||||
. join(', ', map { $_->alias . ' (' . $_->name . ')' }
|
||||
@$services));
|
||||
}
|
||||
else {
|
||||
_info("Services have not changed")
|
||||
_info('Services have not changed');
|
||||
}
|
||||
};
|
||||
if ( $EVAL_ERROR ) {
|
||||
@@ -4830,11 +4838,14 @@ sub write_services {
|
||||
_info("Removed $file");
|
||||
}
|
||||
}
|
||||
closedir $dh;
|
||||
closedir $dh
|
||||
or die "Error closing $lib_dir: $OS_ERROR";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
# Write Service->schedule lines to crontab, along with any other
|
||||
# non-pt-agent lines, and load.
|
||||
sub schedule_services {
|
||||
my (%args) = @_;
|
||||
|
||||
@@ -4868,6 +4879,8 @@ sub schedule_services {
|
||||
return;
|
||||
}
|
||||
|
||||
# Combine Service->schedule lines with non-pt-agent lines,
|
||||
# i.e. don't clobber the user's other crontab lines.
|
||||
sub make_new_crontab {
|
||||
my (%args) = @_;
|
||||
|
||||
@@ -4900,6 +4913,140 @@ sub make_new_crontab {
|
||||
# #################### #
|
||||
|
||||
sub run_service {
|
||||
my (%args) = @_;
|
||||
|
||||
have_required_args(\%args, qw(
|
||||
service
|
||||
spool_dir
|
||||
lib_dir
|
||||
)) or die;
|
||||
my $service = $args{service};
|
||||
my $spool_dir = $args{spool_dir};
|
||||
my $lib_dir = $args{lib_dir};
|
||||
|
||||
# TODO: where should this output go?
|
||||
_info("Running $service service");
|
||||
|
||||
$service = load_service(
|
||||
service => $service,
|
||||
lib_dir => $lib_dir,
|
||||
);
|
||||
|
||||
my @output_files;
|
||||
my $final_exit_status = 0;
|
||||
my $spool_file = "$spool_dir/" . $service->name;
|
||||
my $runs = $service->runs;
|
||||
my $runno = 0;
|
||||
foreach my $run ( @$runs ) {
|
||||
|
||||
# Set up the output file, i.e. where this run puts its results.
|
||||
# Runs can access each other's output files. E.g. run0 may
|
||||
# write to fileX, then subsequent runs can access that file
|
||||
# with the special var __RUN_N_OUTPUT__ where N=0.
|
||||
my $output_file;
|
||||
my $output = $run->output;
|
||||
if ( $output eq 'spool' ) {
|
||||
$output_file = $spool_file;
|
||||
push @output_files, $spool_file;
|
||||
}
|
||||
elsif ( $output eq 'tmp' ) {
|
||||
my ($fh, $file) = tempfile();
|
||||
close $fh;
|
||||
$output_file = $file;
|
||||
push @output_files, $file;
|
||||
}
|
||||
elsif ( $output eq 'none' ) {
|
||||
$output_file = '/dev/null';
|
||||
push @output_files, undef;
|
||||
}
|
||||
else {
|
||||
die "Invalid output: $output\n";
|
||||
}
|
||||
|
||||
# Create the full command line to execute, replacing any
|
||||
# special vars like __RUN_N_OUTPUT__, __TMPDIR__, etc.
|
||||
my $cmd = join(' ',
|
||||
$run->program,
|
||||
$run->options,
|
||||
'>',
|
||||
$output_file,
|
||||
);
|
||||
$cmd = replace_special_vars(
|
||||
cmd => $cmd,
|
||||
service => $service,
|
||||
output_files => \@output_files,
|
||||
);
|
||||
_info("Run $runno: $cmd");
|
||||
|
||||
# Execute this run.
|
||||
system($cmd);
|
||||
my $exit_status = $CHILD_ERROR >> 8;
|
||||
_info("Run $runno: exit $exit_status");
|
||||
|
||||
$final_exit_status |= $exit_status;
|
||||
$runno++;
|
||||
}
|
||||
|
||||
# Remove temp output files.
|
||||
foreach my $file ( @output_files ) {
|
||||
next if $file eq $spool_file;
|
||||
unlink $file
|
||||
or _warn("Error removing $file: $OS_ERROR");
|
||||
}
|
||||
|
||||
_info("Done running " . $service->name);
|
||||
|
||||
return $final_exit_status;
|
||||
}
|
||||
|
||||
sub load_service {
|
||||
my (%args) = @_;
|
||||
|
||||
have_required_args(\%args, qw(
|
||||
service
|
||||
lib_dir
|
||||
)) or die;
|
||||
my $service = $args{service};
|
||||
my $lib_dir = $args{lib_dir};
|
||||
|
||||
my $service_file = "$lib_dir/services/$service";
|
||||
if ( ! -f $service_file ) {
|
||||
die "$service_file does not exist.\n";
|
||||
}
|
||||
|
||||
my $service_hash = decode_json(slurp($service_file));
|
||||
my $service_obj = Percona::WebAPI::Resource::Service->new(%$service_hash);
|
||||
|
||||
return $service_obj;
|
||||
}
|
||||
|
||||
sub replace_special_vars {
|
||||
my (%args) = @_;
|
||||
|
||||
have_required_args(\%args, qw(
|
||||
cmd
|
||||
output_files
|
||||
)) or die;
|
||||
my $cmd = $args{cmd};
|
||||
my $output_files = $args{output_files};
|
||||
|
||||
my $new_cmd = join(' ',
|
||||
map {
|
||||
my $word = $_;
|
||||
if ( my ($runno) = $word =~ m/__RUN_(\d)_OUTPUT__/ ) {
|
||||
if ( $output_files->[$runno] ) {
|
||||
$word = $output_files->[$runno];
|
||||
}
|
||||
else {
|
||||
die "Run$runno has no output for $word to access.\n";
|
||||
}
|
||||
}
|
||||
$word;
|
||||
}
|
||||
split(/\s+/, $cmd)
|
||||
);
|
||||
|
||||
return $new_cmd;
|
||||
}
|
||||
|
||||
# ################## #
|
||||
@@ -4940,6 +5087,19 @@ sub init_config_file {
|
||||
return;
|
||||
}
|
||||
|
||||
sub slurp {
|
||||
my ($file) = @_;
|
||||
return unless -f $file;
|
||||
open my $fh, '<', $file
|
||||
or die "Error opening $file: $OS_ERROR";
|
||||
my $data = do {
|
||||
local $INPUT_RECORD_SEPARATOR = undef;
|
||||
<$fh>;
|
||||
};
|
||||
close $fh;
|
||||
return $data;
|
||||
}
|
||||
|
||||
sub _log {
|
||||
my ($level, $msg) = @_;
|
||||
$msg .= "\n" if $msg !~ m/\n$/;
|
||||
|
Reference in New Issue
Block a user