【问题标题】:Perl (Net::SSH::Perl) script sometimes hangs while running remote command but shell script worksPerl (Net::SSH::Perl) 脚本在运行远程命令时有时会挂起,但 shell 脚本可以工作
【发布时间】:2014-09-23 08:22:19
【问题描述】:

我编写了一个 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 box详情:

[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 和 Xmx 参数来分别设置初始和最大 Java 堆大小。确认应用设置后,我再次运行构建。一些构建通过了,一些构建又被卡住了。我认为进一步增加堆大小没有任何意义。编写了一个 shell 脚本来执行相同的任务,它不需要任何额外的内存来运行。现在不知道去哪里找线索了。

任何帮助将不胜感激。

【问题讨论】:

    标签: perl jenkins


    【解决方案1】:

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

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

    【讨论】:

    • 感谢康奈尔的建议!我开始使用 Net::OpenSSH 而不是 Net::SSH::Perl,这似乎有所帮助。但是,您的建议也毫无价值。我修改了我的脚本以纳入您的建议。 :)
    • 对于延迟回复表示歉意。我会早点回复,但我首先想修改我的脚本然后回复。 :)
    猜你喜欢
    • 2011-05-31
    • 2021-12-14
    • 2013-06-17
    • 2016-06-19
    • 2011-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-28
    相关资源
    最近更新 更多