Linux系统中使用PHP脚本定时监控交换机端口流量并添加删除修改交换机规则控制流量

今日在公司项目中用到了自动运维的脚本,用来每分钟执行php脚本监控交换机,如果交换机流量过大则添加出口,如果过小则减少出口。用到了一些技术性的东西。

具体代码实例如下:

<?php
/**********************************************
 * 监听交换机端口流量并切换规则
 * 当端口流量大于阀值则顺序执行A系列命令
 * 当端口流量小于阀值则倒序执行B系列命令
 * Author:Jerry
 * EMail : admin#laoji.org
 * Data :2019/5/30
 ***********************************************/
//  开始运行脚本预输出
$stime=microtime(true); 
echo str_repeat('-', 120).PHP_EOL;
ini_set('date.timezone','Asia/Shanghai');
echo '当前时间:'.date("Y-m-d H:i:s").PHP_EOL;
//  执行命令得出端口流量值
$cmd = '/usr/bin/snmpwalk -v2c -c power@idc 192.168.108.108 1.3.6.1.2.1.31.1.1.1.10.5';
//  流量阀值
$valve = '1000';

// 交换机信息配置
$ip = '192.168.108.108';
$port = '23';
$user = 'puer';
$passwd = 'puer123';


//  命令集,cmdA 添加规则集,cmdD删除规则集
$cmdA = array(
    array(  'ip route-static vpn-instance baishanyun2041 0.0.0.0 0.0.0.0 192.168.108.137 public description UPLINK-20180525',
            'ip route-static vpn-instance baishanyun2041 0.0.0.0 0.0.0.0 192.168.108.141 public description UPLINK-20180525'
        ),
    array(  'ip route-static vpn-instance baishanyun1029 0.0.0.0 0.0.0.0 192.168.108.137 public description UPLINK-20180525',
            'ip route-static vpn-instance baishanyun1029 0.0.0.0 0.0.0.0 192.168.108.141 public description UPLINK-20180525'
        ),
    array(  'ip route-static vpn-instance baishanyun1030 0.0.0.0 0.0.0.0 192.168.108.137 public description UPLINK-20180525',
            'ip route-static vpn-instance baishanyun1030 0.0.0.0 0.0.0.0 192.168.108.141 public description UPLINK-20180525'
        ),
    array(  'ip route-static vpn-instance baishanyun1033 0.0.0.0 0.0.0.0 192.168.108.137 public description UPLINK-20180525',
            'ip route-static vpn-instance baishanyun1033 0.0.0.0 0.0.0.0 192.168.108.141 public description UPLINK-20180525'
        )    
);
$cmdD = array(
    array(  'UNDO ip route-static vpn-instance baishanyun2041 0.0.0.0 0.0.0.0 192.168.108.137 public',
            'UNDO ip route-static vpn-instance baishanyun2041 0.0.0.0 0.0.0.0 192.168.108.141 public'
        ),
    array(  'UNDO ip route-static vpn-instance baishanyun1029 0.0.0.0 0.0.0.0 192.168.108.137 public',
            'UNDO ip route-static vpn-instance baishanyun1029 0.0.0.0 0.0.0.0 192.168.108.141 public'
        ),
    array(  'UNDO ip route-static vpn-instance baishanyun1030 0.0.0.0 0.0.0.0 192.168.108.137 public',
            'UNDO ip route-static vpn-instance baishanyun1030 0.0.0.0 0.0.0.0 192.168.108.141 public'
        ),
    array(  'UNDO ip route-static vpn-instance baishanyun1033 0.0.0.0 0.0.0.0 192.168.108.137 public',
            'UNDO ip route-static vpn-instance baishanyun1033 0.0.0.0 0.0.0.0 192.168.108.141 public'
        ),
);



//  获取当前流量值
$return = explode(':', shell_exec($cmd) );
$traffic = trim($return[count($return) - 1]);


//  开始登录交换机
$telnet = new telnet("{$ip}", "{$port}");
echo $telnet->read_till("login: ");
$telnet->write("{$user}\n");
echo $telnet->read_till("password: ");
$telnet->write("{$passwd}\n");
echo $telnet->read_till(">");
//echo $telnet->read_till(":> ");
$telnet->write("sys\n");
echo $telnet->read_till("]");
$telnet->write("dis this | inc ip route-static vpn-instance baishanyun\n");
echo $config = $tmp = $telnet->read_till("]");
//  获取交换机全部配置
while( strpos($tmp,'---- More ----') !== false ){
    $telnet->write(" \n"); 
    echo $config .= $tmp = $telnet->read_till("]");
}

