#!/usr/bin/env python
#-*- coding:UTF-8 -*-
"""
@Item   :  Rsync Backup
@Author :  Villiam Sheng
@Group  :  Linux Group
@Date   :  2012-08-13
@Funtion:
                rsync_conf:     Configuration rsync server, and the server
                #res[os.path.join(root,fpath)] =  int((time.time() - os.stat(os.path.join(root,fpath)).st_ctime) / 86910)
                #int((time.time() - os.stat(os.path.join(root,fpath)).st_ctime) / 86910)
                #try:
                #    res[os.path.join(root,fpath)] =  time.strptime((fpath.split(`_`)[2]),`%Y%m%d%H%M%S`).tm_yday           #擷取檔名,得到時間天數,
                #except Exception,e:
                #    print e
                #res[os.path.join(root,fpath)] =  int((time.time() - os.stat(os.path.join(root,fpath)).st_ctime) / 86910)
                Central idea:
"""
import os,sys,time,re,socket,threading,json,base64,traceback,ConfigParser,fcntl,struct
from rsync_log import rsync_log
from rsync_post import rsync_post
from  statvfs import F_BLOCKS,F_BAVAIL,F_BSIZE
pcg = 0
""" 生成斐波那契數列"""
lists = []
a,b = 0,1
while b <= 365:
    a,b = b ,a+b
    lists.append(b)
class rsync_thread(threading.Thread):
    def __init__(self,path):
        threading.Thread.__init__(self)
        self.log = rsync_log()
        self.path = path
    """ 計算當前磁碟的使用百分比"""
    def disk(self):
        try:
            vfs = os.statvfs(self.path)
            disk_full = int(vfs[F_BLOCKS]*vfs[F_BSIZE]/1024/1024/1024)
            disk_free = int(vfs[F_BAVAIL]*vfs[F_BSIZE]/1024/1024/1024)
            return  `%.1f`%(float(disk_full - disk_free) / disk_full * 100)
        except:
            self.log.log_info(`rsync_info.err`,`dfile.disk`,traceback.print_exc())
            return traceback.print_exc()
    def run(self):
        global pcg
        old_df = []     # 上一年的刪除歷史檔案
        new_df = []     # 今年的刪除歷史檔案
        sf = []         # 保留的歷史檔案
        res = {}        # 所有檔案的天數及檔案的路徑
        rs = 0          # 刪除檔案的總和
        size = []       # 獲取刪除檔案的大小
        msize = []      # 今天備份所有檔案的大小
        tday_size = []  # 今天備份檔案的大小
        ms = 0          # 今天備份檔案的總和
        year = time.localtime().tm_year
        """ 得到檔案的天數,以檔名作為key,天數作為value """
        for root,dirs,files in os.walk(self.path):
            for fpath in files:
                res[os.path.join(root,fpath)] =  time.localtime(os.stat(os.path.join(root,fpath)).st_ctime).tm_yday
        """ 判斷檔案的天數是否符合斐波那契數列,符合條件append到sf列表中,不符合append df列表中 """
        for v,k in  res.items():
            if k in lists:
                sf.append(k)
                self.log.log_info(`log_info.save`,`dfile.rsync_thread`,`%s:::%s`%(v,k))
            elif k not in lists:
                if year != time.localtime(os.stat(v).st_ctime).tm_year:
                    old_df.append({v:k})
                else:
                    new_df.append({v:k})
            """
            try:
                for s in  range(len(new_df)):
                    for f,k in new_df[s].items():
                        tday_size.append(k)
                if max({}.fromkeys(tday_size).keys()) == k:
                    msize.append(os.path.getsize(f))
            except:
                pass
            """
        c = []
        pcg = float(self.disk())
        """ 判斷今天是否有新的檔案備份,在刪除的列表中刪除最後一天的資料,但必須保證磁碟的使用百分比大於 %55 """
        if time.localtime().tm_yday in res.values():
            if len(old_df) != 0:
                for s in  range(len(old_df)):
                    for f,k in old_df[s].items():
                        c.append(k)
                for s in  range(len(old_df)):
                    for f,k in old_df[s].items():
                        if min({}.fromkeys(c).keys()) == k and pcg > 91:
                            size.append(os.path.getsize(f))
                            os.system(`rm -frv %s` %f)
                            self.log.log_info(`log_info.delete`,`remove cmd`,`rm -frv %s %s`%(f,k))
                        elif pcg <= 91:
                            break
                        pcg = float(self.disk())
            elif len(new_df) != 0:
                for s in  range(len(new_df)):
                    for f,k in new_df[s].items():
                        c.append(k)
                for s in  range(len(new_df)):
                    for f,k in new_df[s].items():
                        if min({}.fromkeys(c).keys()) == k and pcg > 91:
                            size.append(os.path.getsize(f))
                            os.system(`rm -frv %s` %f)
                            self.log.log_info(`log_info.delete`,`remove cmd`,`rm -frv %s %s`%(f,k))
                        elif pcg <= 91:
                            break
                        pcg = float(self.disk())
            for s in size:
                rs += s
            #for m in msize:
            #    ms += m
            self.log.log_info(`log_info.delete`,`Disk release %s %s MB`%(self.path,rs /1024/1024),`Disk append %s %s MB`%(self.path,ms /1024/1024))
        else:
            self.log.log_info(`log_info.delete`,`Disk files `,` %s No update file` %self.path)
            sys.exit()
