#!/usr/bin/env perl use strict; use warnings; use diagnostics; use File::Basename qw(basename); use Net::OpenSSH; use DateTime; use DBI; use feature 'say'; sub remote { my ( $ssh, @cmd ) = @_; $ssh->system(@cmd); $ssh->error and die "Remote command failed (@cmd): " . $ssh->error; } sub shell_quote { my ($string) = @_; $string =~ s/'/'"'"'/g; return "'$string'"; } my $date = DateTime->now->iso8601; my $screen_name = 'smchurla_fail'; my $local_root = '/home/christoph/Notes/TU/MastersThesis/FailNix'; my $local_builds_dir = "$local_root/builds"; my $remote_host = 'mars'; # smchurla@mars.cs.tu-dortmund.de my $remote_root = '/home/lab/smchurla/Documents/failnix'; my $remote_db_conf = "$remote_root/db.conf"; my $remote_builds_dir = "$remote_root/builds"; my $remote_runner = "$remote_root/scripts/runner.pl"; my $remote_log = "$remote_root/runner.log"; # The mars db is bound to local port 3306 over SSH. # - This requires using the configured 'mars' # remote_host instead of smchurla@mars # or setting up another tunnel here my $db_host = "127.0.0.1"; my $db_port = "3306"; my $db_user = "smchurla"; my $db_prefix = "$db_user\_$date"; # Database password open( my $fhandle, '<', "$local_root/mars-db.conf" ) or die "Failed to read mars-db.conf: $!"; chomp( my $db_password = <$fhandle> ); close($fhandle); # Initialize SSH connection # - This connection also sets up the database tunnel my $ssh = Net::OpenSSH->new( $remote_host, timeout => 30, master_opts => [ -o => 'BatchMode=yes', -o => 'StrictHostKeyChecking=accept-new', ], ); $ssh->error and die 'SSH connection failed: ' . $ssh->error; say 'Connected to mars.cs.tu-dortmund.de'; # TODO: Abort if old experiments are still on the server => meaning they're not archived # Pull changes # remote( $ssh, 'git', '-C', $remote_root, 'pull' ); # TODO: Requires auth # Find new experiments opendir( my $dhandle, $local_builds_dir ) or die "opendir($local_builds_dir): $!"; my @experiments = grep { $_ ne '.' && $_ ne '..' && -d "$local_builds_dir/$_" } readdir($dhandle); closedir($dhandle); # Upload new experiments remote( $ssh, 'mkdir', '-p', $remote_builds_dir ); foreach (@experiments) { say " - Uploading $_ to $remote_builds_dir/$date\_$_..."; $ssh->scp_put( { recursive => 1, copy_attrs => 1 }, "$local_builds_dir/$_", "$remote_builds_dir/$date\_$_" ) or die "Failed to upload $_: " . $ssh->error; } # Initialize db connection my $dbh = DBI->connect( "DBI:MariaDB:host=$db_host;port=$db_port", $db_user, $db_password ) or die 'Failed to connect to database: ' . $DBI::errstr; say 'Connected to database'; say 'Existing databases:'; my @db_names = sort map { s/DBI:MariaDB://r } grep { !/information_schema|smchurla_ll/ } $dbh->data_sources(); foreach (@db_names) { say " - $_"; } # Create dbs for new experiments say 'Creating databases...'; foreach (@experiments) { say " - Creating database $db_prefix\_$_..."; $dbh->do("create database `$db_prefix\_$_`") or die "Failed to create database: " . $dbh->errstr; } # Kill old screen session (don't check success as a session might not exist) # say "Killing previous screen session with name $screen_name"; # $ssh->system( "screen", "-XS", $screen_name, "quit" ); # Start new screen session # my $invoke_runner = # "cd " . shell_quote($remote_root) . " && perl " . shell_quote($remote_runner); # say # "Starting new screen session with name $screen_name and command $invoke_runner"; # remote( $ssh, "screen", "-dmS", $screen_name, "sh", "-lc", # "exec $invoke_runner" ); remote( $ssh, "nohup sh -c " . shell_quote("cd $remote_root && perl $remote_runner") . " >" . shell_quote($remote_log) . " 2>&1 < /dev/null &" ); say "Started remote runner for ", scalar(@experiments), " experiments"; $dbh->disconnect or warn $dbh->errstr;