05/8/14

perl 批量执行命令脚本

一、环境描述

监控发现多台服务器负载异常,登陆服务器查看,发现salt-minion进程狂多(>100个),而且cpu占用100%。从而导致服务器负责也飙上去。

二、原因

通过分析,应该是由于slat-master进程关闭,各个服务器的salt-minion客服端无法与服务端进行交互,导致客户端堆积需求salt-minion进程,消耗大量内存和cpu资源。

三、处理步骤

1、重启服务端salt-master进程,结果发现:服务端网卡及负载波动太大,并且执行salt命令会超时,无返回接口。

2、查询salt-minion日志,发现大量如下报错:

[salt.crypt ][ERROR   ] The Salt Master has cached the public key for this node, this salt minion will wait for 10 seconds before attempting to re-authenticate

经核实,该问题在salt 0.7.1版本中确实存在,主要时由于mine模块功能不全导致,后期版本已经修复这个bug。我们可以通过修改mine模块代码,限制salt-minion开启进程数。

3,面对salt相关命令执行无效的问题,采用将服务端和客服端的/etc/salt/kpi目录下缓存文件删除,并重新salt-key -A所有客户端minion连接。但服务器比较多,需要批量处理。

4、批量脚步采用了网上现成代码进行修改,主要逻辑是:使用perl的Net::SSH::Expect模块,模拟ssh到各个服务器执行一系列命令,从而达到解决问题的目的。

5、脚步包括一个perl脚步salt_minion_batch_restart.pl + 命令列表 commend_list.txt + 服务器ip_port列表 ip_list.txt

6、执行完脚步之后,slat-key -A 。然后,通过salt命令检查,如:salt ‘*’ cmd .run ‘uptime’。

四、代码展示

1、salt_minion_batch_restart.pl

#!/usr/bin/perl

#use strict;

use Net::SSH::Expect;

use Net::SCP::Expect;

 

my @ssh_list;

my $ip_list=’ip_list.txt’;

my $command_txt=’command_list.txt’;

 

open FH,$ip_list;

