PERL fork – 運用fork()函式管理大量Cisco設備

此程式使用telnet方法,取得每個 Cisco 路由器或交換器的組態,所需的時間約2秒鐘,如果貴公司有1,000台 Cisco 設備,一般單執行緒(single thread)程式依序存取一個設備,恐耗時2,000秒相當於33+分鐘,運用fork()函式的PERL程式,使用平行多程序,同時對所有的Cisco設備進行存取,所需時間在10秒鐘左右;請各位試試看。

  • 執行成功訊息輸出(scalar type)儲存於:
    • $hostinfo{ 主機名稱 }->{ 執行指令 }
  • 執行失敗訊息輸出(scalar type)儲存於
    • $hosterrinfo{ 主機名稱 }->{ 執行指令 }
#!/usr/bin/perl -w
# This perl script is main to be doing numeric cisco equipment management
use strict;  
use IPC::Shareable;

$SIG{ 'CHLD' } = 'IGNORE';

my @hosts = ( '主機名稱或IP定址', '主機名稱或IP定址' );  
my @cmds = ( 'sh geego', 'sh ver', 'sh clock', 'sh queueing', 'sh hosts' );  
my $username = '登入帳號名稱';  # cisco telnet 的帳號  
my $passwd = '帳號之密碼';    # cisco telnet 的密碼  
my $enable_passwd = 'enable的密碼';  
my %hostinfo = ();  
my %hosterrinfo = ();  
my @children = ();  
my %ipcoptions = ( create => 'yes',  
                   exclusive => 0,
                   mode => 0644,
                   destroy => 'yes' );

tie %hostinfo, 'IPC::Shareable', 'good', \%ipcoptions or die "Can’t tie %hostinfo.\n";

tie %hosterrinfo, 'IPC::Shareable', 'err', \%ipcoptions or die "Can’t tie %hosterrinfo\n";

foreach my $host ( @hosts )  
{
    my $pid = fork();
    die "Can’t fork.:$!\n" unless defined( $pid );

    if( $pid == 0 ) # these are child processes
    {
        print "Child process is $$\n";
        get_info( $host );
        exit( 0 );
    }
    else # This is the parent process
    {
        print "$$ -> Process $pid is processing $host now.\n";
        push( @children, $pid );
    }
}

foreach ( @children )  
{
    #my $child_pid = waitpid( $_, 0 );
    my $child_pid = wait();
    print “Process $_ is done.\n";
}

sub get_info  
{
    use Net::Telnet::Cisco;  # 特別的 Perl Cisco Telnet的模組
    my ( $hostname ) = @_;
    my $cisco = Net::Telnet::Cisco->new( 'Host' => $hostname,
                                         'Errmode'=> 'return' );  # Perl Cisco Telnet的物件初始化

    $cisco->login( Password => "$passwd" );
    $cisco->ignore_warnings;

    foreach my $cmd ( @cmds )
    {
        my @output = $cisco->cmd( "$cmd" );

        if( $cisco->errmsg() )
        {
            $hosterrinfo{ $hostname }->{ $cmd } = $cisco->errmsg();
        }
        else
       {
            my $out = join( " ", @output );
            $hostinfo{ $hostname }->{ $cmd } = $out;
       }
    }
}

foreach my $host ( keys %hostinfo )  
{
    foreach my $cmd ( keys %{$hostinfo{ $host }} )
    {
        print "$host => $cmd =>\n $hostinfo{ $host }->{ $cmd }\n";
    }
}