14 python 監控文件或目錄變化
Python實戰-從菜鳥到大牛的進階之路 作者:極客學院 投票推薦 加入書簽 留言反饋
我們經常會遇到監控一個文件或目錄的變化,如果有變化,把文件上傳備份至備份主機,並且我們還要監控上傳過程是否有問題等,根據此需求,查閱了相關的一些材料,編寫如下腳本實現這個功能:
#!/usr/bin/env python #coding=utf-8 ####################### # #status wd gss sql file changed #date:2013-08-26 王偉 #文件有變化上傳至備份主機,上傳之後驗證文件是否正確 # #######################import paramiko,os,sys,datetime,time,mysqldbfrom pyinotify import watchmanager, notifier, processevent, in_delete, in_create,in_modify\''\''\''create table `wddel_log.status_sql` ( `ip` varchar(16) not nullment \''機器ip\'', `tar_name` varchar(50) not nullment \''備份文件名字\'', `md5` varchar(50) not nullment \''備份文件 md5\'', `g` int(2) not nullment \''0:成功;1:失敗\'', `error_log` varchar(100) not nullment \''錯誤日誌\'', `uptime` datetime not nullment \''更新時間\'', key `ip` (`ip`), key `uptime` (`uptime`)) engine=innodb default charset=utf8\''\''\''#日誌表創建腳本gm_path=\''/home/asktao/\''center_hostname=\''192.168.1.100\''center_username=\''root\''center_password=\''123456\''center_port=63008def log2db(ip,tar_name,md5,g,error=\''0\''):#刪除日誌入庫 try:tar_name = os.path.split(tar_name)[1]now = time.strftime("%y-%m-%d %h:%m:%s")conn = mysqldb.connect(host = \''192.168.1.104\'',user = \''root\'',passwd = \''1q2w3e4r\'',charset=\''utf8\'',connect_timeout=20)cursor = conn.cursorsql = "select ip from wddel_log.status_sql where ip=\''%s\''" % ipcursor.execute(sql)res = cursor.fetchallif len(res)==0: inster_sql = "insert into wddel_log.status_sql values(\''%s\'',\''%s\'',\''%s\'',%s,\''%s\'',\''%s\'')" % (ip,tar_name,md5,g,error,now) cursor.execute(inster_sql) connmitelse: update_sql = "update wddel_log.status_sql set md5=\''%s\'',g=\''%s\'',error_log=\''%s\'',uptime=\''%s\'' where ip=\''%s\''" % (md5,g,error,now,ip) cursor.execute(update_sql) connmitcursor.closeconn.close except exception,e:print edef find_ip:#獲取本地 eth0 的 ip 地址 ip = os.popen("/sbin/ip a|grep \''global eth0\''").readlines[0].split[1].split("/")[0] if "192.168." in ip:ip = os.popen("/sbin/ip a|grep \''global eth1\''").readlines[0].split[1].split("/")[0] return ipdef md5sum(file_name):#驗證 sql 打包文件的 md5 if os.path.isfile(file_name):f = open(file_name,\''rb\'')py_ver = sys.version[:3]if py_ver == "2.4": import md5 as hashlibelse: import hashlib md5 = hashlib.md5(f.read).hexdigest f.close return md5 else:return 0def center_md5(file_name):#上傳至備份中心的文件的 md5 try:s=paramiko.sshclients.set_missing_host_key_policy(paramiko.autoaddpolicy)s.connect(hostname = center_hostname,port=center_port,username=center_username, password=center_password)conm = "/usr/bin/md5sum %s" % file_namestdin,stdout,stderr=s.execmand(conm)result = stdout.readlines[0].split[0].strips.closereturn result except exception,e:return edef back_file(ip,tar_name,tar_md5):#上傳文件到備份中心 remote_dir=\''/data/sql\'' file_name=os.path.join(remote_dir,os.path.split(tar_name)[1]) try:t=paramiko.transport((center_hostname,center_port))t.connect(username=center_username,password=center_password)sftp=paramiko.sftpclient.from_transport(t)sftp.put(tar_name,file_name)t.close#print "%s back_file ok" % tar_nameos.remove(tar_name)remot_md5=center_md5(file_name)if remot_md5 == tar_md5: log2db(ip,tar_name,tar_md5,0)else: log2db(ip,tar_name,tar_md5,1,\''remot_md5!=tar_md5\'') except exception,e:#print "connect error!"log2db(ip,tar_name,tar_md5,1,e)os.remove(tar_name)def back_sql:#執行備份 ip = find_ip tar_name = "/tmp/%s.tar.gz" % ip sql_conn = "/usr/bin/find %s -type f -name \''*.sql\''|/usr/bin/xargs /bin/tar zcvpf %s" % (gm_path,tar_name) sql_tar = os.popen(sql_conn).readlines tar_md5 = md5sum(tar_name) if tar_md5 != 0:back_file(ip,tar_name,tar_md5) else:error_log = "%s not find" % tar_namelog2db(ip,tar_name,tar_md5,0,error_log)ss pfilepath(processevent):#文件變化的觸發 def process_in_create(self, event):if os.path.splitext(event.name)[1] == ".sql": text = "create file: %s " % os.path.join(event.path, event.name) #print text back_sql def process_in_modify(self, event):if os.path.splitext(event.name)[1] == ".sql": text = "modify file: %s " % os.path.join(event.path, event.name) #print text back_sqldef fsmonitor:#主監控函數 back_sql#運行腳本先備份 sql 文件 wm = watchmanager mask = in_create |in_modify notifier = notifier(wm, pfilepath) wdd = wm.add_watch(gm_path, mask, rec=true) print \''now starting monitor %s\'' % (gm_path) while true:try : notifier.process_events if notifier.check_events:notifier.read_eventsexcept keyboardinterrupt: notifier.stop breakif __name__ == "__main__": fsmonitor </pre>
此腳本中主要用到 paramiko 和 pyinotify 模塊,關於 paramiko 的講解可以參見:http://wangwei007.blog.51cto/68019/1058726一文,pyinotify 的用法可以參見官方文檔:https://github/seb-m/pyinotify/wiki/events-types
#!/usr/bin/env python #coding=utf-8 ####################### # #status wd gss sql file changed #date:2013-08-26 王偉 #文件有變化上傳至備份主機,上傳之後驗證文件是否正確 # #######################import paramiko,os,sys,datetime,time,mysqldbfrom pyinotify import watchmanager, notifier, processevent, in_delete, in_create,in_modify\''\''\''create table `wddel_log.status_sql` ( `ip` varchar(16) not nullment \''機器ip\'', `tar_name` varchar(50) not nullment \''備份文件名字\'', `md5` varchar(50) not nullment \''備份文件 md5\'', `g` int(2) not nullment \''0:成功;1:失敗\'', `error_log` varchar(100) not nullment \''錯誤日誌\'', `uptime` datetime not nullment \''更新時間\'', key `ip` (`ip`), key `uptime` (`uptime`)) engine=innodb default charset=utf8\''\''\''#日誌表創建腳本gm_path=\''/home/asktao/\''center_hostname=\''192.168.1.100\''center_username=\''root\''center_password=\''123456\''center_port=63008def log2db(ip,tar_name,md5,g,error=\''0\''):#刪除日誌入庫 try:tar_name = os.path.split(tar_name)[1]now = time.strftime("%y-%m-%d %h:%m:%s")conn = mysqldb.connect(host = \''192.168.1.104\'',user = \''root\'',passwd = \''1q2w3e4r\'',charset=\''utf8\'',connect_timeout=20)cursor = conn.cursorsql = "select ip from wddel_log.status_sql where ip=\''%s\''" % ipcursor.execute(sql)res = cursor.fetchallif len(res)==0: inster_sql = "insert into wddel_log.status_sql values(\''%s\'',\''%s\'',\''%s\'',%s,\''%s\'',\''%s\'')" % (ip,tar_name,md5,g,error,now) cursor.execute(inster_sql) connmitelse: update_sql = "update wddel_log.status_sql set md5=\''%s\'',g=\''%s\'',error_log=\''%s\'',uptime=\''%s\'' where ip=\''%s\''" % (md5,g,error,now,ip) cursor.execute(update_sql) connmitcursor.closeconn.close except exception,e:print edef find_ip:#獲取本地 eth0 的 ip 地址 ip = os.popen("/sbin/ip a|grep \''global eth0\''").readlines[0].split[1].split("/")[0] if "192.168." in ip:ip = os.popen("/sbin/ip a|grep \''global eth1\''").readlines[0].split[1].split("/")[0] return ipdef md5sum(file_name):#驗證 sql 打包文件的 md5 if os.path.isfile(file_name):f = open(file_name,\''rb\'')py_ver = sys.version[:3]if py_ver == "2.4": import md5 as hashlibelse: import hashlib md5 = hashlib.md5(f.read).hexdigest f.close return md5 else:return 0def center_md5(file_name):#上傳至備份中心的文件的 md5 try:s=paramiko.sshclients.set_missing_host_key_policy(paramiko.autoaddpolicy)s.connect(hostname = center_hostname,port=center_port,username=center_username, password=center_password)conm = "/usr/bin/md5sum %s" % file_namestdin,stdout,stderr=s.execmand(conm)result = stdout.readlines[0].split[0].strips.closereturn result except exception,e:return edef back_file(ip,tar_name,tar_md5):#上傳文件到備份中心 remote_dir=\''/data/sql\'' file_name=os.path.join(remote_dir,os.path.split(tar_name)[1]) try:t=paramiko.transport((center_hostname,center_port))t.connect(username=center_username,password=center_password)sftp=paramiko.sftpclient.from_transport(t)sftp.put(tar_name,file_name)t.close#print "%s back_file ok" % tar_nameos.remove(tar_name)remot_md5=center_md5(file_name)if remot_md5 == tar_md5: log2db(ip,tar_name,tar_md5,0)else: log2db(ip,tar_name,tar_md5,1,\''remot_md5!=tar_md5\'') except exception,e:#print "connect error!"log2db(ip,tar_name,tar_md5,1,e)os.remove(tar_name)def back_sql:#執行備份 ip = find_ip tar_name = "/tmp/%s.tar.gz" % ip sql_conn = "/usr/bin/find %s -type f -name \''*.sql\''|/usr/bin/xargs /bin/tar zcvpf %s" % (gm_path,tar_name) sql_tar = os.popen(sql_conn).readlines tar_md5 = md5sum(tar_name) if tar_md5 != 0:back_file(ip,tar_name,tar_md5) else:error_log = "%s not find" % tar_namelog2db(ip,tar_name,tar_md5,0,error_log)ss pfilepath(processevent):#文件變化的觸發 def process_in_create(self, event):if os.path.splitext(event.name)[1] == ".sql": text = "create file: %s " % os.path.join(event.path, event.name) #print text back_sql def process_in_modify(self, event):if os.path.splitext(event.name)[1] == ".sql": text = "modify file: %s " % os.path.join(event.path, event.name) #print text back_sqldef fsmonitor:#主監控函數 back_sql#運行腳本先備份 sql 文件 wm = watchmanager mask = in_create |in_modify notifier = notifier(wm, pfilepath) wdd = wm.add_watch(gm_path, mask, rec=true) print \''now starting monitor %s\'' % (gm_path) while true:try : notifier.process_events if notifier.check_events:notifier.read_eventsexcept keyboardinterrupt: notifier.stop breakif __name__ == "__main__": fsmonitor </pre>
此腳本中主要用到 paramiko 和 pyinotify 模塊,關於 paramiko 的講解可以參見:http://wangwei007.blog.51cto/68019/1058726一文,pyinotify 的用法可以參見官方文檔:https://github/seb-m/pyinotify/wiki/events-types