From 17d3e3bf7b4ec68d1a95819f3274f623653fd580 Mon Sep 17 00:00:00 2001 From: Iu Date: Sun, 31 Mar 2024 11:10:47 +0300 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=D0=9A=D0=BE=D1=80=D1=80=D0=B5=D0=BA?= =?UTF-8?q?=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=BA=D0=B0=20=D0=B2=D1=8B=D1=87?= =?UTF-8?q?=D0=B8=D1=81=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20Use%,=20=D0=BA?= =?UTF-8?q?=D0=B0=D0=BA=20=D1=8D=D1=82=D0=BE=20=D0=B4=D0=B5=D0=BB=D0=B0?= =?UTF-8?q?=D0=B5=D1=82=20df?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 ++ src/main.py | 32 ++++++++++++++++++++------------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 5d381cc..cb3d3be 100644 --- a/.gitignore +++ b/.gitignore @@ -160,3 +160,5 @@ cython_debug/ # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ +/mnt/ +/img \ No newline at end of file diff --git a/src/main.py b/src/main.py index 3fd6bcc..3323f38 100644 --- a/src/main.py +++ b/src/main.py @@ -5,30 +5,38 @@ import time BS = 1024**2 -def set_utilization(du, utilization_percent=0.6, baloon_filename='baloon'): - fs = os.path.realpath(du) +def set_utilization(fs, utilization_percent=0.6, baloon_filename='baloon', hysteresis_percent=0.01): + fs = os.path.realpath(fs) du = disk_usage(fs) - print(f'total: {int(du.total/ 2**30)}GB, used: {int(du.used/ 2**30)}GB, free: {int(du.free/ 2**30)}GB') - to_be_wasted = int((du.total * utilization_percent) - du.used) - print(f'to_be_wasted: {int(to_be_wasted/ 2**30)}GB') - if to_be_wasted < 0: + if utilization_percent < 0.1 or utilization_percent > 0.9: + raise ValueError('utilization_percent must be between 0.1 and 0.9') + if hysteresis_percent < 0.0001 or hysteresis_percent > 0.1: + raise ValueError('hysteresis_percent must be between 0.0001 and 0.1') + hysteresis = int(du.total * hysteresis_percent) + if hysteresis < BS: hysteresis = BS + 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)}%') + 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 ') + if to_be_wasted < -hysteresis: to_be_trimmed = abs(to_be_wasted) baloon_size = os.path.getsize(os.path.join(fs, baloon_filename)) if baloon_size> to_be_trimmed: os.truncate(os.path.join(fs, baloon_filename), baloon_size - to_be_trimmed) - else: print(f'can\'t trim {baloon_size} > {to_be_trimmed}') - elif to_be_wasted > 0: + print(f'trimmed {to_be_trimmed} Bytes') + else: print(f'can\'t trim {baloon_size} < {to_be_trimmed}Bytes') + elif to_be_wasted > hysteresis: with open(os.path.join(fs, baloon_filename) , 'ab') as f: last = 0 + writed = to_be_wasted while to_be_wasted > 0: if time.time() - last > 1: - print('\r', end='') - print(f'left {int(to_be_wasted/ 2**30)}GB ', end='') + print(f'left {int(to_be_wasted/ 2**30)}GB \r', end='') last = time.time() write_size = min(to_be_wasted, BS) f.write(b'x' * write_size) to_be_wasted -= write_size - print('Done ') + print(f'Done, added {writed} bytes') -set_utilization('.') \ No newline at end of file + From 8e22979c39c8ec157ba94a25050e3de131fb8335 Mon Sep 17 00:00:00 2001 From: Iu Date: Sun, 31 Mar 2024 12:27:24 +0300 Subject: [PATCH 2/2] =?UTF-8?q?+=20=D0=9F=D0=B0=D1=80=D0=B0=D0=BC=D0=B5?= =?UTF-8?q?=D1=82=D1=80=D1=8B,=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=20?= =?UTF-8?q?=D0=B2=20=D1=80=D0=B5=D0=B6=D0=B8=D0=BC=D0=B5=20=D0=B4=D0=B5?= =?UTF-8?q?=D0=BC=D0=BE=D0=BD=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.py | 73 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 10 deletions(-) diff --git a/src/main.py b/src/main.py index 3323f38..9d4d58b 100644 --- a/src/main.py +++ b/src/main.py @@ -2,41 +2,94 @@ import os from shutil import disk_usage import time +import argparse 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) du = disk_usage(fs) if utilization_percent < 0.1 or utilization_percent > 0.9: raise ValueError('utilization_percent must be between 0.1 and 0.9') - if hysteresis_percent < 0.0001 or hysteresis_percent > 0.1: - raise ValueError('hysteresis_percent must be between 0.0001 and 0.1') + if hysteresis_percent < 0 or hysteresis_percent > 0.1: + raise ValueError('hysteresis_percent must be between 0 and 0.1') hysteresis = int(du.total * hysteresis_percent) if hysteresis < BS: hysteresis = BS - 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)}%') 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 ') + if not quiet: + 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'to_be_wasted: {round(to_be_wasted/ 2**30, 3)}GB ') if to_be_wasted < -hysteresis: to_be_trimmed = abs(to_be_wasted) baloon_size = os.path.getsize(os.path.join(fs, baloon_filename)) if 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') - else: print(f'can\'t trim {baloon_size} < {to_be_trimmed}Bytes') + if not quiet: print(f'trimmed {to_be_trimmed} Bytes') + elif not quiet: print(f'can\'t trim {baloon_size} < {to_be_trimmed}Bytes') elif to_be_wasted > hysteresis: with open(os.path.join(fs, baloon_filename) , 'ab') as f: last = 0 writed = to_be_wasted while to_be_wasted > 0: 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() write_size = min(to_be_wasted, BS) f.write(b'x' * 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)