User:AnomieBOT/source/tools-startbot.pl

#!/usr/bin/perl -w

use strict;

# binmodes
$|=1;
binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';

my $quiet = 0;
if ( $ARGV[0] eq '--quiet' ) {
    $quiet = 1;
    shift;
}

die "Cannot run as root\n" if $<==0;
die "USAGE: $0 taskdir\n" if @ARGV!=1;

use Cwd;
use File::Basename;

my $base;
BEGIN {
    $base = File::Basename::dirname( Cwd::realpath( __FILE__ ) );
    chdir( $base );
}

use lib $base;
use AnomieBOT::API;
use AnomieBOT::API::Toolforge;
use JSON;
use POSIX ':sys_wait_h';
use sort 'stable';

my %instances=();

chdir($AnomieBOT::API::basedir);

my $dir=shift or die "USAGE: $0 taskdir\n";
$dir.='/' unless substr($dir,-1) eq '/';

opendir(D, $dir) or die "Could not open task directory: $!\n";
while(my $file=readdir(D)){
    next if -d $dir.$file;
    next if substr($file,0,1) eq '.';
    my $task='';
    if(!open(X, '<:utf8', $dir.$file)){
        warn "Could not open task file $file: $!\n";
        next;
    }
    while(<X>){
        $task=$1 if /^package (.*);$/;
    }
    close(X);
    if($task eq ''){
        warn "Invalid task file $file\n";
        next;
    }
    AnomieBOT::API::load($dir.$file);
    my $t=$task->new();
    my $a=$t->approved;
    $instances{$a}=1 if $a>0;
}
closedir(D);
die "No instances found" unless %instances;

# Check permissions
die "Bad file permissions on conf.ini" if (stat 'conf.ini')[2]&7;

# List running instances
my $toolforge = AnomieBOT::API::Toolforge->new( toolname => 'anomiebot' );
my %running=();
if ( 0 ) { # https://phabricator.wikimedia.org/T321919#11126898
    my $res = $toolforge->jobs();
    die "Failed to fetch job info: " . $res->message . "\n" unless $res->is_success;
    foreach my $job (@{$res->json_content->{'jobs'}}) {
        $running{$job->{'name'}} = $job->{'pod_name'} if $job->{'status_short'} =~ /^Running /;
    }
} else {
    my $res = $toolforge->pods();
    die "Failed to fetch job info: " . $res->message . "\n" unless $res->is_success;
    foreach my $job (@{$res->json_content->{'items'}}) {
        $running{$job->{'metadata'}{'labels'}{'job-name'} // ''} = $job->{'metadata'}{'name'} if $job->{'status'}{'phase'} eq 'Running';
    }
}

my $home = $ENV{'HOME'};

# Start the instances
for my $botnum (sort { $a <=> $b } keys %instances) {
    my $jname = "anomiebot-$botnum";
    if(exists($running{$jname})){
        my $jhost = $running{$jname};
        warn "Job $jname is already running on $jhost\n" unless $quiet;
    } else {
        my $api = AnomieBOT::API->new("conf.ini", $botnum, { db => 0 });
        my $memlimit = $api->{'memlimit'};
        my $cpulimit = $api->{'cpulimit'};
        $api->DESTROY;
        $api = undef;
        my $res = $toolforge->submit_job(
            name      => $jname,
            cmd       => "$home/bot/bot-wrapper.sh $botnum $dir >> $home/botlogs/$jname.job 2>&1",
            imagename => 'perl5.40',
            filelog   => JSON::false,
            memory    => $memlimit,
            cpu       => $cpulimit,
            emails    => 'onfailure',
        );
        if ( $res->is_success ) {
            print "Submitted $jname\n";
        } else {
            warn "Failed submitting $jname: " . join( "; ", @{ ( eval { $res->json_content->{'error'}; } // [ $res->message ] ) } );
        }
    }
}