270 lines
6.5 KiB
Perl
270 lines
6.5 KiB
Perl
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
#
|
|
# This Source Code Form is "Incompatible With Secondary Licenses", as
|
|
# defined by the Mozilla Public License, v. 2.0.
|
|
|
|
# XXX In order to support Windows, we have to make gd_redirect_output
|
|
# use Log4Perl or something instead of calling "logger". We probably
|
|
# also need to use Win32::Daemon or something like that to daemonize.
|
|
|
|
package Bugzilla::JobQueue::Runner;
|
|
|
|
use 5.10.1;
|
|
use strict;
|
|
|
|
use Cwd qw(abs_path);
|
|
use File::Basename;
|
|
use File::Copy;
|
|
use Pod::Usage;
|
|
|
|
use Bugzilla::Constants;
|
|
use Bugzilla::JobQueue;
|
|
use Bugzilla::Util qw(get_text);
|
|
BEGIN { eval "use parent qw(Daemon::Generic)"; }
|
|
|
|
our $VERSION = BUGZILLA_VERSION;
|
|
|
|
# Info we need to install/uninstall the daemon.
|
|
our $chkconfig = "/sbin/chkconfig";
|
|
our $initd = "/etc/init.d";
|
|
our $initscript = "bugzilla-queue";
|
|
|
|
# The Daemon::Generic docs say that it uses all sorts of
|
|
# things from gd_preconfig, but in fact it does not. The
|
|
# only thing it uses from gd_preconfig is the "pidfile"
|
|
# config parameter.
|
|
sub gd_preconfig {
|
|
my $self = shift;
|
|
|
|
$self->{_run_command} = 'subprocess_worker';
|
|
my $pidfile = $self->{gd_args}{pidfile};
|
|
if (!$pidfile) {
|
|
$pidfile = bz_locations()->{datadir} . '/' . $self->{gd_progname}
|
|
. ".pid";
|
|
}
|
|
return (pidfile => $pidfile);
|
|
}
|
|
|
|
# All config other than the pidfile has to be done in gd_getopt
|
|
# in order for it to be set up early enough.
|
|
sub gd_getopt {
|
|
my $self = shift;
|
|
|
|
$self->SUPER::gd_getopt();
|
|
|
|
if ($self->{gd_args}{progname}) {
|
|
$self->{gd_progname} = $self->{gd_args}{progname};
|
|
}
|
|
else {
|
|
$self->{gd_progname} = basename($0);
|
|
}
|
|
|
|
# There are places that Daemon Generic's new() uses $0 instead of
|
|
# gd_progname, which it really shouldn't, but this hack fixes it.
|
|
$self->{_original_zero} = $0;
|
|
$0 = $self->{gd_progname};
|
|
}
|
|
|
|
sub gd_postconfig {
|
|
my $self = shift;
|
|
# See the hack above in gd_getopt. This just reverses it
|
|
# in case anything else needs the accurate $0.
|
|
$0 = delete $self->{_original_zero};
|
|
}
|
|
|
|
sub gd_more_opt {
|
|
my $self = shift;
|
|
return (
|
|
'pidfile=s' => \$self->{gd_args}{pidfile},
|
|
'n=s' => \$self->{gd_args}{progname},
|
|
);
|
|
}
|
|
|
|
sub gd_usage {
|
|
pod2usage({ -verbose => 0, -exitval => 'NOEXIT' });
|
|
return 0
|
|
}
|
|
|
|
sub gd_can_install {
|
|
my $self = shift;
|
|
|
|
my $source_file;
|
|
if ( -e "/etc/SuSE-release" ) {
|
|
$source_file = "contrib/$initscript.suse";
|
|
} else {
|
|
$source_file = "contrib/$initscript.rhel";
|
|
}
|
|
my $dest_file = "$initd/$initscript";
|
|
my $sysconfig = '/etc/sysconfig';
|
|
my $config_file = "$sysconfig/$initscript";
|
|
|
|
if (!-x $chkconfig or !-d $initd) {
|
|
return $self->SUPER::gd_can_install(@_);
|
|
}
|
|
|
|
return sub {
|
|
if (!-w $initd) {
|
|
print "You must run the 'install' command as root.\n";
|
|
return;
|
|
}
|
|
if (-e $dest_file) {
|
|
print "$initscript already in $initd.\n";
|
|
}
|
|
else {
|
|
copy($source_file, $dest_file)
|
|
or die "Could not copy $source_file to $dest_file: $!";
|
|
chmod(0755, $dest_file)
|
|
or die "Could not change permissions on $dest_file: $!";
|
|
}
|
|
|
|
system($chkconfig, '--add', $initscript);
|
|
print "$initscript installed.",
|
|
" To start the daemon, do \"$dest_file start\" as root.\n";
|
|
|
|
if (-d $sysconfig and -w $sysconfig) {
|
|
if (-e $config_file) {
|
|
print "$config_file already exists.\n";
|
|
return;
|
|
}
|
|
|
|
open(my $config_fh, ">", $config_file)
|
|
or die "Could not write to $config_file: $!";
|
|
my $directory = abs_path(dirname($self->{_original_zero}));
|
|
my $owner_id = (stat $self->{_original_zero})[4];
|
|
my $owner = getpwuid($owner_id);
|
|
print $config_fh <<END;
|
|
#!/bin/sh
|
|
BUGZILLA="$directory"
|
|
# This user must have write access to Bugzilla's data/ directory.
|
|
USER=$owner
|
|
END
|
|
close($config_fh);
|
|
}
|
|
else {
|
|
print "Please edit $dest_file to configure the daemon.\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
sub gd_can_uninstall {
|
|
my $self = shift;
|
|
|
|
if (-x $chkconfig and -d $initd) {
|
|
return sub {
|
|
if (!-e "$initd/$initscript") {
|
|
print "$initscript not installed.\n";
|
|
return;
|
|
}
|
|
system($chkconfig, '--del', $initscript);
|
|
print "$initscript disabled.",
|
|
" To stop it, run: $initd/$initscript stop\n";
|
|
}
|
|
}
|
|
|
|
return $self->SUPER::gd_can_install(@_);
|
|
}
|
|
|
|
sub gd_check {
|
|
my $self = shift;
|
|
|
|
# Get a count of all the jobs currently in the queue.
|
|
my $jq = Bugzilla->job_queue();
|
|
my @dbs = $jq->bz_databases();
|
|
my $count = 0;
|
|
foreach my $driver (@dbs) {
|
|
$count += $driver->select_one('SELECT COUNT(*) FROM ts_job', []);
|
|
}
|
|
print get_text('job_queue_depth', { count => $count }) . "\n";
|
|
}
|
|
|
|
sub gd_setup_signals {
|
|
my $self = shift;
|
|
$self->SUPER::gd_setup_signals();
|
|
$SIG{TERM} = sub { $self->gd_quit_event(); }
|
|
}
|
|
|
|
sub gd_quit_event {
|
|
Bugzilla->job_queue->kill_worker();
|
|
exit(1);
|
|
}
|
|
|
|
sub gd_other_cmd {
|
|
my ($self, $do, $locked) = @_;
|
|
if ($do eq "once") {
|
|
$self->{_run_command} = 'work_once';
|
|
} elsif ($do eq "onepass") {
|
|
$self->{_run_command} = 'work_until_done';
|
|
} else {
|
|
$self->SUPER::gd_other_cmd($do, $locked);
|
|
}
|
|
}
|
|
|
|
sub gd_run {
|
|
my $self = shift;
|
|
$self->_do_work($self->{_run_command});
|
|
}
|
|
|
|
sub _do_work {
|
|
my ($self, $fn) = @_;
|
|
|
|
my $jq = Bugzilla->job_queue();
|
|
$jq->set_verbose($self->{debug});
|
|
$jq->set_pidfile($self->{gd_pidfile});
|
|
foreach my $module (values %{ Bugzilla::JobQueue->job_map() }) {
|
|
eval "use $module";
|
|
$jq->can_do($module);
|
|
}
|
|
$jq->$fn;
|
|
}
|
|
|
|
1;
|
|
|
|
__END__
|
|
|
|
=head1 NAME
|
|
|
|
Bugzilla::JobQueue::Runner - A class representing the daemon that runs the
|
|
job queue.
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
use Bugzilla::JobQueue::Runner;
|
|
Bugzilla::JobQueue::Runner->new();
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
This is a subclass of L<Daemon::Generic> that is used by L<jobqueue>
|
|
to run the Bugzilla job queue.
|
|
|
|
=head1 B<Methods in need of POD>
|
|
|
|
=over
|
|
|
|
=item gd_check
|
|
|
|
=item gd_run
|
|
|
|
=item gd_can_install
|
|
|
|
=item gd_quit_event
|
|
|
|
=item gd_other_cmd
|
|
|
|
=item gd_more_opt
|
|
|
|
=item gd_postconfig
|
|
|
|
=item gd_usage
|
|
|
|
=item gd_getopt
|
|
|
|
=item gd_preconfig
|
|
|
|
=item gd_can_uninstall
|
|
|
|
=item gd_setup_signals
|
|
|
|
=back
|