From 5139a87797f4e98bff6bb71f96fa2710e86e60dc Mon Sep 17 00:00:00 2001 From: Pier-Luc St-Onge Date: Thu, 20 Aug 2026 16:38:27 -0400 Subject: [PATCH 1/6] Red background behind over quota --- bin/computecanada/diskusage_report.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bin/computecanada/diskusage_report.py b/bin/computecanada/diskusage_report.py index e45b0b4..f11577e 100755 --- a/bin/computecanada/diskusage_report.py +++ b/bin/computecanada/diskusage_report.py @@ -7,6 +7,7 @@ import sys from pathlib import Path from datetime import datetime +from colorama import Back, Style import pwd SUPPORTED_FS_TYPES = {'lustre', 'nfs', 'gpfs', 'nfs4'} @@ -238,7 +239,9 @@ def report_quotas(paths_info): description = f"{path_info['filesystem']} ({quota_type} {quota_info['identity_name']})" space = f"{sizeof_fmt(quota_info['space_used_bytes'], scale=space_display_scale)}/{sizeof_fmt(quota_info['space_quota_bytes'], scale=space_display_scale)}" files = f"{sizeof_fmt(quota_info['file_used'], suffix='', scale=1000)}/{sizeof_fmt(quota_info['file_quota'], suffix='', scale=1000)}" - print(f"{description:>39} {space:>20} {files:>18}") + style_space = Back.RED + Style.BRIGHT if quota_info['space_used_bytes'] >= quota_info['space_quota_bytes'] else '' + style_files = Back.RED + Style.BRIGHT if quota_info['file_used'] >= quota_info['file_quota'] else '' + print(f"{description:>39}", style_space + f"{space:>20}" + Style.RESET_ALL, style_files + f"{files:>18}" + Style.RESET_ALL) # display breakdowns per user if requested for path, path_info in paths_info.items(): From 8bfc96fd41b8d7c8168470e85ecdbe37edc29e40 Mon Sep 17 00:00:00 2001 From: Pier-Luc St-Onge Date: Fri, 21 Aug 2026 09:59:40 -0400 Subject: [PATCH 2/6] Using foreground color, threshold at 95% of quota --- bin/computecanada/diskusage_report.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/computecanada/diskusage_report.py b/bin/computecanada/diskusage_report.py index f11577e..d290b21 100755 --- a/bin/computecanada/diskusage_report.py +++ b/bin/computecanada/diskusage_report.py @@ -7,7 +7,7 @@ import sys from pathlib import Path from datetime import datetime -from colorama import Back, Style +from colorama import Fore, Style import pwd SUPPORTED_FS_TYPES = {'lustre', 'nfs', 'gpfs', 'nfs4'} @@ -239,8 +239,8 @@ def report_quotas(paths_info): description = f"{path_info['filesystem']} ({quota_type} {quota_info['identity_name']})" space = f"{sizeof_fmt(quota_info['space_used_bytes'], scale=space_display_scale)}/{sizeof_fmt(quota_info['space_quota_bytes'], scale=space_display_scale)}" files = f"{sizeof_fmt(quota_info['file_used'], suffix='', scale=1000)}/{sizeof_fmt(quota_info['file_quota'], suffix='', scale=1000)}" - style_space = Back.RED + Style.BRIGHT if quota_info['space_used_bytes'] >= quota_info['space_quota_bytes'] else '' - style_files = Back.RED + Style.BRIGHT if quota_info['file_used'] >= quota_info['file_quota'] else '' + style_space = Fore.RED + Style.BRIGHT if quota_info['space_used_bytes'] >= 0.95 * quota_info['space_quota_bytes'] else '' + style_files = Fore.RED + Style.BRIGHT if quota_info['file_used'] >= 0.95 * quota_info['file_quota'] else '' print(f"{description:>39}", style_space + f"{space:>20}" + Style.RESET_ALL, style_files + f"{files:>18}" + Style.RESET_ALL) # display breakdowns per user if requested From 990d427e0139841bb2f3dd90587b633cc7fde669 Mon Sep 17 00:00:00 2001 From: Pier-Luc St-Onge Date: Fri, 21 Aug 2026 11:21:03 -0400 Subject: [PATCH 3/6] Asterisks next to any usage over quota --- bin/computecanada/diskusage_report.py | 28 ++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/bin/computecanada/diskusage_report.py b/bin/computecanada/diskusage_report.py index d290b21..8dd3a26 100755 --- a/bin/computecanada/diskusage_report.py +++ b/bin/computecanada/diskusage_report.py @@ -29,6 +29,7 @@ ('links/nearlines', '*'), ], 'gpfs_diskusage_location': None, + 'warning_threshold': 0.95, } cfg = DEFAULT_CONFIG @@ -220,6 +221,7 @@ def sizeof_fmt(num, suffix="B", scale=1024, units=None): return f"{num:.0f}{units[-1]}{suffix}" def report_quotas(paths_info): + any_overquota = False header = ["Description", "Space", "# of files"] has_explorer = False print(f"{header[0]:>39} {header[1]:>20} {header[2]:>18}") @@ -237,11 +239,22 @@ def report_quotas(paths_info): continue quota_type = 'user' if path_info['filesystem'] in ('/home', '/scratch') else quota_info['quota_type'] description = f"{path_info['filesystem']} ({quota_type} {quota_info['identity_name']})" - space = f"{sizeof_fmt(quota_info['space_used_bytes'], scale=space_display_scale)}/{sizeof_fmt(quota_info['space_quota_bytes'], scale=space_display_scale)}" - files = f"{sizeof_fmt(quota_info['file_used'], suffix='', scale=1000)}/{sizeof_fmt(quota_info['file_quota'], suffix='', scale=1000)}" - style_space = Fore.RED + Style.BRIGHT if quota_info['space_used_bytes'] >= 0.95 * quota_info['space_quota_bytes'] else '' - style_files = Fore.RED + Style.BRIGHT if quota_info['file_used'] >= 0.95 * quota_info['file_quota'] else '' - print(f"{description:>39}", style_space + f"{space:>20}" + Style.RESET_ALL, style_files + f"{files:>18}" + Style.RESET_ALL) + space_usage, space_quota = quota_info['space_used_bytes'], quota_info['space_quota_bytes'] + files_usage, files_quota = quota_info['file_used'], quota_info['file_quota'] + space_isoverquota = space_usage / space_quota > cfg['warning_threshold'] + files_isoverquota = files_usage / files_quota > cfg['warning_threshold'] + space_style = Fore.RED + Style.BRIGHT if space_isoverquota else '' + files_style = Fore.RED + Style.BRIGHT if files_isoverquota else '' + space_marker = ' **' if space_isoverquota else '' + files_marker = ' **' if files_isoverquota else '' + space_ratio = f"{sizeof_fmt(space_usage, scale=space_display_scale)}/{sizeof_fmt(space_quota, scale=space_display_scale)}{space_marker}" + files_ratio = f"{sizeof_fmt(files_usage, suffix='', scale=1000)}/{sizeof_fmt(files_quota, suffix='', scale=1000)}{files_marker}" + print( + f"{description:>39}", + space_style + f"{space_ratio:>20}" + Style.RESET_ALL, + files_style + f"{files_ratio:>18}" + Style.RESET_ALL + ) + any_overquota |= space_isoverquota | files_isoverquota # display breakdowns per user if requested for path, path_info in paths_info.items(): @@ -256,6 +269,11 @@ def report_quotas(paths_info): subprocess.run(["diskusage_rbh", fs[1:], path_info['group']] + diskusage_rbh_arg) print("\n") + if any_overquota: + print( + f"\n** Usage near or over quota", + f"(warning threshold at {cfg['warning_threshold']*100:.0f}% of the quota)" + ) # report breakdown commands if has_explorer: From 8a2b0eef4f52f7241e133ce15d97201facc4fb94 Mon Sep 17 00:00:00 2001 From: Pier-Luc St-Onge Date: Fri, 21 Aug 2026 11:30:37 -0400 Subject: [PATCH 4/6] Added color/no-color flag, True by default --- bin/computecanada/diskusage_report.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/bin/computecanada/diskusage_report.py b/bin/computecanada/diskusage_report.py index 8dd3a26..a50c934 100755 --- a/bin/computecanada/diskusage_report.py +++ b/bin/computecanada/diskusage_report.py @@ -40,6 +40,7 @@ parser.add_argument("--nearline", default=False, action='store_true', help="Display information for the nearline filesystem") parser.add_argument("--per_user", default=False, action='store_true', help="Display per-user breakdown if available") parser.add_argument("--all_users", default=False, action='store_true', help="Display information for all users of the project") +parser.add_argument('--color', default=True, action=argparse.BooleanOptionalAction, help="Display any usage over quota in red") args = parser.parse_args() def get_network_filesystems(): @@ -220,7 +221,7 @@ def sizeof_fmt(num, suffix="B", scale=1024, units=None): num /= scale return f"{num:.0f}{units[-1]}{suffix}" -def report_quotas(paths_info): +def report_quotas(paths_info, with_color): any_overquota = False header = ["Description", "Space", "# of files"] has_explorer = False @@ -243,8 +244,8 @@ def report_quotas(paths_info): files_usage, files_quota = quota_info['file_used'], quota_info['file_quota'] space_isoverquota = space_usage / space_quota > cfg['warning_threshold'] files_isoverquota = files_usage / files_quota > cfg['warning_threshold'] - space_style = Fore.RED + Style.BRIGHT if space_isoverquota else '' - files_style = Fore.RED + Style.BRIGHT if files_isoverquota else '' + space_style = Fore.RED + Style.BRIGHT if with_color and space_isoverquota else '' + files_style = Fore.RED + Style.BRIGHT if with_color and files_isoverquota else '' space_marker = ' **' if space_isoverquota else '' files_marker = ' **' if files_isoverquota else '' space_ratio = f"{sizeof_fmt(space_usage, scale=space_display_scale)}/{sizeof_fmt(space_quota, scale=space_display_scale)}{space_marker}" @@ -334,7 +335,7 @@ def deep_update_dict(dict1, dict2): relevant_paths = get_relevant_paths() network_filesystems = get_network_filesystems() paths_info = get_paths_info(relevant_paths, network_filesystems) - report_quotas(paths_info) + report_quotas(paths_info, args.color) if not args.per_user and any([x in cfg['filesystems'].keys() for x in ['/project', '/nearline']]): print("--") From 8ba567e58ef017b72c489ae0de8861e93149ac52 Mon Sep 17 00:00:00 2001 From: Pier-Luc St-Onge Date: Fri, 21 Aug 2026 15:35:28 -0400 Subject: [PATCH 5/6] Addressing possible division by zero --- bin/computecanada/diskusage_report.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/computecanada/diskusage_report.py b/bin/computecanada/diskusage_report.py index a50c934..e8b0dff 100755 --- a/bin/computecanada/diskusage_report.py +++ b/bin/computecanada/diskusage_report.py @@ -242,8 +242,8 @@ def report_quotas(paths_info, with_color): description = f"{path_info['filesystem']} ({quota_type} {quota_info['identity_name']})" space_usage, space_quota = quota_info['space_used_bytes'], quota_info['space_quota_bytes'] files_usage, files_quota = quota_info['file_used'], quota_info['file_quota'] - space_isoverquota = space_usage / space_quota > cfg['warning_threshold'] - files_isoverquota = files_usage / files_quota > cfg['warning_threshold'] + space_isoverquota = space_usage / (space_quota + 1) > cfg['warning_threshold'] + files_isoverquota = files_usage / (files_quota + 1) > cfg['warning_threshold'] space_style = Fore.RED + Style.BRIGHT if with_color and space_isoverquota else '' files_style = Fore.RED + Style.BRIGHT if with_color and files_isoverquota else '' space_marker = ' **' if space_isoverquota else '' From ea1b522aed83309f09b94b6aea20b2996ed745c5 Mon Sep 17 00:00:00 2001 From: Pier-Luc St-Onge Date: Fri, 21 Aug 2026 15:52:34 -0400 Subject: [PATCH 6/6] New marker to the left side, colored note --- bin/computecanada/diskusage_report.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/bin/computecanada/diskusage_report.py b/bin/computecanada/diskusage_report.py index e8b0dff..f549ba7 100755 --- a/bin/computecanada/diskusage_report.py +++ b/bin/computecanada/diskusage_report.py @@ -246,10 +246,10 @@ def report_quotas(paths_info, with_color): files_isoverquota = files_usage / (files_quota + 1) > cfg['warning_threshold'] space_style = Fore.RED + Style.BRIGHT if with_color and space_isoverquota else '' files_style = Fore.RED + Style.BRIGHT if with_color and files_isoverquota else '' - space_marker = ' **' if space_isoverquota else '' - files_marker = ' **' if files_isoverquota else '' - space_ratio = f"{sizeof_fmt(space_usage, scale=space_display_scale)}/{sizeof_fmt(space_quota, scale=space_display_scale)}{space_marker}" - files_ratio = f"{sizeof_fmt(files_usage, suffix='', scale=1000)}/{sizeof_fmt(files_quota, suffix='', scale=1000)}{files_marker}" + space_marker = '-> ' if space_isoverquota else '' + files_marker = '-> ' if files_isoverquota else '' + space_ratio = f"{space_marker}{sizeof_fmt(space_usage, scale=space_display_scale)}/{sizeof_fmt(space_quota, scale=space_display_scale)}" + files_ratio = f"{files_marker}{sizeof_fmt(files_usage, suffix='', scale=1000)}/{sizeof_fmt(files_quota, suffix='', scale=1000)}" print( f"{description:>39}", space_style + f"{space_ratio:>20}" + Style.RESET_ALL, @@ -271,9 +271,10 @@ def report_quotas(paths_info, with_color): print("\n") if any_overquota: + note_style = Fore.RED + Style.BRIGHT if with_color else '' print( - f"\n** Usage near or over quota", - f"(warning threshold at {cfg['warning_threshold']*100:.0f}% of the quota)" + f"\n{note_style}-> Usage near or over quota", + f"(warning threshold at {cfg['warning_threshold']*100:.0f}% of the quota)" + Style.RESET_ALL ) # report breakdown commands