Show disk usage and quota on a cluster. Supports BeeGFS and Lustre.
$ dusage --help
Usage: dusage [OPTIONS]
Options:
  -u, --user TEXT       The username to check (default: *****).
  -p, --project TEXT    The allocation project.
  -d, --directory TEXT  The directory/path to check.
  --no-colors           Disable colors.
  --help                Show this message and exit.- Clone this repository.
- Change into the _dusage folder.
- Run the install.sh script while being inside the _dusage folder. This sets up a virtual environment for the script.
- Adjust dusage.cfg to your cluster.
- Change "undefined_hostname" in dusage to an actual cluster name. The cluster name needs to be listed in dusage.cfg.
- Run dusage.
The code is divided into a front-end and a back-end.
The front-end calls the back-end under the hood, puts the results into a nice table, and colorizes them. You can also call the back-end directly (see below) if you need the numbers but want to present or use them differently.
Design choices:
- All back-end code is contained within one file: dusage_backend.py
- Local configuration can be done outside the Python code. Example: dusage.cfg
- No external library dependencies. Only depends on the standard library.
- Interface functions return a dictionary instead of a dataclass (which we wanted to use initially) to work on old Python versions typically found on clusters (Python 3.7 is too new for some clusters).
- All functions that start with an underscore are internal.
The back-end provides 3 interface functions:
- quota_using_account
- quota_using_project
- quota_using_path
Let us consider an actual example. You need a configuration file where you can localize the settings. Every time you call an API function, you need to point it to the configuration file.
Here is the configuration file (dusage.cfg) that we use for our clusters at NRIS:
[DEFAULT]
file_system_prefix = /cluster/
home_prefix = /cluster/home/
scratch_prefix = /cluster/work/users/
project_path_prefixes = /cluster/projects/, /cluster/shared/
[saga]
file_system = beegfs
path_based = no
[fram]
file_system = lustre
path_based = no
[betzy]
file_system = lustre
path_based = yesNow let us call the 3 API functions. The pprint used in the example below is
only to make the returned dictionary more readable here:
from pprint import pprint
from dusage_backend import quota_using_project, quota_using_account, quota_using_path
result = quota_using_project(
    config_file="dusage.cfg", cluster="betzy", project="nn1234k"
)
pprint(result)
# example output:
# {'/cluster/projects/nn1234k': {'inodes_hard_limit': 1000000,
#                                'inodes_soft_limit': 1000000,
#                                'inodes_used': 1,
#                                'space_hard_limit_bytes': 1099511627776,
#                                'space_soft_limit_bytes': 1099511627776,
#                                'space_used_bytes': 4096}}
result = quota_using_account(config_file="dusage.cfg", cluster="betzy", account="somebody")
pprint(result)
# example output:
# {'/cluster/home/somebody': {'inodes_hard_limit': 110000,
#                             'inodes_soft_limit': 100000,
#                             'inodes_used': 1317,
#                             'space_hard_limit_bytes': 32212254720,
#                             'space_soft_limit_bytes': 21474836480,
#                             'space_used_bytes': 369164288},
#  '/cluster/projects/nn1234k': {'inodes_hard_limit': 1000000,
#                                'inodes_soft_limit': 1000000,
#                                'inodes_used': 1,
#                                'space_hard_limit_bytes': 1099511627776,
#                                'space_soft_limit_bytes': 1099511627776,
#                                'space_used_bytes': 4096}}
result = quota_using_path(
    config_file="dusage.cfg", cluster="betzy", path="/cluster/home/somebody"
)
pprint(result)
# example output:
# {'/cluster/home/somebody': {'inodes_hard_limit': 110000,
#                             'inodes_soft_limit': 100000,
#                             'inodes_used': 1317,
#                             'space_hard_limit_bytes': 32212254720,
#                             'space_soft_limit_bytes': 21474836480,
#                             'space_used_bytes': 369164288}}