上一篇讲了方法论,关于主备环境的一致性问题。
这周终于要写脚本了。
一、背景:
主备双机环境下,备机作为热备主机,只在有故障情况下使用。在备机启动业务前,需检查备机环境是否与主机完全一致,主要包括启动程序、启动配置,以及jar包。
二、功能及配置说明
(一)功能说明:
1、可配置多个程序模块。通过[NAME XXX] ..... [/NAME]来标记。
2、对city中的配置值,以逗号为分隔符,对制定配置sh,para项,替换XX。
3、对配置项sh、para中,主备机相同结构文件进行核对。
4、可以对本地文件进行核对,配置:local即可。
5、可以自行扩展配置项,并写配置分支函数,来实现扩展功能。如:检查文件目录、检查MQ状态等。
(二)配置说明:其中[NAME XXXX]可以自行配置
[NAME abcd] #abcd为模块名 Hostname=node1 #对比文件所在主机,ssh无密码登录 city=zs,zh,sz #替换下面配置中的XX地市,注意XX为大写,以逗号为分隔符。 sh=/home/hadoop/*/_perl/_1403/ms/XX/XX.sh para=/home/hadoop/*/_perl/_1403/ms/XX.txt local=/home/hadoop/*/_perl/_1403/ms/zh.txt,/home/hadoop/*/_perl/_1403/ms/t7.txt #本地文件比较,以逗号为分隔符 jar_lib_chk=1 #1表示核对$jar_lib,0表示不核对,源自*-background.jar 这个jar包是否依赖公共lib下面的包,如果依赖的话那些也需要一致。 jar_lib=/home/hadoop/*/_perl/_1403/ms/zs [/NAME] #固定格式作为该段配置结束
三、使用方法:
1、主备之间需可以ssh无密码登录,即可从运行主机ssh到对照主机执行命令。
2、各类文件:
# 程序运行的主目录
my $rundir = ‘/home/hadoop/*/_perl/_1403/ms‘;
# 运行日志
my $log_file = $rundir. "/chk_ms.log";
# 错误报告
my $log_error = $rundir. "/chk_ms.err";
# 配置文件
my $cfg_file = $rundir . "/chk_ms.cfg";
3、运行方式:修改配置文件chk_ms.cfg,以及运行目录$rundir。主要脚本和配置文件需在同一级目录。直接启动即可。如:
../chk_ms.pl
四、源码:
#!/usr/bin/perl
#########################
##chk_ms.pl,核查主备一致性
##主要功能:
##1、可配置多个程序模块。通过[NAME XXX] ..... [/NAME]来标记。
##2、对city中的配置值,以逗号为分隔符,对制定配置sh,para项,替换XX。
##3、对配置项sh、para中,主备机相同结构文件进行核对。
##4、可以对本地文件进行核对,配置:local即可。
##5、可以自行扩展配置项,并写配置分支函数,来实现扩展功能。如:检查文件目录、检查MQ状态等。
##lanfity@126.com
##version v1.0
##########################
use strict;
use Fcntl qw(:DEFAULT :flock);
# 程序运行的主目录
my $rundir = ‘/home/hadoop/*/_perl/_1403/ms‘;
# 运行日志
my $log_file = $rundir. "/chk_ms.log";
# 错误报告
my $log_error = $rundir. "/chk_ms.err";
# 配置文件
my $cfg_file = $rundir . "/chk_ms.cfg";
sub write_log
{
my $time=scalar localtime;
open (HDW,">>",$log_file);
flock (HDW,LOCK_EX);
print HDW $time," ",join ‘ ‘,@_,"\n";
flock (HDW,LOCK_UN);
close HDW;
}
sub write_err
{
my $time=scalar localtime;
open (HDW,">>",$log_error);
flock (HDW,LOCK_EX);
print HDW "ERROR: ",$time," ",join ‘ ‘,@_,"\n";
print "ERROR: ",join ‘ ‘,@_,"\n";
flock (HDW,LOCK_UN);
close HDW;
}
#获取文件的序列号,使用cksum
sub get_sn
{
my $file=$_[0];
chomp(my $sn=`cksum $file 2>/dev/null|awk ‘{print \$1" "\$2}‘ `);
if ($sn eq "") {
write_err "local $file not exist";
write_log "ERR:local $file not exist";
}
return $sn;
}
#获取其他主机文件的序列号,使用ssh信任机制,以及cksum
sub ssh_sn
{
my ($file,$host)=@_;
chomp(my $sn=`ssh $host "cksum $file 2>/dev/null"|awk ‘{print \$1" "\$2}‘`);
if ($sn eq "") {
write_err "remote $file not exist";
write_log "ERR:remote $file not exist";
}
return $sn;
}
#对多个地市的配置进行对比,参数为$0:对比的文件名;$1:"city"字段;$2:对比的远端ip。输出:对比结果,print或写入$log_err
sub mult_city
{
my $hostname=$_[2];
my $city=$_[1];
my @city=split /\,/,$city;
foreach $city(@city){
my $char=$_[0];
$char =~ s/XX/$city/g; #所有XX替换
write_log " mult_city start $city is $char";
my $loc=get_sn($char);
my $rem=ssh_sn($char,$hostname); ###待调试ssh后再测试
if ( $loc ne $rem ){
write_err "$city $char is different\n";
write_log "ERR:$city $char is different\n";
}
}
}
#获取对应目录的文件名。参数为:$1:对比的目录。输出:数组,文件名。
sub get_file
{
my ($dir_file,$catch)=@_;
my $path=$dir_file."/*.".$catch;
my @dir=glob($path);
return @dir;
}
# 扫描函数
sub do_scan
{
# 先读取配置文件,获取要扫描的程序,以及扫描哪些选项
my $scan_cfg = get_config();
# 在 for循环里逐个程序项扫描
for my $hid (keys %{$scan_cfg}) {
write_log "Checking $hid ....";
print "Checking $hid ....\n";
my $hostname=$$scan_cfg{$hid}{"Hostname"};
my $city=$$scan_cfg{$hid}{"city"};
for my $cfg_key (keys %{$$scan_cfg{$hid}})
{
my $value=$$scan_cfg{$hid}{$cfg_key};
next if $cfg_key eq "jar_lib";
write_log "$hid start $cfg_key is $value";
# 检查本地文件是否一致
if ($cfg_key eq ‘local‘) {
my ($file1,$file2)=split /\,/,$value;
if ( &get_sn($file1) ne &get_sn($file2) )
{write_err "$cfg_key is different,$file1 : $file2";
write_log "$cfg_key is different,$file1 : $file2";
}
# 检查启动shell是否一致
} elsif ($cfg_key eq ‘sh‘){
mult_city($value,$city,$hostname);
# 检查启动配置是否一致
} elsif ($cfg_key eq ‘para‘){
mult_city($value,$city,$hostname);
# 检查jar库是否一致
}elsif ($cfg_key eq ‘jar_lib_chk‘){
if ( $value == "1" ){
my $dir=$$scan_cfg{$hid}{"jar_lib"};
write_log " now checking jar_lib $dir";
foreach my $file(get_file($dir,"jar")){ #匹配关键字jar
my $loc=get_sn($file);
my $rem=ssh_sn($file,$hostname);
if ( $loc ne $rem ){
write_err "jar_lib $dir is different, please sync. ";
write_log "jar_lib $dir is different, please sync. ";
next;
}
}
}
}
}
print "Checking $hid END\n";
write_log "Checking $hid END.";
}
}
# 该函数用来读取配置文件,并将结果放入一个 Hash。
sub get_config
{
my %config;
open (HDR,$cfg_file) or die "[EMERG] can‘t open cfg_file: $!\n";
#[NAME XXXX]
#Hostname=XXX
#city=fs,zs,zh,st,sw,cz,jy,zq,qy,sg,yf,sz #替换下面配置中的XX地市,注意XX为大写,逗号为分隔符
#sh=/crmapp/_run/_market/_bin/_XX/SubsStatusSynToBillMain_XX.sh
#para=/crmapp/_conf/_XX/_market/SubsStatusSynToBillMain.properties
#
#jar_lib_chk=1 #1表示核对$jar_lib,0表示不核对,源自ngcrm-background.jar 这个jar包 是否依赖公共lib下面的包, 如果依赖的话 那些也需要一致。
#jar_lib=/crmapp/_run/_lib
#
#local=/crmapp/_run/_lib/qloader.jar,/crmapp/_run/_lib/ngcrm-background.jar #本地文件比较,以逗号为分隔符
#[/NAME] #本节配置结束
while(<HDR>)
{
next if /^$/;
next if /^\s*\#/;
if ( my ($hid) = /\[NAME\s+(\w+)\]/ ) {
while (<HDR>) {
next if /^$/;
next if /^\s*\#/;
last if /\[\/NAME\]/;
chomp;
my ($cfg_key,$cfg_value) = split /=/;
$cfg_key =~ s/^\s+|\s+$//g;
$cfg_value =~ s/\#.*$//;
$cfg_value =~ s/^\s+|\s+$//g;
$cfg_value =~ s/^\"|\"$//g;
$cfg_value =~ s/^\‘|\‘$//g;
$config{$hid}->{$cfg_key} = $cfg_value;
}
}
}
close HDR;
return \%config;
}
do_scan;本文出自 “bss运维小窝” 博客,请务必保留此出处http://bssop.blog.51cto.com/8233954/1376599
原文:http://bssop.blog.51cto.com/8233954/1376599