Perl(Net :: SSH :: Perl)脚本有时会在运行远程命令时挂起但shell脚本有效

时间:2014-07-31 11:43:35

标签: perl jenkins

我编写了一个Perl脚本,它在机器A上复制可交付物(并且还在另一台机器B上备份相同的资源),然后调用已经存在于机器A上的shell脚本。这个shell脚本部署了机器A上的可交付(通常是一个war文件)虽然复制和调用shell脚本的整个任务可以很容易地用bash编写,但是我想使用Perl只是因为我没有编写Perl程序很长一段时间。我们有一个Jenkins的主从设置,Perl脚本从Jenkins奴隶运行。

use strict;
use warnings;
use Cwd;
use File::Copy;
use Getopt::Long;
use File::Basename;
use Net::SSH::Perl;
use Net::SCP::Expect;

my ($conf_file, $environment, $action, $job, $dest_file, $user, $host, $IP, $TARGET_SERVER, $JOB_ENV, $JENKINS_JOB, $wrapper, $src_file, $src_path, $src_dist_path, $src_dist_full_path, $dist_temp_archive_path, $dist_archive_host, $archive_user, $scpe, $id_file, @id_file, @array, $line);

my $ITE = "server.ite.com";

if ($environment eq "release") {
    $IP = $ITE;
    $JOB_ENV = "Release_";
    $JENKINS_JOB = substr $ENV{'JOB_NAME'}, 8;
    $dist_temp_archive_path = "/home/ec2-user/release_archive";
}

$conf_file = "/home/ec2-user/SCM/generic/deploy_build.cnf";
open (FH, "<", $conf_file) or die "Cannot open < $conf_file: $!";

while (<FH>) {
    if ( $_ =~ /\b$JENKINS_JOB\b/ ) {
        push @array, $_;
    } else {
        next;
    }
}

foreach $line (@array) {
    ($job, $src_dist_path, $dest_file, $user, $wrapper) = split(':', $line);

    if ($dest_file eq "") {
        ($src_file, $src_path) = fileparse($src_dist_path);
        $dest_file = $src_file;
    }

    $job = $JOB_ENV . $job;

    $id_file = "/home/ec2-user/.ssh/sandy";
    @id_file = ("/home/ec2-user/.ssh/sandy");

    if ($action eq "copy_distributable") {
        printf "Initiating subroutine to copy distributable on remote machine...\n";
        &copy_distributable;
    } elsif ($action eq "exec_wrapper") {
        if (defined $wrapper && length $wrapper) {
            printf "Initiating subroutine for executing wrapper on remote machine...\n";
            &exec_wrapper;
        } else {
            printf "*** No wrapper specified ****\n";
        }
    }
}

sub copy_distributable {
    $archive_user="ec2-user";
    $src_dist_full_path = "$ENV{WORKSPACE}/$src_dist_path";
    $dist_archive_host = "55.666.77.88";

    if ( -f $src_dist_full_path ) {
        $scpe = Net::SCP::Expect->new(identity_file => $id_file, host => $dist_archive_host);
        $scpe->scp("$src_dist_full_path", "$dist_temp_archive_path/$dest_file");

        $scpe = Net::SCP::Expect->new(identity_file => $id_file, host => $IP, user => $user);
        $scpe->scp("$src_dist_full_path", "/home/$user/$dest_file");

        printf "Deliverable copied on deployment machine. Now moving on to next task of archiving the deliverable...\n\n";

        my $ssh = Net::SSH::Perl->new($dist_archive_host, "identity_files" => \@id_file);
        $ssh->login($archive_user);
        printf "mv $dist_temp_archive_path/$dest_file $dist_temp_archive_path/latest\n\n";
        my($stdout, $stderr, $exit) = $ssh->cmd("mv $dist_temp_archive_path/$dest_file $dist_temp_archive_path/latest");
        printf "Output: $stdout\n" if $stdout;
        printf "Error: $stderr\n" if $stderr;
        printf "Deliverable archived on Jenkins master\n";
    } else {
        printf "Deliverable not found\n";
        exit 1;
    }
}


sub exec_wrapper {
    my $ssh = Net::SSH::Perl->new($IP, "identity_files" => \@id_file);
    $ssh->login($user);
    my($stdout, $stderr, $exit) = $ssh->cmd("~/release/$wrapper");
    printf "Output: $stdout\n" if $stdout;
    printf "Error: $stderr\n" if $stderr;
}

构建工作区所在的Jenkins slave框的详细信息:

[ec2-user@jenkins_slave2 ~]$ uname -a
Linux jenkins_slave 3.10.35-43.137.amzn1.x86_64 #1 SMP Wed Apr 2 09:36:59 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

[ec2-user@jenkins_slave2 ~]$ free -m
              total      used       free       shared   buffers         cached
Mem:          7228       5688       1539          0         72           3824
-/+ buffers/cache:     1791       5436
Swap:        16382       163       16219

此外,盒子上有足够的内存来复制和最终部署可交付物。磁盘空间也不是任何一台机器上的问题。两者都是在AWS上运行的Linux实例。

现在的问题是,虽然程序通常可以运行很多次,但是在调用部署脚本(shell脚本)时它会挂起。为了调试,我使用Devel :: Trace在Jenkins中运行Perl脚本。当构建卡住时,我中止了构建。一旦我中止了构建,我就遇到了堆空间错误,所以我添加了Xms&amp; Xmx参数分别设置初始和最大Java堆大小。确认设置已应用后,我再次运行构建。一些构建过去了,一些再次陷入困境。我认为增加堆大小没有任何意义。编写shell脚本来执行相同的任务,并且不需要运行任何此类额外内存。现在我不知道在哪里寻找线索。

真的很感激任何帮助。

1 个答案:

答案 0 :(得分:1)

我遇到了类似的问题。通过sftp上传文件的客户端将在3个文件后挂起。过了一会儿,我意识到客户端正在创建一个用于上传一个文件的新连接。

也许你可以在foreach循环之前打开连接(创建$ ssh / $ scpe变量)并将它们传递给copy_distributable函数以便重用。