From 1a4d8ef4718355db6d4d486e613e5c392bfe04f6 Mon Sep 17 00:00:00 2001 From: "Peter J. Holzer" Date: Sat, 20 Aug 2022 17:40:16 +0200 Subject: [PATCH] Use a lossy timeseries to predict when a filesystem will be full (PoC) --- predict_disk_full | 64 ++++++++++++++++++++++++++++++++++++ predict_disk_full_home_bytes | 4 +++ predict_disk_full_var_bytes | 4 +++ 3 files changed, 72 insertions(+) create mode 100755 predict_disk_full create mode 100755 predict_disk_full_home_bytes create mode 100755 predict_disk_full_var_bytes diff --git a/predict_disk_full b/predict_disk_full new file mode 100755 index 0000000..d394f0b --- /dev/null +++ b/predict_disk_full @@ -0,0 +1,64 @@ +#!/usr/bin/python3 + +# PoC + +# add a new entry and remove a random old entry with a probability +# depending on the target size + +import argparse +import datetime +import json +import random +import sys +import time +import os + +ap = argparse.ArgumentParser() + +ap.add_argument("--targetsize", type=int, default=1000) +ap.add_argument("filesystem") + +args = ap.parse_args() + +st = os.statvfs(args.filesystem) + +blocks_reserved = st.f_bfree - st.f_bavail +blocks_usable = st.f_blocks - blocks_reserved +blocks_used = st.f_blocks - st.f_bfree + +# Just for readability +bytes_usable = blocks_usable * st.f_bsize +bytes_used = blocks_used * st.f_bsize + + +filename = args.filesystem.replace("/", "_") + ".bytes.json" + +ts = [] +try: + with open(filename) as f: + ts = json.load(f) +except FileNotFoundError as e: + pass # Ok, will create + +now = time.time() +ts.append((now, bytes_used, bytes_usable)) +if random.random() > 1 - len(ts) / args.targetsize: + i = random.randrange(0, len(ts)) + ts.pop(i) + +with open(filename, "w") as f: + json.dump(ts, f) + +for d in reversed(ts): + bytes_predicted = bytes_used * bytes_used / d[1] + print("Predicted use", bytes_predicted, + "in", now - d[0], "seconds", + "at", datetime.datetime.fromtimestamp(now + now - d[0])) + if bytes_predicted > bytes_usable: + print("Predicted disk full", + "in", now - d[0], "seconds", + "at", datetime.datetime.fromtimestamp(now + now - d[0])) + sys.exit(1) +else: + print("safe for", now - ts[0][0], "seconds", + "at", datetime.datetime.fromtimestamp(now + now - ts[0][0])) diff --git a/predict_disk_full_home_bytes b/predict_disk_full_home_bytes new file mode 100755 index 0000000..960f9f0 --- /dev/null +++ b/predict_disk_full_home_bytes @@ -0,0 +1,4 @@ +#!/bin/sh +set -e +cd $(dirname $0) +./predict_disk_full /home diff --git a/predict_disk_full_var_bytes b/predict_disk_full_var_bytes new file mode 100755 index 0000000..69e2e46 --- /dev/null +++ b/predict_disk_full_var_bytes @@ -0,0 +1,4 @@ +#!/bin/sh +set -e +cd $(dirname $0) +./predict_disk_full /var