mirror of
https://github.com/percona/percona-toolkit.git
synced 2025-09-12 06:00:14 +00:00
Change start_services() to run_services() and make it do triple duty: start, restart, and stop. When a real service is removed, call its stop- meta-service before write_services(). Add run_services_once() for services with the run_once flag.
This commit is contained in:
195
bin/pt-agent
195
bin/pt-agent
@@ -4756,7 +4756,6 @@ use Percona::WebAPI::Resource::Agent;
|
|||||||
use Percona::WebAPI::Resource::Config;
|
use Percona::WebAPI::Resource::Config;
|
||||||
use Percona::WebAPI::Resource::Service;
|
use Percona::WebAPI::Resource::Service;
|
||||||
use Percona::WebAPI::Representation;
|
use Percona::WebAPI::Representation;
|
||||||
use Percona::WebAPI::Util;
|
|
||||||
|
|
||||||
Percona::Toolkit->import(qw(_d Dumper have_required_args));
|
Percona::Toolkit->import(qw(_d Dumper have_required_args));
|
||||||
Percona::WebAPI::Representation->import(qw(as_json as_config));
|
Percona::WebAPI::Representation->import(qw(as_json as_config));
|
||||||
@@ -5621,36 +5620,60 @@ sub get_services {
|
|||||||
curr_services => $curr_services,
|
curr_services => $curr_services,
|
||||||
);
|
);
|
||||||
|
|
||||||
# First, save each service in --lib/services/. This must
|
# First, stop and remove services. Do this before write_services()
|
||||||
# be done before calling start_services() because that sub
|
# because this call looks for --lib/services/stop-service which
|
||||||
# looks for --lib/services/start-service, etc.
|
# write_services() removes. I.e. use the service's stop- meta
|
||||||
|
# counterpart (if any) before we remove the service.
|
||||||
|
run_services(
|
||||||
|
action => 'stop',
|
||||||
|
services => $sorted_services->{removed},
|
||||||
|
lib_dir => $lib_dir,
|
||||||
|
bin_dir => $args{bin_dir}, # optional, for testing
|
||||||
|
);
|
||||||
|
|
||||||
|
# Second, save each service in --lib/services/. Do this before
|
||||||
|
# the next calls to run_services() because those calls look for
|
||||||
|
# --lib/services/start-service which won't exist for new services
|
||||||
|
# until written by this call.
|
||||||
write_services(
|
write_services(
|
||||||
sorted_services => $sorted_services,
|
sorted_services => $sorted_services,
|
||||||
lib_dir => $lib_dir,
|
lib_dir => $lib_dir,
|
||||||
json => $args{json}, # optional, for testing
|
json => $args{json}, # optional, for testing
|
||||||
);
|
);
|
||||||
|
|
||||||
# Start and restart services. This must be done before calling
|
# Start new services and restart existing updated services.
|
||||||
# schedule_services() so that, for example, start-query-history
|
# Do this before calling schedule_services() so that, for example,
|
||||||
# is ran before query-history is scheduled and starts running.
|
# start-query-history is ran before query-history is scheduled
|
||||||
|
# and starts running.
|
||||||
|
|
||||||
# Start new services.
|
# Start new services.
|
||||||
# TODO: this probably can't/won't fail, but if it does, is it
|
# TODO: this probably can't/won't fail, but if it does, is it
|
||||||
# worth setting success=0?
|
# worth setting success=0?
|
||||||
start_services(
|
run_services(
|
||||||
|
action => 'start',
|
||||||
services => $sorted_services->{added},
|
services => $sorted_services->{added},
|
||||||
lib_dir => $lib_dir,
|
lib_dir => $lib_dir,
|
||||||
bin_dir => $args{bin_dir}, # optional, for testing
|
bin_dir => $args{bin_dir}, # optional, for testing
|
||||||
);
|
);
|
||||||
|
|
||||||
# Restart existing, re-configured services.
|
# Restart existing updated services.
|
||||||
start_services(
|
run_services(
|
||||||
restart => 1,
|
action => 'restart',
|
||||||
services => $sorted_services->{updated},
|
services => $sorted_services->{updated},
|
||||||
lib_dir => $lib_dir,
|
lib_dir => $lib_dir,
|
||||||
bin_dir => $args{bin_dir}, # optional, for testing
|
bin_dir => $args{bin_dir}, # optional, for testing
|
||||||
);
|
);
|
||||||
|
|
||||||
|
# Run services with the run_once flag. Unlike run_services(),
|
||||||
|
# this call runs the service directly, whether it's meta or not,
|
||||||
|
# then it removes it from the services hashref so there's no
|
||||||
|
# chance of running it again unless it's received again.
|
||||||
|
run_services_once(
|
||||||
|
services => $sorted_services->{services},
|
||||||
|
lib_dir => $lib_dir,
|
||||||
|
bin_dir => $args{bin_dir}, # optional, for testing
|
||||||
|
);
|
||||||
|
|
||||||
# Schedule any services with a run_schedule or spool_schedule.
|
# Schedule any services with a run_schedule or spool_schedule.
|
||||||
# This must be called last, after write_services() and
|
# This must be called last, after write_services() and
|
||||||
# start_services() because, for example, a service schedule
|
# start_services() because, for example, a service schedule
|
||||||
@@ -5698,6 +5721,11 @@ sub sort_services {
|
|||||||
my $name = $service->name;
|
my $name = $service->name;
|
||||||
$services->{$name} = $service;
|
$services->{$name} = $service;
|
||||||
|
|
||||||
|
# run_services() only needs real services, from which it can infer
|
||||||
|
# certain meta-services like "start-foo" for real service "foo",
|
||||||
|
# but write_services() needs meta-services too so it can know to
|
||||||
|
# remove their files from --lib/services/.
|
||||||
|
|
||||||
if ( !exists $prev_services->{$name} ) {
|
if ( !exists $prev_services->{$name} ) {
|
||||||
push @added, $service;
|
push @added, $service;
|
||||||
}
|
}
|
||||||
@@ -5866,7 +5894,87 @@ sub make_new_crontab {
|
|||||||
# from the real service's name. A service doesn't require meta-services;
|
# from the real service's name. A service doesn't require meta-services;
|
||||||
# there may be nothing to do to start it, in which case the real service
|
# there may be nothing to do to start it, in which case the real service
|
||||||
# starts running due to its run_schedule and schedule_services().
|
# starts running due to its run_schedule and schedule_services().
|
||||||
sub start_services {
|
sub run_services {
|
||||||
|
my (%args) = @_;
|
||||||
|
have_required_args(\%args, qw(
|
||||||
|
action
|
||||||
|
services
|
||||||
|
lib_dir
|
||||||
|
)) or die;
|
||||||
|
my $action = $args{action};
|
||||||
|
my $services = $args{services};
|
||||||
|
my $lib_dir = $args{lib_dir};
|
||||||
|
|
||||||
|
# Optional args
|
||||||
|
my $bin_dir = defined $args{bin_dir} ? $args{bin_dir}
|
||||||
|
: "$FindBin::Bin/";
|
||||||
|
my $exec_cmd = $args{exec_cmd} || sub { return system(@_) };
|
||||||
|
|
||||||
|
my $env_vars = env_vars();
|
||||||
|
my $log = "$lib_dir/logs/start-stop.log";
|
||||||
|
my $cmd_fmt = ($env_vars ? "$env_vars " : '')
|
||||||
|
. $bin_dir . "pt-agent --run-service %s >> $log 2>&1";
|
||||||
|
|
||||||
|
SERVICE:
|
||||||
|
foreach my $service ( @$services ) {
|
||||||
|
next if $service->meta; # only real services
|
||||||
|
|
||||||
|
my $name = $service->name;
|
||||||
|
|
||||||
|
# To restart, one must first stop, then start afterwards.
|
||||||
|
if ( $action eq 'stop' || $action eq 'restart' ) {
|
||||||
|
if ( -f "$lib_dir/services/stop-$name" ) {
|
||||||
|
my $cmd = sprintf $cmd_fmt, "stop-$name";
|
||||||
|
_info("Stopping $name: $cmd");
|
||||||
|
$exec_cmd->($cmd);
|
||||||
|
my $cmd_exit_status = $CHILD_ERROR >> 8;
|
||||||
|
if ( $cmd_exit_status != 0 ) {
|
||||||
|
_warn("Error stopping $name, check $log and "
|
||||||
|
. "$lib_dir/logs/$name.run");
|
||||||
|
next SERVICE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $action eq 'start' || $action eq 'restart' ) {
|
||||||
|
# Remove old meta files. Meta files are generally temporary
|
||||||
|
# in any case, persisting info from one interval to the next.
|
||||||
|
# If the service has changed (e.g., report interval is longer),
|
||||||
|
# there's no easy way to tranistion from old metadata to new,
|
||||||
|
# so we just rm the old metadata and start anew.
|
||||||
|
my $meta_files = "$lib_dir/meta/$name*";
|
||||||
|
foreach my $meta_file ( glob $meta_files ) {
|
||||||
|
if ( unlink $meta_file ) {
|
||||||
|
_info("Removed $meta_file");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_warn("Cannot remove $meta_file: $OS_ERROR");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Start the service and wait for it to exit. If it dies
|
||||||
|
# really early (before it really begins), our log file will
|
||||||
|
# have the error; else, the service should automatically
|
||||||
|
# switch to its default log file ending in ".run".
|
||||||
|
if ( -f "$lib_dir/services/start-$name" ) {
|
||||||
|
my $cmd = sprintf $cmd_fmt, "start-$name";
|
||||||
|
_info("Starting $name: $cmd");
|
||||||
|
$exec_cmd->($cmd);
|
||||||
|
my $cmd_exit_status = $CHILD_ERROR >> 8;
|
||||||
|
if ( $cmd_exit_status != 0 ) {
|
||||||
|
_warn("Error starting $name, check $log and "
|
||||||
|
."$lib_dir/logs/$name.run");
|
||||||
|
next SERVICE;
|
||||||
|
}
|
||||||
|
_info("Started $name successfully");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub run_services_once {
|
||||||
my (%args) = @_;
|
my (%args) = @_;
|
||||||
have_required_args(\%args, qw(
|
have_required_args(\%args, qw(
|
||||||
services
|
services
|
||||||
@@ -5882,62 +5990,27 @@ sub start_services {
|
|||||||
my $exec_cmd = $args{exec_cmd} || sub { return system(@_) };
|
my $exec_cmd = $args{exec_cmd} || sub { return system(@_) };
|
||||||
|
|
||||||
my $env_vars = env_vars();
|
my $env_vars = env_vars();
|
||||||
my $log = "$lib_dir/logs/start.log";
|
my $log = "$lib_dir/logs/run-once.log";
|
||||||
my $cmd_fmt = ($env_vars ? "$env_vars " : '')
|
my $cmd_fmt = ($env_vars ? "$env_vars " : '')
|
||||||
. $bin_dir . "pt-agent --run-service %s >> $log 2>&1";
|
. $bin_dir . "pt-agent --run-service %s >> $log 2>&1";
|
||||||
|
|
||||||
SERVICE:
|
SERVICE:
|
||||||
foreach my $service ( @$services ) {
|
foreach my $name ( sort keys %$services ) {
|
||||||
next if $service->meta; # only real services
|
my $service = $services->{$name};
|
||||||
|
next unless $service->run_once;
|
||||||
|
|
||||||
my $name = $service->name;
|
delete $services->{$name};
|
||||||
|
|
||||||
# To restart, one must first stop, then start afterwards.
|
my $cmd = sprintf $cmd_fmt, "start-$name";
|
||||||
if ( $restart ) {
|
_info("Running $name: $cmd");
|
||||||
if ( -f "$lib_dir/services/stop-$name" ) {
|
$exec_cmd->($cmd);
|
||||||
my $cmd = sprintf $cmd_fmt, "stop-$name";
|
my $cmd_exit_status = $CHILD_ERROR >> 8;
|
||||||
_info("Stopping $name: $cmd");
|
if ( $cmd_exit_status != 0 ) {
|
||||||
$exec_cmd->($cmd);
|
_warn("Error starting $name, check $log and "
|
||||||
my $cmd_exit_status = $CHILD_ERROR >> 8;
|
."$lib_dir/logs/$name.run");
|
||||||
if ( $cmd_exit_status != 0 ) {
|
next SERVICE;
|
||||||
_warn("Error stopping $name, check $log and "
|
|
||||||
. "$lib_dir/logs/$name.run");
|
|
||||||
next SERVICE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Remove old meta files. Meta files are generally temporary
|
|
||||||
# in any case, persisting info from one interval to the next.
|
|
||||||
# If the service has changed (e.g., report interval is longer),
|
|
||||||
# there's no easy way to tranistion from old metadata to new,
|
|
||||||
# so we just rm the old metadata and start anew.
|
|
||||||
my $meta_files = "$lib_dir/meta/$name*";
|
|
||||||
foreach my $meta_file ( glob $meta_files ) {
|
|
||||||
if ( unlink $meta_file ) {
|
|
||||||
_info("Removed $meta_file");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_warn("Cannot remove $meta_file: $OS_ERROR");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Start the service and wait for it to exit. If it dies
|
|
||||||
# really early (before it really begins), our log file will
|
|
||||||
# have the error; else, the service should automatically
|
|
||||||
# switch to its default log file ending in ".run".
|
|
||||||
if ( -f "$lib_dir/services/start-$name" ) {
|
|
||||||
my $cmd = sprintf $cmd_fmt, "start-$name";
|
|
||||||
_info("Starting $name: $cmd");
|
|
||||||
$exec_cmd->($cmd);
|
|
||||||
my $cmd_exit_status = $CHILD_ERROR >> 8;
|
|
||||||
if ( $cmd_exit_status != 0 ) {
|
|
||||||
_warn("Error starting $name, check $log and "
|
|
||||||
."$lib_dir/logs/$name.run");
|
|
||||||
next SERVICE;
|
|
||||||
}
|
|
||||||
_info("Started $name successfully");
|
|
||||||
}
|
}
|
||||||
|
_info("Ran $name successfully");
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@@ -36,9 +36,10 @@ my $sample = "t/pt-agent/samples";
|
|||||||
# Create fake spool and lib dirs. Service-related subs in pt-agent
|
# Create fake spool and lib dirs. Service-related subs in pt-agent
|
||||||
# automatically add "/services" to the lib dir, but the spool dir is
|
# automatically add "/services" to the lib dir, but the spool dir is
|
||||||
# used as-is.
|
# used as-is.
|
||||||
my $tmpdir = tempdir("/tmp/pt-agent.$PID.XXXXXX", CLEANUP => 1);
|
my $tmpdir = tempdir("/tmp/pt-agent.$PID.XXXXXX", CLEANUP => 0);
|
||||||
mkdir "$tmpdir/spool" or die "Error making $tmpdir/spool: $OS_ERROR";
|
output(
|
||||||
mkdir "$tmpdir/services" or die "Error making $tmpdir/services: $OS_ERROR";
|
sub { pt_agent::init_lib_dir(lib_dir => $tmpdir) }
|
||||||
|
);
|
||||||
my $spool_dir = "$tmpdir/spool";
|
my $spool_dir = "$tmpdir/spool";
|
||||||
|
|
||||||
sub write_svc_files {
|
sub write_svc_files {
|
||||||
@@ -88,9 +89,10 @@ my $output = output(
|
|||||||
sub {
|
sub {
|
||||||
$exit_status = pt_agent::run_service(
|
$exit_status = pt_agent::run_service(
|
||||||
service => 'query-history',
|
service => 'query-history',
|
||||||
spool_dir => $spool_dir,
|
|
||||||
lib_dir => $tmpdir,
|
lib_dir => $tmpdir,
|
||||||
|
spool_dir => $spool_dir,
|
||||||
Cxn => '',
|
Cxn => '',
|
||||||
|
suffix => '', # optional, for testing
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
stderr => 1,
|
stderr => 1,
|
||||||
@@ -98,11 +100,11 @@ my $output = output(
|
|||||||
|
|
||||||
ok(
|
ok(
|
||||||
no_diff(
|
no_diff(
|
||||||
"cat $tmpdir/spool/query-history",
|
"cat $tmpdir/spool/query-history/query-history",
|
||||||
"$sample/query-history/data001.json",
|
"$sample/query-history/data001.json",
|
||||||
),
|
),
|
||||||
"1 run: spool data (query-history/data001.json)"
|
"1 run: spool data (query-history/data001.json)"
|
||||||
);
|
) or diag(`ls -l $tmpdir/spool/`);
|
||||||
|
|
||||||
chomp(my $n_files = `ls -1 $spool_dir | wc -l | awk '{print \$1}'`);
|
chomp(my $n_files = `ls -1 $spool_dir | wc -l | awk '{print \$1}'`);
|
||||||
is(
|
is(
|
||||||
@@ -116,7 +118,7 @@ is(
|
|||||||
0,
|
0,
|
||||||
"1 run: exit 0"
|
"1 run: exit 0"
|
||||||
);
|
);
|
||||||
|
exit;
|
||||||
# #############################################################################
|
# #############################################################################
|
||||||
# Service with two task, both using a program.
|
# Service with two task, both using a program.
|
||||||
# #############################################################################
|
# #############################################################################
|
||||||
@@ -162,6 +164,7 @@ $output = output(
|
|||||||
spool_dir => $spool_dir,
|
spool_dir => $spool_dir,
|
||||||
lib_dir => $tmpdir,
|
lib_dir => $tmpdir,
|
||||||
Cxn => '',
|
Cxn => '',
|
||||||
|
suffix => '', # optional, for testing
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
stderr => 1,
|
stderr => 1,
|
||||||
@@ -291,6 +294,7 @@ SKIP: {
|
|||||||
spool_dir => $spool_dir,
|
spool_dir => $spool_dir,
|
||||||
lib_dir => $tmpdir,
|
lib_dir => $tmpdir,
|
||||||
Cxn => $cxn,
|
Cxn => $cxn,
|
||||||
|
suffix => '', # optional, for testing
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
stderr => 1,
|
stderr => 1,
|
||||||
@@ -318,6 +322,7 @@ SKIP: {
|
|||||||
spool_dir => $spool_dir,
|
spool_dir => $spool_dir,
|
||||||
lib_dir => $tmpdir,
|
lib_dir => $tmpdir,
|
||||||
Cxn => $cxn,
|
Cxn => $cxn,
|
||||||
|
suffix => '', # optional, for testing
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
stderr => 1,
|
stderr => 1,
|
||||||
@@ -341,6 +346,7 @@ SKIP: {
|
|||||||
spool_dir => $spool_dir,
|
spool_dir => $spool_dir,
|
||||||
lib_dir => $tmpdir,
|
lib_dir => $tmpdir,
|
||||||
Cxn => $cxn,
|
Cxn => $cxn,
|
||||||
|
suffix => '', # optional, for testing
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
stderr => 1,
|
stderr => 1,
|
||||||
|
Reference in New Issue
Block a user