feat: implement getmail runner script and update email fetching configuration

This commit is contained in:
2025-10-06 23:36:50 +02:00
parent 7f9a64b0ed
commit 84c8288f8a
5 changed files with 157 additions and 58 deletions
-2
View File
@@ -48,8 +48,6 @@ module "mail" {
relay_smtp_username = var.scaleway_project_id relay_smtp_username = var.scaleway_project_id
relay_smtp_password = local.mail_app_api_secret_key relay_smtp_password = local.mail_app_api_secret_key
fetch_emails_schedule = local.fetch_emails_schedule
mail_crypt_private_key = var.mail_crypt_private_key mail_crypt_private_key = var.mail_crypt_private_key
mail_crypt_public_key = var.mail_crypt_public_key mail_crypt_public_key = var.mail_crypt_public_key
+4
View File
@@ -101,6 +101,10 @@ locals {
secret_name = "mail-tls" secret_name = "mail-tls"
} }
} }
getmail_runner_script = file("${path.module}/resources/getmail/runner.py")
checksum_getmail_runner_script = sha256(local.getmail_runner_script)
getmail_fetch_interval_seconds = coalesce(var.getmail_fetch_interval_seconds, 120)
} }
data "external" "password_hasher" { data "external" "password_hasher" {
+105 -53
View File
@@ -8,80 +8,132 @@ resource "kubernetes_secret" "getmail_config" {
type = "Opaque" type = "Opaque"
} }
resource "kubernetes_cron_job_v1" "fetch_emails" { resource "kubernetes_config_map_v1" "getmail_runner" {
metadata {
name = "getmail-runner"
namespace = kubernetes_namespace.mail.metadata[0].name
}
data = {
"runner.py" = local.getmail_runner_script
}
}
resource "kubernetes_deployment_v1" "fetch_emails" {
metadata { metadata {
namespace = kubernetes_namespace.mail.metadata[0].name namespace = kubernetes_namespace.mail.metadata[0].name
name = "fetch-emails" name = "fetch-emails"
labels = {
app = "fetch-emails"
}
} }
spec { spec {
schedule = var.fetch_emails_schedule replicas = 1
selector {
job_template { match_labels = {
app = "fetch-emails"
}
}
template {
metadata { metadata {
name = "fetch-emails" labels = {
app = "fetch-emails"
}
annotations = {
"checksum/runner-script" = local.checksum_getmail_runner_script
}
} }
spec { spec {
backoff_limit = 1 container {
parallelism = 1 name = "getmail"
completions = 1 image = "a13labs/getmail6:${var.getmail_tag}"
active_deadline_seconds = 300 command = ["python3", "/runner/runner.py"]
env {
template { name = "FETCH_INTERVAL_SECONDS"
metadata { value = local.getmail_fetch_interval_seconds
labels = {
app = "fetch-emails"
}
} }
spec { volume_mount {
container { name = "getmail-config"
name = "getmail" mount_path = "/getmail"
image = "a13labs/getmail6:${var.getmail_tag}" read_only = true
args = concat(["--getmaildir", "/var/getmail"], flatten([for job in local.getmail_jobs : ["-r", "/getmail/getmailrc_${job.name}"]])) }
volume_mount {
name = "getmail-cache"
mount_path = "/var/getmail"
}
volume_mount {
name = "runner-script"
mount_path = "/runner"
read_only = true
}
volume_mount {
name = "tmp"
mount_path = "/tmp"
}
volume_mount { security_context {
name = "getmail-config" run_as_user = 1000
mount_path = "/getmail" run_as_group = 1000
read_only = true read_only_root_filesystem = true
} }
security_context { # Basic liveness (process must still be running)
run_as_user = 1000 liveness_probe {
run_as_group = 1000 exec {
} command = ["bash", "-c", "pgrep -f runner.py > /dev/null"]
volume_mount {
name = "getmail-cache"
mount_path = "/var/getmail"
}
} }
initial_delay_seconds = 30
period_seconds = 30
}
restart_policy = "Never" resources {
requests = {
volume { cpu = "20m"
name = "getmail-config" memory = "64Mi"
secret {
secret_name = kubernetes_secret.getmail_config.metadata[0].name
dynamic "items" {
for_each = local.getmail_jobs
content {
key = "getmailrc_${items.value.name}"
path = "getmailrc_${items.value.name}"
}
}
}
} }
limits = {
cpu = "200m"
memory = "256Mi"
}
}
}
volume { volume {
name = "getmail-cache" name = "getmail-config"
host_path { secret {
path = local.getmail_path secret_name = kubernetes_secret.getmail_config.metadata[0].name
dynamic "items" {
for_each = local.getmail_jobs
content {
key = "getmailrc_${items.value.name}"
path = "getmailrc_${items.value.name}"
} }
} }
} }
} }
volume {
name = "getmail-cache"
host_path {
path = local.getmail_path
}
}
volume {
name = "runner-script"
config_map {
name = kubernetes_config_map_v1.getmail_runner.metadata[0].name
items {
key = "runner.py"
path = "runner.py"
}
}
}
volume {
name = "tmp"
empty_dir {}
}
} }
} }
} }
@@ -0,0 +1,44 @@
import os, signal, subprocess, time, sys
import logging
INTERVAL = int(os.getenv("FETCH_INTERVAL_SECONDS", "120"))
GETMAILDIR = "/var/getmail"
CONFIG_DIR = "/getmail"
JOBS = [f for f in os.listdir(CONFIG_DIR) if f.startswith("getmailrc_")]
logging.basicConfig(
level=logging.INFO,
format="[%(asctime)s] %(levelname)s %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
stop = False
def handle(sig, frame):
global stop
logging.info(f"Received signal {sig}, stopping runner...")
stop = True
for s in (signal.SIGINT, signal.SIGTERM):
signal.signal(s, handle)
def run_once():
args = ["getmail", "--getmaildir", GETMAILDIR]
for job in JOBS:
args += ["-r", f"{CONFIG_DIR}/{job}"]
logging.info(f"Running getmail with jobs: {JOBS}")
try:
rc = subprocess.call(args, stdout=sys.stdout, stderr=sys.stderr)
logging.info(f"getmail exited with code {rc}")
return rc
except Exception as e:
logging.error(f"Error running getmail: {e}")
return 1
logging.info("Starting getmail runner...")
while not stop:
rc = run_once()
for _ in range(INTERVAL):
if stop: break
time.sleep(1)
logging.info("Exiting getmail runner.")
sys.exit(0)
+4 -3
View File
@@ -46,9 +46,10 @@ variable "relay_smtp_password" {
sensitive = true sensitive = true
} }
variable "fetch_emails_schedule" { variable "getmail_fetch_interval_seconds" {
description = "The cron schedule for fetching emails" description = "The interval for fetching emails (in seconds)"
type = string type = number
default = 120
} }
variable "getmail_tag" { variable "getmail_tag" {