update documentation
This commit is contained in:
parent
a1ea6e4609
commit
e924bf1db6
4 changed files with 52 additions and 28 deletions
25
README.md
25
README.md
|
|
@ -1,6 +1,7 @@
|
||||||
# eintopf-radar-sync
|
# mail-quota-warning
|
||||||
Small script to sync events of an radar.quad.net group to a specific Eintopf
|
|
||||||
instance.
|
Small script to check a configured list of IMAP accounts for mailbox quota and send
|
||||||
|
a warning mail in case a specific threashold is exceeded.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|
@ -11,7 +12,7 @@ Add the module to your `flake.nix`:
|
||||||
```nix
|
```nix
|
||||||
{
|
{
|
||||||
inputs = {
|
inputs = {
|
||||||
eintopf-radar-sync.url = "git+https://git.project-insanity.org/onny/eintopf-radar-sync.git";
|
mail-quota-warning.url = "git+https://git.project-insanity.org/onny/mail-quota-warning.git";
|
||||||
[...]
|
[...]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -21,12 +22,12 @@ Add the module to your `flake.nix`:
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
specialArgs.inputs = inputs;
|
specialArgs.inputs = inputs;
|
||||||
modules = [
|
modules = [
|
||||||
inputs.eintopf-radar-sync.nixosModule
|
inputs.mail-quota-warning.nixosModule
|
||||||
|
|
||||||
({ pkgs, ... }:{
|
({ pkgs, ... }:{
|
||||||
|
|
||||||
nixpkgs.overlays = [
|
nixpkgs.overlays = [
|
||||||
inputs.eintopf-radar-sync.overlay
|
inputs.mail-quota-warning.overlay
|
||||||
];
|
];
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
@ -42,30 +43,26 @@ Add the module to your `flake.nix`:
|
||||||
Add this to your `configuration.nix` file
|
Add this to your `configuration.nix` file
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
environment.etc."eintopf-radar-sync-secrets".text = ''
|
environment.etc."eintopf-radar-sync-secrets.yml".text = ''
|
||||||
EINTOPF_AUTHORIZATION_TOKEN=foobar23
|
EINTOPF_AUTHORIZATION_TOKEN=foobar23
|
||||||
'';
|
'';
|
||||||
|
|
||||||
services.eintopf-radar-sync = {
|
services.mail-quota-warning = {
|
||||||
enable = true;
|
enable = true;
|
||||||
settings = {
|
settings = {
|
||||||
EINTOPF_URL = "https://karlsunruh.eintopf.info";
|
EINTOPF_URL = "https://karlsunruh.eintopf.info";
|
||||||
RADAR_GROUP_ID = "436012";
|
RADAR_GROUP_ID = "436012";
|
||||||
};
|
};
|
||||||
secrets = [ /etc/eintopf-radar-sync-secrets ];
|
secrets = [ /etc/mail-quota-warning-secrets.yml ];
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Replace setting variables according to your setup.
|
Replace setting variables according to your setup.
|
||||||
|
|
||||||
Get the authorization token through login request in the Eintopf
|
|
||||||
Swagger api interface, for example
|
|
||||||
https://karlsunruh.project-insanity.org/api/v1/swagger#/auth/login
|
|
||||||
|
|
||||||
### From source
|
### From source
|
||||||
|
|
||||||
```
|
```
|
||||||
cd eintopf-radar-sync
|
cd mail-quota-warning
|
||||||
nix develop
|
nix develop
|
||||||
export EINTOPF_URL = "https://karlsunruh.eintopf.info"
|
export EINTOPF_URL = "https://karlsunruh.eintopf.info"
|
||||||
export EINTOPF_AUTHORIZATION_TOKEN = "secret key"
|
export EINTOPF_AUTHORIZATION_TOKEN = "secret key"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
check_interval_days: 7 # Minimum days between warnings for same account
|
check_interval_days: 7 # Minimum days between warnings for same account
|
||||||
quota_warning_threshold_percent: 80
|
quota_warning_threshold_percent: 80
|
||||||
|
working_dir: /var/lib/mail-quota-warning
|
||||||
|
|
||||||
accounts:
|
accounts:
|
||||||
- name: Sales
|
- name: Sales
|
||||||
|
|
|
||||||
|
|
@ -5,30 +5,55 @@ import yaml
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import threading
|
import threading
|
||||||
|
import argparse
|
||||||
from email.mime.text import MIMEText
|
from email.mime.text import MIMEText
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
CONFIG_FILE = "config.yml"
|
CONFIG_FILE = "config.yml"
|
||||||
STATE_FILE = "quota_state.json"
|
STATE_FILE = "quota_state.json"
|
||||||
|
|
||||||
# TODO:
|
# TODO
|
||||||
# - make working dir configurable for state file
|
# - load config from file
|
||||||
# - optional read config.yml from command line argument
|
# - override with env vars
|
||||||
# - note in warning mail that it exceeded XX% quota threashold
|
|
||||||
# - fix list summary mark all accounts which are critical
|
|
||||||
|
|
||||||
def load_config():
|
def get_config_value(config, env_var, config_key, default_value, value_type=int):
|
||||||
with open(CONFIG_FILE, "r") as f:
|
"""Get configuration value from environment variable or config file, with fallback to default"""
|
||||||
|
env_value = os.environ.get(env_var)
|
||||||
|
if env_value is not None:
|
||||||
|
try:
|
||||||
|
return value_type(env_value)
|
||||||
|
except ValueError:
|
||||||
|
log(f"Invalid value for {env_var}: {env_value}, using config/default")
|
||||||
|
|
||||||
|
return config.get(config_key, default_value)
|
||||||
|
|
||||||
|
def parse_args():
|
||||||
|
parser = argparse.ArgumentParser(description="Email quota monitoring script")
|
||||||
|
parser.add_argument(
|
||||||
|
"--config",
|
||||||
|
default="config.yml",
|
||||||
|
help="Path to config.yml file (default: config.yml in current directory)"
|
||||||
|
)
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
def load_config(config_file):
|
||||||
|
if not os.path.exists(config_file):
|
||||||
|
log(f"Config file not found: {config_file}")
|
||||||
|
raise FileNotFoundError(f"Config file not found: {config_file}")
|
||||||
|
|
||||||
|
with open(config_file, "r") as f:
|
||||||
return yaml.safe_load(f)
|
return yaml.safe_load(f)
|
||||||
|
|
||||||
def load_state():
|
def load_state():
|
||||||
if os.path.exists(STATE_FILE):
|
state_file = "quota_state.json"
|
||||||
with open(STATE_FILE, "r") as f:
|
if os.path.exists(state_file):
|
||||||
|
with open(state_file, "r") as f:
|
||||||
return json.load(f)
|
return json.load(f)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def save_state(state):
|
def save_state(state):
|
||||||
with open(STATE_FILE, "w") as f:
|
state_file = "quota_state.json"
|
||||||
|
with open(state_file, "w") as f:
|
||||||
json.dump(state, f, indent=2)
|
json.dump(state, f, indent=2)
|
||||||
|
|
||||||
def log(msg):
|
def log(msg):
|
||||||
|
|
@ -235,7 +260,8 @@ def check_account_quota(account, config, state, threshold, interval_days):
|
||||||
return None, quota_info
|
return None, quota_info
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
config = load_config()
|
args = parse_args()
|
||||||
|
config = load_config(args.config)
|
||||||
state = load_state()
|
state = load_state()
|
||||||
interval_days = config.get("check_interval_days", 7)
|
interval_days = config.get("check_interval_days", 7)
|
||||||
threshold = config.get("quota_warning_threshold_percent", 80)
|
threshold = config.get("quota_warning_threshold_percent", 80)
|
||||||
|
|
|
||||||
|
|
@ -21,14 +21,14 @@ in
|
||||||
type = lib.types.submodule {
|
type = lib.types.submodule {
|
||||||
freeformType = with lib.types; attrsOf types.str;
|
freeformType = with lib.types; attrsOf types.str;
|
||||||
options = {
|
options = {
|
||||||
EINTOPF_URL = lib.mkOption {
|
CHECK_INTERVAL_DAYS = lib.mkOption {
|
||||||
default = "";
|
default = "";
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
description = ''
|
description = ''
|
||||||
Base URL of the target Eintopf host.
|
Base URL of the target Eintopf host.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
RADAR_GROUP_ID = lib.mkOption {
|
QUOTA_WARNING_THRESHOLD_PERCENT = lib.mkOption {
|
||||||
default = "";
|
default = "";
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
description = ''
|
description = ''
|
||||||
|
|
@ -49,7 +49,7 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
secrets = lib.mkOption {
|
secretFile = lib.mkOption {
|
||||||
type = with lib.types; listOf path;
|
type = with lib.types; listOf path;
|
||||||
description = ''
|
description = ''
|
||||||
A list of files containing the various secrets. Should be in the
|
A list of files containing the various secrets. Should be in the
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue