Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2538729
  • 博文数量: 308
  • 博客积分: 5547
  • 博客等级: 大校
  • 技术积分: 3782
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-24 09:47
个人简介

hello world.

文章分类

全部博文(308)

分类: 系统运维

2013-12-11 13:36:39

    在上一篇,那个Shell写好后,领导说,你的那个Shell只能监控到服务器本地指定目录文件的变化。不过当监控多台服务器上的文件变化,那么就需要部署多个脚本,比较麻烦。建议是,在数据库上创建一个表,记录需要监控的服务器,文件。程序自动扫描进行监控。
    自己静下心来思考,觉得领导说的还是很有道理。在数据库上创建一张表,记录要监控的文件信息。方便维护。当需要添加要监控的文件,在数据库中添加一条记录,即可实现。数据库SQL代码如下:

点击(此处)折叠或打开

  1. -- Create table
  2. create table TI_FILE_CHECK
  3. (
  4.   FILE_ID NUMBER(16) not null,
  5.   SERVER_IP VARCHAR2(20) not null,
  6.   USER_NAME VARCHAR2(40) not null,
  7.   PASS_WORD VARCHAR2(40) not null,
  8.   PROJECT_NAME VARCHAR2(40) not null,
  9.   FILE_NAME VARCHAR2(100) not null,
  10.   LOCAL_SIZE NUMBER(16) not null,
  11.   LOCAL_TIME DATE not null,
  12.   FILE_PATH VARCHAR2(500) not null,
  13.   OS_TYPE VARCHAR2(1) default 0 not null,
  14.   RECV_PHONENUM VARCHAR2(20) not null,
  15.   IS_UP VARCHAR2(1) default 0 not null,
  16.   UP_SIZE NUMBER(16),
  17.   UP_TIME DATE,
  18.   REMARK VARCHAR2(500)
  19. )
  20. tablespace TBS_ITF_DAT1
  21.   pctfree 10
  22.   initrans 1
  23.   maxtrans 255
  24.   storage
  25.   (
  26.     initial 64K
  27.     next 1M
  28.     minextents 1
  29.     maxextents unlimited
  30.   );
  31. -- Add comments to the table
  32. comment on table TI_FILE_CHECK
  33.   is '文件监控表';
  34. -- Add comments to the columns
  35. comment on column TI_FILE_CHECK.FILE_ID
  36.   is '文件ID';
  37. comment on column TI_FILE_CHECK.SERVER_IP
  38.   is '服务器IP';
  39. comment on column TI_FILE_CHECK.USER_NAME
  40.   is '登陆服务器的用户名';
  41. comment on column TI_FILE_CHECK.PASS_WORD
  42.   is '登陆服务器的密码';
  43. comment on column TI_FILE_CHECK.PROJECT_NAME
  44.   is '程序名称';
  45. comment on column TI_FILE_CHECK.FILE_NAME
  46.   is '文件名称';
  47. comment on column TI_FILE_CHECK.LOCAL_SIZE
  48.   is '原始文件大小(在UNIX/LINUX操作系统上使用 ls -l 获取的文件的大小值)';
  49. comment on column TI_FILE_CHECK.LOCAL_TIME
  50.   is '原始文件日期(在UNIX/LINUX操作系统上使用 ls -l 获取的文件日期的写入值)';
  51. comment on column TI_FILE_CHECK.FILE_PATH
  52.   is '文件绝对路径(包含文件名)';
  53. comment on column TI_FILE_CHECK.OS_TYPE
  54.   is '操作系统类型(0:AIX),现在只支持AIX系统,如果其他版本,请扩展Shell脚本程序';
  55. comment on column TI_FILE_CHECK.RECV_PHONENUM
  56.   is '接收短信的号码';
  57. comment on column TI_FILE_CHECK.IS_UP
  58.   is '文件是否更新:0:没有更新;1:文件已经更新';
  59. comment on column TI_FILE_CHECK.UP_SIZE
  60.   is '更新后的大小(数据的来源是ls -l获取的最新值)';
  61. comment on column TI_FILE_CHECK.UP_TIME
  62.   is '更新的日期(数据的来源是ls -l获取的最新值)';
  63. comment on column TI_FILE_CHECK.REMARK
  64.   is '发送的短信内容';
  65. -- Create/Recreate primary, unique and foreign key constraints
  66. alter table TI_FILE_CHECK
  67.   add constraint PK_FILE_CHECK_FILE_ID primary key (FILE_ID)
  68.   using index
  69.   tablespace TBS_ITF_DAT1
  70.   pctfree 10
  71.   initrans 2
  72.   maxtrans 255
  73.   storage
  74.   (
  75.     initial 64K
  76.     next 1M
  77.     minextents 1
  78.     maxextents unlimited
  79.   );
   
    我自己捋了捋,思路。首先在数据库上创建表,然后用一个程序读取要监控的数据,生成文件放到本地。读取数据库数据,生成文件。当时上网查了查资料,很多资料都是用shell脚本代码,通过sqlplus 里面的SQL查询语句。我觉得也可以,可是试了后,才发现不行。因为我需要的数据有一定的格式。方便下一步读取数据。最后为了完成数据的格式化。最终决定,写个java程序,用java程序读取数据库数据,生成数据文件。生成数据文件后,下一步操作,那就是使用Shell一次读取生成文件的一行数据,登陆到远程服务器上,查询哪个文件信息。想办法,将结果在返回到调用端。经过查找资料,在UNIX上有一个expect,可以模拟登陆,完成登陆完成查询操作。关于查询结果的返回,可以使用scp将数据copy到本地。当然了这些都需要调用端,通过传递参数实现。结果全部带回到本地后,下面就好弄了。通过循环读取文件,比较文件的日期是否发生了变化,这个当然了,使用awk。不过我们使用的AIX服务器,后面日期用的英文。因此自己编写shell函数,进行翻译操作。最终将发生变化的数据记录到文件中。然后用awk读取结果文件拼凑成SQL语句,提交到数据库。说了这么多,估计你也听的累了,先放上我写的Shell程序,代码如下:

点击(此处)折叠或打开

  1. #!/bin/sh
  2. # 程序描述: 扫描数据库表中的数据,根据IP,用户名,密码,文件路径等信息
  3. # 扫描文件的大小,日期是否发生了变化,如果变动,记录变动的信息。
  4. # 作者: 程晓鹏
  5. # 日期:2013.12.03
  6. # 运行程序命令:nohup ./FileCheck.sh &

  7. #监控程序所在的目录
  8. FC_SOURCE_HOME=/ngbss/mddms/FileCheck
  9. #监控程序处理结果备份目录
  10. FC_RESULT_HOME=$FC_SOURCE_HOME/result
  11. #监控程序,返回数据的临时目录
  12. FC_TMP_HOME=$FC_SOURCE_HOME/tmp

  13. #被比对的原始数据文件,以此文件做标准
  14. FC_CHECK_FILENAME=CHECK_LIST.TXT
  15. #经过程序处理,最终发生变化,记录结果的文件
  16. FC_RESULT_FILENAME=RESULT_CHECKLIST.TXT
  17. #根据结果文件,生成插入数据库的SQL文件
  18. FC_SQL_FILENAME=SQL_CHECKLIST.TXT

  19. #部署监控程序的IP
  20. FC_IP=127.0.0.1
  21. #部署监控程序的用户名
  22. FC_USERNAME=peng
  23. #部署监控程序的密码
  24. FC_PASSWORD=abc_321
  25. #连接SQLPLUS的信息
  26. FC_SQLPLUS_INFO=sa/sa_123@db1

  27. #睡眠时间(单位:)
  28. FC_SLEEP_TIME=5

  29. #获取更新的文件大小(参数1:文件的绝对路径, 参数2:操作系统的版本[0:为AIX])
  30. function GetUpdateFileSize
  31. {
  32.   if [ $2 -eq "0" ]; then
  33.     echo $(ReadFileSize_AIX_6_1 $1);
  34.   fi
  35. }

  36. #获取文件的更新时间(参数1:文件的绝对路径, 参数2:操作系统的版本[0:为AIX)
  37. function GetFileUpdateTime
  38. {
  39.   if [ $2 -eq "0" ]; then
  40.     echo $(ReadFileUpdateTime_AIX_6_1 $1);
  41.   fi
  42. }

  43. #获取文件大小[AIX操作系统支持的](参数1:文件的绝对路径)
  44. function ReadFileSize_AIX_6_1
  45. {
  46.   local result=`cat "$1" | awk '{print $5}'`; #文件大小
  47.   echo $result;
  48. }

  49. #获取文件的更新时间,AIX6.1支持的函数(参数为文件的绝对路径)
  50. function ReadFileUpdateTime_AIX_6_1
  51. {
  52.   local month=`cat "$1" | awk '{print $6}'`; #
  53.   local day=`cat "$1" | awk '{print $7}'`; #
  54.   local tmp=`cat "$1" | awk '{print $8}'`; #,或者时间的字符串
  55.   
  56.   local tmplen=`echo $tmp | awk '{print length($0)}'`; #长度
  57.   local v_year="";
  58.   local v_month="";
  59.   local v_day="";
  60.   local v_time="";

  61.   if [ $tmplen -gt 4 ]
  62.   then
  63.     v_year=$(GetCurrentYear); #当字符长度大于4,则该字段为时间,因此v_year赋值为当前所属的年份
  64.     v_time=$tmp; #ls命令中的时间
  65.   else
  66.     v_year=$tmp; #文件的年份
  67.     v_time="00:00"; #使用默认值
  68.   fi

  69.   v_month=$(ConvertMonthToNumber "$month");
  70.   v_day=$day;
  71.   echo $v_year-$v_month-$v_day $v_time:00; #返回的格式为yyyy-MM-dd hh:mm:ss
  72. }

  73. #将英文表示的月份变更为数字(01-12)
  74. function ConvertMonthToNumber
  75. {
  76.   local result="";
  77.   case $1 in
  78.   "Jan") result="01";;
  79.   "Feb") result="02";;
  80.   "Mar") result="03";;
  81.   "Apr") result="04";;
  82.   "May") result="05";;
  83.   "Jun") result="06";;
  84.   "Jul") result="07";;
  85.   "Aug") result="08";;
  86.   "Sep") result="09";;
  87.   "Oct") result="10";;
  88.   "Nov") result="11";;
  89.   "Dec") result="12";;
  90.   esac

  91.   echo $result;
  92. }

  93. #获取当前年份(4为数字)
  94. function GetCurrentYear
  95. {
  96.   echo `date +%Y`;
  97. }

  98. #获取当前日期,时间
  99. function GetCurrentTime
  100. {
  101.   echo `date +"%Y-%m-%d %T"`;
  102. }

  103. #画线操作,隔离日志
  104. function PrintLine
  105. {
  106.   echo "-------------------------------------------------------------------------------\n"
  107. }

  108. #将日期字符串,返回为日期的字符串,如'2010-11-29 14:38:00'
  109. #返回值为:20101129143800
  110. #此函数,主要是为了比较比较日期大小。将日期字符串,转化为int,进行比较
  111. #(没办法 AIX 不支持 date -d,也只能采用变通的方法了)
  112. function GetDateNumber
  113. {
  114.   #下面执行的命令,其实很简单,就是将日期之间的'-',':',空格删除操作。
  115.   local result=`echo $1 | sed -e 's/-//g' | sed -e 's/ //g' | sed -e 's/://g'`;
  116.   echo $result;
  117. }

  118. #获取文件的记录数(参数为文件的全路径)
  119. function GetFileLineCount
  120. {
  121.   result=0;
  122.   if [ -f "$1" ]; then
  123.     result=`wc -l "$1" | awk '{print $1}'`;
  124.   fi
  125.   echo $result;
  126. }

  127. #清空文件内容
  128. function ClearFileContent
  129. {
  130.   if [ -f "$1" ]; then
  131.     cat /dev/null > "$1";
  132.   fi
  133. }

  134. #使用java程序,下载比对源CheckList文件
  135. function DownLoadCheckListFile
  136. {
  137.   cd $FC_SOURCE_HOME/ExportDataFile;
  138.   MYDIR=`pwd`;
  139.   CLASSPATH=$MYDIR;
  140.   for f in `find $MYDIR/lib -type f -name "*.jar"`
  141.   do
  142.     CLASSPATH=$CLASSPATH:$f; #加载java程序需要的classpath
  143.   done

  144.   java -Xmx256m -cp $CLASSPATH com.epro.client.ExportData "$FC_SOURCE_HOME" "$FC_CHECK_FILENAME";
  145. }

  146. #读取对比源,CheckList文件(参数为文件的全路径)
  147. #每读一行,获取这条记录的最新信息,放到临时目录中
  148. function ExportUpdateFile
  149. {
  150.   cat $FC_SOURCE_HOME/$FC_CHECK_FILENAME | while read line
  151.   do
  152.     local fileID=`echo $line | awk '{print $1}'`; #文件ID
  153.     local ip=`echo $line | awk '{print $2}'`; #IP地址
  154.     local username=`echo $line | awk '{print $3}'`; #用户名
  155.     local password=`echo $line | awk '{print $4}'`; #密码
  156.     local filepath=`echo $line | awk '{print $10}'`; #文件路径
  157.     expect $FC_SOURCE_HOME/FileInfo.exp $ip $username $password $filepath $FC_IP $FC_USERNAME $FC_PASSWORD $FC_TMP_HOME $fileID; #调用expect查看文件的信息
  158.   done
  159. }

  160. #进行数据处理,使用$FC_CHECK_FILENAME作为比对源文件,和$FC_TMP_HOME目录下的最新文件信息做比较
  161. #当发现比对源文件的文件大小,或者日期发现了变化,进行记录
  162. #比对数据源的内容如下:(不含下一行的第一个字符'#'
  163. #1 127.0.0.1 peng peng123 炫铃程序 CRBT.jar 13929 2010-11-29 14:38:00 /ngbss/otherapp/pengtest/CRBT/lib/CRBT.jar 18538305950 0
  164. function DisposeData
  165. {
  166.   $(ClearFileContent $FC_SOURCE_HOME/$FC_RESULT_FILENAME); #清空文件内容
  167.   cat $FC_SOURCE_HOME/$FC_CHECK_FILENAME | while read line
  168.   do
  169.     local lo_fileID=`echo $line | awk '{print $1}'`; #文件ID
  170.     local lo_ip=`echo $line | awk '{print $2}'`; #IP地址
  171.     local lo_projectname=`echo $line | awk '{print $5}'`; #项目程序名称
  172.     local lo_filename=`echo $line | awk '{print $6}'`; #文件名
  173.     local lo_size=`echo $line | awk '{print $7}'`; #比对源大小
  174.     local lo_date=`echo $line | awk '{print $8 " " $9}'`; #比对文件日期
  175.     local lo_fullpath=`echo $line | awk '{print $10}'`; #文件全路径
  176.     local lo_recvnum=`echo $line | awk '{print $11}'`; #接收短信的号码
  177.     local lo_os_type=`echo $line | awk '{print $12}'`; #操作系统的类型 0:AIX操作系统
  178.     
  179.     #当临时文件中含有更新的文件时,进行时间,大小的比对操作
  180.     if [ -f $FC_TMP_HOME/$lo_fileID ]
  181.     then
  182.        local up_size=$(GetUpdateFileSize $FC_TMP_HOME/$lo_fileID $lo_os_type);
  183.        local up_time=$(GetFileUpdateTime $FC_TMP_HOME/$lo_fileID $lo_os_type);
  184.        local int_datelocal=$(GetDateNumber "$lo_date");
  185.        local int_dateup=$(GetDateNumber "$up_time");
  186.        if [ $int_dateup -gt $int_datelocal ]; then #当文件的最新日期,大于数据库记录的原始日期时
  187.          echo $lo_fileID $lo_ip $lo_projectname $lo_filename $up_size $up_time $lo_fullpath $lo_recvnum >> $FC_SOURCE_HOME/$FC_RESULT_FILENAME;
  188.        fi
  189.     fi
  190.   done
  191. }

  192. #构建SQL语句文件(参数为生成SQL文件的路径)
  193. function BuildSqlFile
  194. {
  195.   $(ClearFileContent $FC_SOURCE_HOME/$FC_SQL_FILENAME); #清空文件内容
  196.   if [ -f $FC_SOURCE_HOME/$FC_RESULT_FILENAME ]; then
  197.     #更新文件监控的信息
  198.     awk '{print "UPDATE ti_file_check SET is_up='\''1'\'', up_size="$5", up_time=to_date('\''"$6" "$7"'\'','\''yyyy-MM-dd hh24:mi:ss'\''), remark='\''[文件更新]:您好:主机:"$2",程序名称:"$3", 文件名:"$4", 已更新。 更新日期为:"$6" "$7", 文件大小:"$5",请知悉。'\'' WHERE file_id = "$1";"}' $FC_SOURCE_HOME/$FC_RESULT_FILENAME >> $FC_SOURCE_HOME/$FC_SQL_FILENAME;
  199.     #发送短信
  200.     awk '{print "INSERT INTO ucr_itf1.sms_out_tab(row_no, message, deal_flag, destaddr) VALUES(ucr_itf1.seq_sms_out.nextval, '\''[文件更新]:您好:主机:"$2",程序名称:"$3", 文件名:"$4", 已更新。 更新日期为:"$6" "$7", 文件大小:"$5",请知悉。'\'', '\''0'\'', '\''"$9"'\'');"}' $FC_SOURCE_HOME/$FC_RESULT_FILENAME >> $FC_SOURCE_HOME/$FC_SQL_FILENAME;
  201.   fi
  202. }

  203. #提交生成的SQl语句
  204. function CommitSqlFile
  205. {
  206.   if [ -f $FC_SOURCE_HOME/$FC_SQL_FILENAME ]; then
  207.     . /ngbss/mddms/.profile
  208.     cmd=`sqlplus $FC_SQLPLUS_INFO <
  209.       @$FC_SOURCE_HOME/$FC_SQL_FILENAME
  210.     commit;
  211.     exit;
  212.     EOF`;
  213.   fi
  214. }

  215. #开始运行(并打印相关的日志信息)
  216. function run
  217. {
  218.   echo $(PrintLine);
  219.   echo $(PrintLine);
  220.   echo $(GetCurrentTime) 调用java程序,开始进行读取数据库,生成$FC_SOURCE_HOME/$FC_CHECK_FILENAME;
  221.   DownLoadCheckListFile;
  222.   linecount=$(GetFileLineCount $FC_SOURCE_HOME/$FC_CHECK_FILENAME); #获取文件记录数
  223.   if [ $linecount -gt 0 ]; then
  224.     echo $(GetCurrentTime) 读取数据库,生成文件完成。
  225.     echo $(GetCurrentTime) 根据"$FC_SOURCE_HOME"/"$FC_CHECK_FILENAME"文件内容,开始进行获取文件当前的最新更新数据
  226.     ExportUpdateFile;
  227.     echo $(GetCurrentTime) 获取每个最新数据成功,文件存放在"$FC_TMP_HOME"目录下
  228.     echo $(GetCurrentTime) 开始进行文件比对操作
  229.     DisposeData;
  230.     echo $(GetCurrentTime) 文件比对操作完成
  231.     linecount=$(GetFileLineCount $FC_SOURCE_HOME/$FC_RESULT_FILENAME); #获取文件记录数
  232.     if [ $linecount -gt 0 ]; then
  233.       echo $(GetCurrentTime) 比较结果如下:
  234.       cat $FC_SOURCE_HOME/$FC_RESULT_FILENAME;
  235.       echo $(GetCurrentTime) 开始生成SQL文件"$FC_SQL_FILENAME"
  236.       BuildSqlFile;
  237.       echo $(GetCurrentTime) 生成SQL完成,SQL文件内容如下:
  238.       cat $FC_SOURCE_HOME/$FC_SQL_FILENAME;
  239.       echo $(GetCurrentTime) 将SQL文件中的数据,进行执行操作
  240.       CommitSqlFile;
  241.       echo $(GetCurrentTime) SQL文件执行成功
  242.       echo $(GetCurrentTime) 更新成功
  243.       strdate=`date +"%Y_%m%d_%H%M%S"`; #当前日期字符串 2013_1210_085503
          #进行结果备份操作
          cp $FC_SOURCE_HOME/$FC_RESULT_FILENAME $FC_RESULT_HOME/$FC_RESULT_FILENAME.$strdate;
          cp $FC_SOURCE_HOME/$FC_SQL_FILENAME $FC_RESULT_HOME/$FC_SQL_FILENAME.$strdate;
        else
          echo $(GetCurrentTime) 没有文件进行更新
        fi
      else
        echo $(GetCurrentTime) 数据库中,没有要进行比对的数据
      fi
    }

    while true
    do
      run;
      sleep $FC_SLEEP_TIME; #进行休眠后,继续运行
    done
    为了方便,编写了一个方法,记录一些日志。也就是上面的run方法了。因为监控程序要不停的运行,运行完成后,休眠一段时间后,继续运行。
    代码中,登陆到远程服务器上,通过调用expect,我们可以看到后面传递了很多参数,我编写的FileInfo.exp文件,代码如下:

