+ Параметры, работа в режиме демона

This commit is contained in:
Iu 2024-03-31 12:27:24 +03:00
parent 17d3e3bf7b
commit 8e22979c39
1 changed files with 63 additions and 10 deletions

View File

@ -2,41 +2,94 @@
import os import os
from shutil import disk_usage from shutil import disk_usage
import time import time
import argparse
BS = 1024**2 BS = 1024**2
def set_utilization(fs, utilization_percent=0.6, baloon_filename='baloon', hysteresis_percent=0.01): def set_utilization(fs, utilization_percent=0.6, baloon_filename='baloon', hysteresis_percent=0.01, quiet=False):
fs = os.path.realpath(fs) fs = os.path.realpath(fs)
du = disk_usage(fs) du = disk_usage(fs)
if utilization_percent < 0.1 or utilization_percent > 0.9: if utilization_percent < 0.1 or utilization_percent > 0.9:
raise ValueError('utilization_percent must be between 0.1 and 0.9') raise ValueError('utilization_percent must be between 0.1 and 0.9')
if hysteresis_percent < 0.0001 or hysteresis_percent > 0.1: if hysteresis_percent < 0 or hysteresis_percent > 0.1:
raise ValueError('hysteresis_percent must be between 0.0001 and 0.1') raise ValueError('hysteresis_percent must be between 0 and 0.1')
hysteresis = int(du.total * hysteresis_percent) hysteresis = int(du.total * hysteresis_percent)
if hysteresis < BS: hysteresis = BS if hysteresis < BS: hysteresis = BS
to_be_wasted = int(((du.used+du.free) * utilization_percent) - ((du.used+du.free) - du.free))
if not quiet:
print(f'hysteresis: {hysteresis}bytes') print(f'hysteresis: {hysteresis}bytes')
print(f'total: {round(du.total/ 2**30, 3)}GB, used: {round(du.used/ 2**30, 3)}GB, free: {round(du.free/ 2**30, 3)}GB usage: {round(du.used * 100 / (du.used+du.free), 3)}%') print(f'total: {round(du.total/ 2**30, 3)}GB, used: {round(du.used/ 2**30, 3)}GB, free: {round(du.free/ 2**30, 3)}GB usage: {round(du.used * 100 / (du.used+du.free), 3)}%')
to_be_wasted = int(((du.used+du.free) * utilization_percent) - ((du.used+du.free) - du.free))
print(f'to_be_wasted: {round(to_be_wasted/ 2**30, 3)}GB ') print(f'to_be_wasted: {round(to_be_wasted/ 2**30, 3)}GB ')
if to_be_wasted < -hysteresis: if to_be_wasted < -hysteresis:
to_be_trimmed = abs(to_be_wasted) to_be_trimmed = abs(to_be_wasted)
baloon_size = os.path.getsize(os.path.join(fs, baloon_filename)) baloon_size = os.path.getsize(os.path.join(fs, baloon_filename))
if baloon_size> to_be_trimmed: if baloon_size> to_be_trimmed:
os.truncate(os.path.join(fs, baloon_filename), baloon_size - to_be_trimmed) os.truncate(os.path.join(fs, baloon_filename), baloon_size - to_be_trimmed)
print(f'trimmed {to_be_trimmed} Bytes') if not quiet: print(f'trimmed {to_be_trimmed} Bytes')
else: print(f'can\'t trim {baloon_size} < {to_be_trimmed}Bytes') elif not quiet: print(f'can\'t trim {baloon_size} < {to_be_trimmed}Bytes')
elif to_be_wasted > hysteresis: elif to_be_wasted > hysteresis:
with open(os.path.join(fs, baloon_filename) , 'ab') as f: with open(os.path.join(fs, baloon_filename) , 'ab') as f:
last = 0 last = 0
writed = to_be_wasted writed = to_be_wasted
while to_be_wasted > 0: while to_be_wasted > 0:
if time.time() - last > 1: if time.time() - last > 1:
print(f'left {int(to_be_wasted/ 2**30)}GB \r', end='') if not quiet: print(f'left {int(to_be_wasted/ 2**30)}GB \r', end='')
last = time.time() last = time.time()
write_size = min(to_be_wasted, BS) write_size = min(to_be_wasted, BS)
f.write(b'x' * write_size) f.write(b'x' * write_size)
to_be_wasted -= write_size to_be_wasted -= write_size
print(f'Done, added {writed} bytes') if not quiet: print(f'Done, added {writed} bytes')
if not quiet:
du = disk_usage(fs)
print(f'total: {round(du.total/ 2**30, 3)}GB, used: {round(du.used/ 2**30, 3)}GB, free: {round(du.free/ 2**30, 3)}GB usage: {round(du.used * 100 / (du.used+du.free), 3)}%')
def hysteresis_type(arg):
MAX_VAL = 10
MIN_VAL = 0
try:
f = float(arg)
except ValueError:
raise argparse.ArgumentTypeError("Must be a floating point number")
if f < MIN_VAL or f > MAX_VAL:
raise argparse.ArgumentTypeError("Argument must be < " + str(MAX_VAL) + " and > " + str(MIN_VAL))
return f
parser = argparse.ArgumentParser(description='Baloon utilize your disk space')
parser.add_argument('-v', '--version', action='version', version='%(prog)s 1.0')
parser.add_argument('-u', '--utilization', type=int, metavar="[10-90]", choices=range(10, 91), help='percentage of utilization', default=60)
parser.add_argument('-b', '--baloon', type=str, metavar="baloon", help='name of the baloon file', default='baloon')
parser.add_argument('-s', '--hysteresis', type=hysteresis_type, metavar="[0-10]", help='hysteresis, in percentage of disk size', default=1)
parser.add_argument('-f', '--fs', type=str, action='append', metavar="fs", help='path to the filesystem', required=True)
parser.add_argument('-d', '--daemon', action='store_true', help='daemon mode')
parser.add_argument('-i', '--interval', type=int, help='interval in seconds to work in daemon mode', default=60*60)
args = parser.parse_args()
fss = []
baloon_filename = args.baloon
hysteresis_percent = args.hysteresis/100.0
utilization_percent = args.utilization/100.0
daemon_mode = args.daemon
daemon_mode_interval = args.interval
for fs in args.fs:
fs = os.path.realpath(fs)
if not os.path.isdir(fs):
raise ValueError(f'{fs} is not a directory')
fss.append(fs)
if not daemon_mode:
for p in vars(args):
print(f'{p}: {getattr(args, p)}')
for fs in fss:
set_utilization(fs, utilization_percent, baloon_filename, hysteresis_percent)
else:
while True:
for fs in fss:
if os.path.isdir(fs):
try:
set_utilization(fs=fs, utilization_percent=utilization_percent, baloon_filename=baloon_filename, hysteresis_percent=hysteresis_percent, quiet=True)
except Exception as e:
pass
time.sleep(daemon_mode_interval)