end0tknr's kipple - 新web写経開発

http://d.hatena.ne.jp/end0tknr/ から移転しました

perlのNet::OpenSSHでリモートサーバのコマンドをバックグラウンドで起動

Net::OpenSSH - search.cpan.org のドキュメントでは、Net::OpenSSH->new(async => 1) や $ssh->spawn() が使えそうにも思えましたが、結局、nohup 〜 & に落ち着きました。
cgi(mod_perl)環境による影響でしょうか?

※「nohup $cmd >/dev/null 2>/dev/null http://www.codereading.com/nb/ignore-the-hangup-signal.html

package EanUtil::BulkMail;
use strict;
use utf8;
use base qw/EanUtil/;
use Encode;
use EanUtil::Config;
use JSON;
use Net::OpenSSH;
use Data::Dumper;

my $CONF = EanUtil::Config->get_config();

sub new {
    my ($class) = @_;
    my $self = {};
    return bless $self, $class;
}

sub act_main {
    my ( $self, $q ) = @_;

    my $action =    $q->param('action') || '';

    if (
        $action eq "set_mailto_list" or #配信対象者の抽出
        $action eq "send_bulk_mail"     #メール送信実行(バックグラウンド実行)
       ){
        my $method = "act_$action";
        return $self->$method($q);
    }

    die "unknown action=$action $!";
}

#メール送信実行
sub act_send_bulk_mail {
    my ( $self, $q ) = @_;

    my ($ssh,$msg_tmp) = $self->connect_ssh();
    unless($ssh){
        my $ret = {};
        $ret->{result} = undef;
        $ret->{msg} = join(' ','SSH接続に失敗しました.',$msg_tmp);
        $self->response_json($ret);
        return undef;
    }

    my $mail_type = $q->param('mail_type');

    ## backgroundで実行
    ##refer to http://www.codereading.com/nb/ignore-the-hangup-signal.html
    my $ssh_cmd = join('',
                       "nohup ",
                       "$CONF->{bulk_mail}->{php} ",
                       "$CONF->{bulk_mail}->{ean_app_root}/batch/",
                       "$BULK_CMDS->{$mail_type}->{send_bulk_mail} ",
                       " >/dev/null 2>/dev/null </dev/null &");

    unless( $ssh->system($ssh_cmd) ){
        my $err_msg = $ssh->error .$ssh_cmd;

        my $ret = {};
        $ret->{result} = undef;
        $ret->{msg} = join(' ','SSH実行に失敗しました.',$err_msg);
        $self->response_json($ret);
        return undef;
    }

    my $ret = {};
    $ret->{result} = 'success';
    $self->response_json($ret);
    return $self;
}

#メール送信先の登録
sub act_set_mailto_list {
    my ( $self, $q ) = @_;

    my ($ssh,$msg_tmp) = $self->connect_ssh();
    unless($ssh){
        my $ret = {};
        $ret->{result} = undef;
        $ret->{msg} = join(' ','SSH接続に失敗しました.',$msg_tmp);
        $self->response_json($ret);
        return undef;
    }

    my $mail_type = $q->param('mail_type');

    my $ssh_cmd = join('',
                       $CONF->{bulk_mail}->{php},
                       ' ',
                       "$CONF->{bulk_mail}->{ean_app_root}/batch/",
                       "$BULK_CMDS->{$mail_type}->{set_mailto_list}");
    unless( $ssh->system($ssh_cmd) ){
        my $err_msg = $ssh->error .$ssh_cmd;

        my $ret = {};
        $ret->{result} = undef;
        $ret->{msg} = join(' ','SSH実行に失敗しました.',$err_msg);
        $self->response_json($ret);
        return undef;
    }

    my $ret = {};
    $ret->{result} = 'success';
    $self->response_json($ret);
    return $self;
}

sub connect_ssh {
    my ($self) = @_;

    my $DUMMY_STDIN_OUT = '/dev/null';
    open(my $stdin_fh, $DUMMY_STDIN_OUT) or die "can't open $DUMMY_STDIN_OUT $!";
    open(my $stdout_fh,$DUMMY_STDIN_OUT) or die "can't open $DUMMY_STDIN_OUT $!";

    my $option = {default_stdin_fh => $stdin_fh,
                  default_stdout_fh => $stdin_fh};

    my $ssh =
        Net::OpenSSH->new($CONF->{bulk_mail}->{ssh_host},
                          user  =>$CONF->{bulk_mail}->{ssh_user},
                          password=>$CONF->{bulk_mail}->{ssh_passwd},
                          %$option);
    if($ssh->error){
        my $msg = join(' ',
                       "fail ssh to",
                       "host:$CONF->{bulk_mail}->{ssh_host}",
                       "user:$CONF->{bulk_mail}->{ssh_user}",
                       $ssh->error);
        return undef, $msg;
    }
    return $ssh;
}

sub response_json {
    my ($self,$res) = @_;
    print CGI::header(-type=>'text/plain',-charset=>'UTF-8');
    print encode_utf8(JSON::to_json($res||{}));
}

1;
__END__