App-RemoteCommand

 view release on metacpan or  search on metacpan

lib/App/RemoteCommand/SSH.pm  view on Meta::CPAN

package App::RemoteCommand::SSH;
use v5.24;
use warnings;
use experimental qw(lexical_subs signatures);

use App::RemoteCommand::Util qw(DEBUG logger);
use Net::OpenSSH;
use IO::Pty;

sub _ssh ($self, %args) {
    my $loglevel = DEBUG ? "error" : "quiet";
    Net::OpenSSH->new($args{host},
        async => 1,
        strict_mode => 0,
        timeout => 6,
        kill_ssh_on_timeout => 1,
        master_setpgrp => 1,
        master_opts => [
            -o => "ConnectTimeout=5",
            -o => "StrictHostKeyChecking=no",
            -o => "UserKnownHostsFile=/dev/null",
            -o => "LogLevel=$loglevel",
            ($args{configfile} ? (-F => $args{configfile}) : ()),
        ],
    );
}

use constant STATE_TODO          => 1;
use constant STATE_CONNECTING    => 2;
use constant STATE_CONNECTED     => 3;
use constant STATE_DISCONNECTING => 4;
use constant STATE_DONE          => 5;

sub new ($class, %args) {
    bless {
        %args,
        ssh => undef,
        cmd => [],
        at_exit => undef,
        state => STATE_TODO,
        exit => -1,
        current => undef,
        sudo => undef,
    }, $class;
}

sub add ($self, $cmd) {
    push $self->{cmd}->@*, $cmd;
}

sub at_exit ($self, @args) {
    @args ? $self->{at_exit} = shift @args : $self->{at_exit};
}

sub cancel ($self, $signal) {

    DEBUG and logger " CANCEL %s, state %s", $self->host, $self->{state};

    if ($self->{state} == STATE_TODO) {
        $self->{state} == STATE_DONE;
    } elsif ($self->{state} == STATE_CONNECTING) {
        $self->{cmd}->@* = ();
        undef $self->{at_exit};
        my $master_pid = $self->{ssh}->get_master_pid;
        DEBUG and logger " SEND SIG$signal %s, process group for master pid %d", $self->host, $master_pid;
        kill $signal => -$master_pid;
    } elsif ($self->{state} == STATE_CONNECTED) {
        $self->{cmd}->@* = ();
        if ($signal
            and $self->{current}
            and $self->{current}{type} eq "cmd"
            and my $pid = $self->{current}{pid}
        ) {
            DEBUG and logger " SEND SIG$signal %s, pid %s", $self->host, $pid;
            kill $signal => $pid;
        }
    } elsif ($self->{state} == STATE_DISCONNECTING) {
        # nop
    } elsif ($self->{state} == STATE_DONE) {



( run in 0.444 second using v1.01-cache-2.11-cpan-df04353d9ac )