class rsync_dfile(object):
    def __init__(self):
        self.log = rsync_log()
        self.rsync_post = rsync_post()
    def work(self):
        fp =  open(`/proc/mounts`,`r`)
        m_info=fp.readlines()
        fp.close()
        data = {}
        sections = []
        for i in m_info:
            if i.find(`data=ordered`) != -1 or  i.find(`mfs`) != -1 or i.find(`nfs`) != -1:
                if os.path.ismount(str(i.split()[1])):
                    if str(i.split()[1]) != `/`:
                        if str(i.split()[1]) != `/root`:
                            if str(i.split()[1]) != `/var`:
                                if len(i.split()[1]) != 1:
                                    if not i.find(`sunrpc`) != -1:
                                        rs_thread = rsync_thread(i.split()[1])
                                        rs_thread.start()
        while threading.active_count() > 1:
            time.sleep(1)
        conf = ConfigParser.ConfigParser()
        conf.read(`/etc/rsyncd.conf`)
        try:
            for i in conf.sections():
                if i != `global`:
                    sections.append(i)
            for i in sections:
                vfs = os.statvfs(conf.get(i,`path`))
                disk_full = int(vfs[F_BLOCKS]*vfs[F_BSIZE]/1024/1024/1024)
                disk_free = int(vfs[F_BAVAIL]*vfs[F_BSIZE]/1024/1024/1024)
                s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
                try:
                    ip = socket.inet_ntoa(fcntl.ioctl(s.fileno(),0x8915,struct.pack(`24s`,`eth0`))[20:24])
                except:
                    ip = socket.inet_ntoa(fcntl.ioctl(s.fileno(),0x8915,struct.pack(`24s`,`eth1`))[20:24])
                t_info={`flag`:0,`store_ip`:ip,`store_module`:i,`store_path`:conf.get(i,`path`),`disk_full`:disk_full,`disk_free`:disk_free,`action`:`rsync_renew`}
                data[`param`] = base64.b64encode(json.dumps(t_info))
                self.rsync_post.work(data)
                self.log.log_info(`rsync_info.err`,`dfile.work`,t_info)
        except Exception,e:
            t_info={`flag`:1,`store_ip`:ip,`store_module`:i,`store_path`:conf.get(i,`path`),`disk_full`:disk_full,`disk_free`:disk_free,`action`:`rsync_renew`}
            data[`param`] = base64.b64encode(json.dumps(t_info))
            self.rsync_post.work(data)
            self.log.log_info(`rsync_info.err`,`dfile.work`,e)
if __name__ == "__main__":
    rs = rsync_dfile()
    while True:
        rs.work()
        if pcg <= 91:
             break