2013-04-05 49 views
1

我試圖從多個服務器異步運行多個SSH命令,我想從命令中捕獲輸出並按順序顯示它們。 爲了拋出一個額外的曲線球,我希望pid3只在pid2完成時運行,並且在前三個命令完成後運行pid4。這個最好的方法將如何實現?如何異步運行多個perl打開命令並按順序顯示輸出

實施例:

// $pid1 and $pid2 should run asynchronously 
my $pid1 = open(my $SSH1, "|ssh -t -t runuser\@$server{'app'} 'sudo chef-client'"); 

my $pid2 = open(my $SSH2, "|ssh -t -t runuser\@$server{'auth'} 'sudo chef-client'"); 

// This command should wait for $pid2 to complete. 
my $pid3 = open(my $SSH3, "|ssh -t -t runuser\@$server{'auth'} \"sudo -- sh -c '$update_commands'\""); 

// This command should wait for $pid1-3 to complete before running. 
my $pid4 = open(my $SSH4, "|ssh -t -t runuser\@$server{'varn'} \"sudo -- sh -c '$varn_commands'\""); 
+0

請參閱tsee的答案http://stackoverflow.com/questions/1752357/how-can-i-run-a-system-command-in-perl-asynchronously?rq=1。此外,在你的問題中唯一的異步東西是pid1 vs pid2/3。其他一切都是順序的。 – imran 2013-04-05 04:31:09

+0

儘管目前所有4個命令都是異步運行的,但您所期望的效果是正確的。 – 2013-04-05 04:33:49

+1

在創建$ pid3之前,請確保處理並關閉$ SSH2。然後,在創建$ pid4之前,確保處理並關閉$ SSH1和$ SSH3。但是有比使用open()更好的方法,請參閱上面鏈接中的建議。 – imran 2013-04-05 04:39:49

回答

1

我(有點粗)溶液迄今。我覺得有可能是在Perl來處理這更優雅的方式,但是這可能完成這項工作:

# Silence all non-error output from the commands on first 2 servers: 
my $pid1 = open(my $SSH1, "|ssh -t -t runuser\@$server{'app'} 'sudo chef-client > /dev/null'"); 

my $pid2 = open(my $SSH2, "|ssh -t -t runuser\@$server{'auth'} 'sudo chef-client > /dev/null'"); 

if ($pid1) { 
    print "Connecting to $server{'app'}: chef-client"; 
    while (<$SSH1>) { 
     print $server{'app'}; 
     print $_; 
    } 
} 
close $SSH1 or die $!; 

if ($pid2) { 
    print "Connecting to $server{'auth'}: chef-client"; 
    while (<$SSH2>) { 
     print $server{'auth'}; 
     print $_; 
    } 
} 
close $SSH2 or die $!; 

# Run pid3 once pid2 is closed 
my $pid3 = open(my $SSH3, "|ssh -t -t runuser\@$server{'auth'} \"sudo -- sh -c '$update_command'\""); 
if ($pid3) { 
    print "Connecting to $server{'auth'}: $update_command"; 
    while (<$SSH3>) { 
     print $_; 
    } 
} 
close $SSH3 or die $!; 

# Run pid4 after all previous commands have completed. 
my $pid4 = open(my $SSH4, "|ssh -t -t runuser\@$server{'varn'} \"sudo -- sh -c '$varn_command'\""); 
if ($pid4) { 
    print "Connecting to $server{'varn'}: $varn_command"; 
    while (<$SSH4>) { 
     print $_; 
    } 
} 
close $SSH4 or die $!; 
1

Forks::Super處理所有的這些要求:

use Forks::Super; 

# run $command1 and $command2 , make stderr available 
my $job1 = fork { cmd => $command1, child_fh => 'err' }; 
my $job2 = fork { cmd => $command2, child_fh => 'err' }; 

# job 3 must wait for job 2. Collect stdout, stderr 
my $job3 = fork { cmd => $command3, depend_on => $job2, child_fh => 'out,err' }; 

# and job 4 waits for the other 3 jobs 
my $job4 = fork { cmd => $command4, depend_on => [ $job1, $job2, $job3 ], 
        child_fh => 'out,err' }; 

# wait for jobs to finish, then we'll collect output 
$_->wait for $job1, $job2, $job3, $job4; 
my @output1 = $job1->read_stderr; 
my @output2 = $job2->read_stderr; 
my @output3 = ($job3->read_stdout, $job3->read_stderr); 
my @output4 = ($job4->read_stdout, $job4->read_stderr); 
... 
1

使用Net::OpenSSH::Parallel

# untested! 
use Net::OpenSSH::Parallel; 
my $pssh = Net::OpenSSH::Parallel->new; 

$pssh->add_server(app => $server{app}, user => 'runuser'); 
$pssh->add_server(auth => $server{auth}, user => 'runuser'); 
$pssh->add_server(varn => $server{varn}, user => 'runuser'); 

$pssh->push('app', cmd => @cmd1); 
$pssh->push('auth', cmd => @cmd2); 
$pssh->push('auth', cmd => @cmd3); 
$pssh->push('varn', join => '*'); 
$pssh->push('varn', cmd => @cmd4); 

$pssh->run; 

如果您需要傳遞密碼,自動執行sudo會稍微複雜一些,但仍然可以完成。它在模塊文檔中進行了解釋。

+0

在我的情況下,我不需要傳遞密碼,因爲我使用的是SSH密鑰。 – 2013-04-09 00:23:56

+0

@HighwayofLife:我不是指ssh身份驗證。通常,當你用'sudo'運行一些命令時,它會要求你輸入一個額外的密碼。儘管在你的環境中,'sudo'可能被配置爲不要求輸入密碼。 – salva 2013-04-09 07:46:17

+0

啊,是的,你會是對的。我的sudo用戶是wheel組的一部分,它默認情況下不需要密碼即可運行sudo命令。但對於其他可能遇到這個問題的人來說,這是一個很好的點 – 2013-04-11 03:21:21

相關問題