$traffic = '2000';
$needCommit = 0 ;
$cmdAry = array();
$return = '';
if( $traffic >= $valve){//流量大于阀值
    $return .= '流量大于阀值'.PHP_EOL;
    $cmdAry = $cmdA;
    for($i=0;$i<count($cmdAry);$i++){
        for( $j=0;$j<count($cmdAry[$i]);$j++){
            if(strpos($config, $cmdAry[$i][$j]) !== false ){
                $return .=  '规则已存在'.$j.'#'.$i.':'.$cmdAry[$i][$j].PHP_EOL;
            }else{
                echo $telnet->write($cmdAry[$i][$j]."\n");
                echo $telnet->read_till("]");
                $needCommit = 1;
                $return .= '规则已写入'.$j.'#'.$i.':'.$cmdAry[$i][$j].PHP_EOL;
                if( $j == (count($cmdAry[$i])-1)){  
                    break 2;
                }
                
            }
        }        
    }  
}else{
    $return .= '流量小于阀值'.PHP_EOL;
    $cmdAry = $cmdD;
    $num = count( $cmdAry ) - 1;
    for( $i=$num;$i>=0;$i--){
        for( $j=0;$j<count($cmdAry[$i]);$j++){
            if( strpos($config, str_replace('UNDO ', '', $cmdAry[$i][$j])) !== false ){
                $telnet->write($cmdAry[$i][$j]."\n");
                echo $telnet->read_till("]");        
                $needCommit = '1';
                $return .= '规则需删除'.$j.'#.'.$i.':'.$cmdAry[$i][$j].PHP_EOL;      
                if( $j == (count($cmdAry[$i])-1) ){
                    $goBreak = 1;
                    break 2;
                }
            }else{
                $return .= '没有匹配到规则'.$j.'#'.$i.':'.$cmdAry[$i][$j].PHP_EOL;
            }
        
        }
    }
}
//  提交commit生效
if( $needCommit ){
    $telnet->write("commit\n");
    echo $telnet->read_till(']');
    $return .= '规则已commit'.PHP_EOL;
}
    
 

echo $telnet->close();
echo $return;



class Telnet {
    var $sock = NULL;

    function telnet($host,$port) {
        $this->sock = fsockopen($host,$port);
        socket_set_timeout($this->sock,2,0);
    }

    function close() {
        if ($this->sock)  fclose($this->sock);
        $this->sock = NULL;
    }

    function write($buffer) {
        $buffer = str_replace(chr(255),chr(255).chr(255),$buffer);
        fwrite($this->sock,$buffer);
    }

    function getc() {
        return fgetc($this->sock);
    }

    function read_till($what) {
        $buf = '';
        while (1) {
            $IAC = chr(255);
             
            $DONT = chr(254);
            $DO = chr(253);
             
            $WONT = chr(252);
            $WILL = chr(251);
             
            $theNULL = chr(0);

            $c = $this->getc();
             
            if ($c === false) return $buf;
            if ($c == $theNULL) {
                continue;
            }

            // if ($c == "1") {
            // continue;
            // }

            if ($c != $IAC) {
                $buf .= $c;

                if ($what == (substr($buf,strlen($buf)-strlen($what)))) {
                    return $buf;
                }
                else {
                    continue;
                }
            }

            $c = $this->getc();
             
            if ($c == $IAC) {
                $buf .= $c;
            }
            else if (($c == $DO) || ($c == $DONT)) {
                $opt = $this->getc();
                // echo "we wont ".ord($opt)."\n";
                fwrite($this->sock,$IAC.$WONT.$opt);
            }
            elseif (($c == $WILL) || ($c == $WONT)) {
                $opt = $this->getc();
                // echo "we dont ".ord($opt)."\n";
                fwrite($this->sock,$IAC.$DONT.$opt);
            }
            else {
                // echo "where are we? c=".ord($c)."\n";
            }
        }
    }
}



$etime=microtime(true);//获取程序执行结束的时间
$total=$etime-$stime;  //计算差值
echo PHP_EOL."执行时间:{$total} 秒".PHP_EOL;

脚本中会自动读取交换机当前配置,并且根据 ---- More ---- 自动输入空格分屏获取全部配置。本需求中cmdA按顺序执行,cmdD则按倒序执行。

本脚本中可以放置在crontab中定时监控。


评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注