点击(此处)折叠或打开

  1. #!/usr/bin/expect -f

  2. # 程序描述:登录到远程主机,进行文件的查询操作,
  3. # 并将结果返回到,调用的主机上
  4. # 作者:程晓鹏
  5. # 日期:2013.12.04

  6. #连接的远程主机IP
  7. set ipaddress [lindex $argv 0]
  8. #连接远程主机的用户名
  9. set username [lindex $argv 1]
  10. #连接远程主机的密码
  11. set passwd [lindex $argv 2]
  12. #查询远程主机,文件的路径
  13. set filepath [lindex $argv 3]

  14. #将文件scp到目的地的相关参数
  15. #文件返回的IP
  16. set recv_ip [lindex $argv 4]
  17. #文件返回所用的用户名
  18. set recv_username [lindex $argv 5]
  19. #文件返回所用的密码
  20. set recv_password [lindex $argv 6]
  21. #文件返回的目录
  22. set recv_path [lindex $argv 7]
  23. #文件返回的文件名
  24. set recv_filename [lindex $argv 8]
  25. set timeout 1
  26. #进行登录
  27. spawn ssh $username@$ipaddress
  28. expect {
  29. "yes/no" { send "yes\r";exp_continue }
  30. #模拟输入密码,进行远程主机的登陆
  31. "password:" { send "$passwd\r" }
  32. }
  33. expect "*from*"
  34. #进行查询操作,将结果存入临时文件中
  35. send "LANG=en_US; ls -l $filepath > /tmp/FileCheck.tmp\r"
  36. #进行远程copy操作
  37. send "scp /tmp/FileCheck.tmp $recv_username@$recv_ip:$recv_path/$recv_filename\r"
  38. expect {
  39. "yes/no" { send "yes\r";exp_continue }
  40. #模拟输入密码
  41. "password:" { send "$recv_password\r" }
  42. }
  43. expect eof
    写的注释,比较多,就不解释了。当然了启动这个程序,也很简单使用nohup命令即可完成。对了方便停掉文件监控程序,也写了一个简单的Shell脚本,代码如下:

点击(此处)折叠或打开

  1. #!/bin/sh
  2. u=`whoami`

  3. ps -ef|grep "$u"|grep FileCheck.sh|grep -v grep|awk '{print $2}' >a.pid
  4.  for pid in `cat a.pid`
  5.  do
  6.   kill -9 $pid
  7.  done
  8.  echo "kill FileCheck done!"
    文件监控启动后,我们使用nohup进行启动,因此会在当前目录下生成一个nohup.out文件,这里面记录了相关的日志信息,方便以后核对。
1.当文件发生变化时,日志会出现如下的内容:

2.正常的监控,没有文件发生变化,输出的日志内容如下:

3.最后一种就是,读取数据库没有要比对的文件,输出的日志内容如下:

最后,当想程序对文件进行监控,其实也很简单。就是更新local_size,local_time为最新的大小。别忘了is_up字段更新为'0';
最后附上我这个程序所有的文件代码。FileCheck.rar ExportDataFile.rar
阅读(5715) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~