summaryrefslogtreecommitdiffstats
path: root/linhes/linhes-system/balance_storage_groups.py
blob: 0dd4b0188b768fdd5382df9440250b4c832a6964 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!/usr/bin/python

import argparse, glob, operator, os, random, shutil, subprocess, sys, signal
shouldQuit = 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):
    print("\nWill quit when file has been moved.\nMoving File...")
    global shouldQuit
    shouldQuit = True

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()

        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])))

        # Move file
        if cmdargs.checkonly:
            print("------------------------------------------------")
            print("Check Only option was used. No files were moved.")
            shouldQuit = True
        else:
            print("------------------------------------------------")
            print("Checking System Status...")
            if subprocess.call(["/usr/bin/python2", "/usr/LH/bin/idle.py", "-s"]):
                print("  System is busy. The file will not be moved.")
                sys.exit()
            print("Moving File...")
            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)