#!/usr/bin/python import argparse, glob, operator, os, random, shutil, subprocess, sys, signal, time shouldQuit = False movingFiles = False def getFreeSpaceForDir(dir): stats = os.statvfs(dir) return (stats.f_bavail * stats.f_frsize) def getFreePercentForDir(dir): stats = os.statvfs(dir) total = (stats.f_blocks) avail = (stats.f_bavail) return (total - avail) / float(total) def getFileSize(fullPath): return os.path.getsize(fullPath) def sizeof_fmt(num, suffix='B'): for unit in ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']: if abs(num) < 1024.0: return "%3.1f %s%s" % (num, unit, suffix) num /= 1024.0 return "%.1f %s%s" % (num, 'Yi', suffix) def signal_handler(signal, frame): if movingFiles: print("\nWill quit when file has been moved.\nMoving File...") global shouldQuit shouldQuit = True else: sys.exit(0) if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('-c', '--checkonly', action='store_true', help="Check only, don't move any files.") parser.add_argument('-p', '--percent', type=int, default=7, help="The percentage difference between the most full dir and least full dir that will stop balancing.") cmdargs = parser.parse_args() SGDIRS = [] SGgrp = "Default" signal.signal(signal.SIGINT, signal_handler) print("\nBalance MythTV Storage Group Directories\nPress Ctrl+C to quit") # Get Storage Groups from MythDB try: from MythTV import MythDB mythDB = MythDB() records = mythDB.getStorageGroup() except: print("Couldn't connect to MythTV database.") sys.exit(1) # Get Storage Group directories for record in records: if record.groupname == SGgrp: dirname = record.dirname SGDIRS.append(dirname) # If there are less than 2 directories defined bail as we can't move anything if len(SGDIRS) < 2: print("There are less than 2 directories defined. Exiting.") sys.exit(0) while not shouldQuit: SGDIRSdata = [] print("\n------------------------------------------------") print("'" + SGgrp + "' Storage Group Directories - Percent Used:") # Get percent free and size free for directory in SGDIRS: # Check if SG path exists if not os.path.exists(directory): print(" " + directory + " - Not Mounted") continue freePcent = getFreePercentForDir(directory) freeSize = getFreeSpaceForDir(directory) SGDIRSdata.append([directory, freePcent, freeSize]) print(" %s - %.2f%%" % (directory, freePcent * 100)) # Sort data on percent free SGDIRSdata = sorted(SGDIRSdata, reverse=True, key=operator.itemgetter(1)) #print SGDIRSdata # Check if SG has any ts, mpg or nuv files i=0 for dir in SGDIRSdata: mostFull = SGDIRSdata[i] i=i+1 if len(glob.glob1(mostFull[0],"*.ts")) or len(glob.glob1(mostFull[0],"*.mpg")) or len(glob.glob1(mostFull[0],"*.nuv")): break else: if i == 1: print("------------------------------------------------") print(" " + mostFull[0] + " - NO files to move") leastFull = SGDIRSdata[-1] print("------------------------------------------------") print("Most Used Storage Group Directory with files to move: ") print(" %s - %.2f%%" % (mostFull[0], mostFull[1] * 100)) print("Least Used Storage Group Directory: ") print(" %s - %.2f%%" % (leastFull[0], leastFull[1] * 100)) # Check if mostFull and leastFull are within the percent var of each other if mostFull[1] - (float(cmdargs.percent) / 100) < leastFull[1]: print("\nThe most used and least used storage group directories are\nwithin " + str(cmdargs.percent) + "% used of each other. No files will be moved.") sys.exit() # Get random file from most used dir fileToMove = random.choice([f for f in os.listdir(mostFull[0]) if f.endswith(".ts") or f.endswith(".mpg") or f.endswith(".nuv")]) filePathToMove = mostFull[0] + "/" + fileToMove # Check that the file isn't too big for least used dir fileSize = getFileSize(filePathToMove) if (fileSize > getFreeSpaceForDir(leastFull[0])): # Too big to move print(filePathToMove + " is too big to move to " + leastFull[0]) sys.exit() # Move file if cmdargs.checkonly: print("------------------------------------------------") print("Check Only option was used. No files were moved.") shouldQuit = True else: isBusy = True while isBusy: if shouldQuit: sys.exit(0) print("------------------------------------------------") print("Checking System Status...") if subprocess.call(["/usr/bin/python", "/usr/bin/idle.py", "-s"]): print(" System is busy. The file will not be moved.") print(" Waiting 5 minutes before trying again.") time.sleep(300) else: isBusy = False print("------------------------------------------------") print("Move File:") print(" " + filePathToMove) print(" Size: " + sizeof_fmt(os.path.getsize(filePathToMove))) print("To:") print(" " + leastFull[0]) print(" Available: " + sizeof_fmt(getFreeSpaceForDir(leastFull[0]))) print("Moving File...") movingFiles = True try: shutil.move(filePathToMove, leastFull[0]) # eg. src and dest are the same file except shutil.Error as e: print(('Error: %s' % e)) except IOError as e: print(('Error: %s' % e.strerror)) # Remove png files print("------------------------------------------------") print("Removing png Files:") pngFiles = glob.glob(filePathToMove + "*.png") for p in pngFiles: os.remove(p) print(" " + p) movingFiles = False