while(<FH>){

if (!($_ =~ m/\#|^$/)) #删除注释和空行

{

@ssh_list=split;

print “======= “,$ssh_list[0],” =======\n”;

print “开始时间:”,get_time(),”\n”;

print “正在登陆”,$ssh_list[0],”…\n”;

&salt_minion_restart(“$ssh_list[0]“,”$ssh_list[1]“);

print “结束时间:”,get_time().”\n”;

}

}

close FH;

 

sub  salt_minion_restart(){

my($host,$port)=@_;

my $ssh= Net::SSH::Expect->new(

host    =>      $host,

port    =>      $port,

user    =>      “root”,

no_terminal     =>0,

raw_pty=>1,

timeout=>       3,

);

$ssh->debug(0);

$ssh->run_ssh or die “SSH process cann’t start :$!”;

my $line;

if ($line=$ssh->read_line()){

print $line .”\n”;

if ($line =~ /Last/)

{

print “$ssh_list[0] has logined\n”;

}

else {

$ssh->send(“yes\n”);

print “$ssh_list[0] send yes\n “;

}

}

 

open F1,$command_txt;

while(<F1>){

if (!($_ =~ m/\#|^$/)) #删除注释和空行

{

my @command=split/\n/,$_;

$result=$ssh->exec(“$command[0]“);

print $command[0],” –>”,$result,”\n”;

}

#print $ssh_list[0],”命令执行完毕\n”;

}

close F1;

 

$ssh->close();

 

}

 

sub get_time {

my $time = shift || time();

my ($sec,$min,$hour,$day,$mon,$year,$wday) = localtime($time);

$year += 1900;

$mon += 1;

$min = ’0′.$min if length($min) < 2;

$sec = ’0′.$sec if length($sec) < 2;

$mon = ’0′.$mon if length($mon) < 2;

$day = ’0′.$day if length($day) < 2;

$hour = ’0′.$hour if length($hour) < 2;

my $weekday = (‘Sun’,’Mon’,’Tue’,’Wed’,’Thu’,’Fri’,’Sat’)[$wday];

my $time_now = “$year-$mon-$day $hour:$min:$sec $weekday”;

return $time_now;

}

 

2、commend_line.txt

test -e /etc/salt/pki/minion && (cd /etc/salt/pki && rm -rf minion)|| echo ‘not exist’ #判断pki下缓存目前是否存在,存在就删除,不存在的话就输出‘not exist’

test -e /etc/init.d/salt-minion && /etc/init.d/salt-minion start #判断salt-minion是否存在,存在的话就启动

ps aux|grep salt  #检查确认salt-minion是否启动成功

 

3、ip_list.txt

192.168.1.133 222

192.168.1.134 222

192.168.1.135 222

192.168.1.136 222

192.168.1.137 222

192.168.1.138 222

192.168.1.139 222

4、存在问题

没有完善的日志功能,从何导致执行过程中ctrl+c 终止了脚本,又要重新开始执行一遍。后期解决这个问题。

10/30/13

配置文件备份方案(expect+shell)

需求描述:备份所有线上服务器squid、httpd、mysql、nginx的配置文件

环境:在公司内网采用expect+shell脚本模式,进行批量备份。expect脚本通过ssh登录服务器,从本地copy一份shell脚本到服务器上,然后执行脚本将配置文件遍历出来传到指定服务器进行备份。

1、expect脚本batch_backupconf.exp

#!/usr/bin/expect
set timeout 30
set target_host [lrange $argv 0 0]
set target_port [lrange $argv 1 1]
set source_host sphinx1906.phpdba.com
set source_port 9191
set login_name root
set password 123456

spawn ssh $target_host -p $target_port -l $login_name -i /root/.ssh/id_rsa

expect {
        "*(yes/no)?"         {
                send  "yes\r"
                exp_continue
        }
        "*assword:"      {
                send "$password\r"
        }
}

expect "#"
send "uname\n"
expect "Linux"
send_user "Now you can do some operation on this terminal\n"
expect "#"
send "scp -P $source_port $source_host:/root/chen-123/expect/backup_conf.sh 
        \/root/ \n"
exec sleep 15
send_user "开始执行代码 \n"
send "sh backup_conf.sh $target_host \n"
expect {
        "*(yes/no)?"    {
                send  "yes\r"
                exp_continue
        }
        "*assword:"     {
                send "$password\r"

        }
}
exec sleep 5
expect "#"
send "rm -f backup_conf.sh \n"
send_user "\nThis is $source_host!\n操作完成!\n"
exec sleep 1
exit

2、shell脚本backup_conf.sh

#!/bin/sh
if [ $# != 1 ];then
        echo "请传参数!"
        exit 1;
fi

for i in `find /opt/phpdba/ -maxdepth 4 -type f -regex ".*\.\(com\|conf\|cnf\)" 
          \-print|grep -E 'httpd\.conf|nginx\.conf|squid\.conf|*\.com|*\.cnf'`;
       do        
        tmp=`echo "$i"|sed s#/#_#g`        
        echo $i
        scp -Pxxx $i xxx.xxx.xxx.xxx:/opt/phpdba/backup_conf/$1_${tmp}
         \`date +%Y%m%d%H`
done

3、batch_backupconf.sh

#!/bin/sh
cat iplist_all|while read line
do
        host_ip=`echo "$line"|awk -F'\t' '{print $1}'`
        host_port=`echo "$line"|awk -F'\t' '{print $2}'`
        echo $host_ip"->"$host_port
        /usr/bin/expect batch_backupconf.exp $host_ip $host_port
done

4、iplist_all
192.168.0.9 22
192.168.0.213 22
192.168.0.114 29622
192.168.0.116 29622