上一篇讲了方法论,关于主备环境的一致性问题。
这周终于要写脚本了。
一、背景:
主备双机环境下,备机作为热备主机,只在有故障情况下使用。在备机启动业务前,需检查备机环境是否与主机完全一致,主要包括启动程序、启动配置,以及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