194 lines
8.2 KiB
Text
194 lines
8.2 KiB
Text
|
|
# Reusable ServiceConcerns presets for component defaults.
|
||
|
|
#
|
||
|
|
# Component contracts.ncl files declare `concerns | _concerns_lib.ServiceConcerns | optional`
|
||
|
|
# and their defaults.ncl files set `concerns | default = presets.<preset>` to give
|
||
|
|
# the component an honest declarative surface without repeating boilerplate.
|
||
|
|
#
|
||
|
|
# Presets cover the recurring archetypes in libre-wuji:
|
||
|
|
# - stateless : no TLS/DNS/data — most container runtimes,
|
||
|
|
# kernel modules, OS-level taskservs
|
||
|
|
# - infra_storage_managed : storage backends that handle their own
|
||
|
|
# backup outside per-component policies
|
||
|
|
# (Longhorn engine state via SystemBackupDef)
|
||
|
|
# - tls_endpoint_with_acme : public service with cert-manager TLS
|
||
|
|
# and ACME issuer config; backup decided
|
||
|
|
# at workspace level
|
||
|
|
# - observability_telemetry : Prometheus/Grafana/Loki/Vector — config
|
||
|
|
# in git, data either transient or already
|
||
|
|
# shipped to S3
|
||
|
|
# - infrastructure_glue : controllers/operators with no user data
|
||
|
|
# (cilium, hccm, csi, ops-controller)
|
||
|
|
|
||
|
|
let _pending_obs = {
|
||
|
|
kind = 'pending,
|
||
|
|
reason = "ObservabilityImpl iteration deferred — surface stub only",
|
||
|
|
backlog_ref = "OBS-001",
|
||
|
|
} in
|
||
|
|
|
||
|
|
let _pending_sec = {
|
||
|
|
kind = 'pending,
|
||
|
|
reason = "SecurityImpl iteration deferred — surface stub only",
|
||
|
|
backlog_ref = "SEC-001",
|
||
|
|
} in
|
||
|
|
|
||
|
|
{
|
||
|
|
presets = {
|
||
|
|
# ── Stateless service ────────────────────────────────────────────────
|
||
|
|
# Container runtimes (containerd, runc, crun, youki), OS modules,
|
||
|
|
# kernel-level taskservs. No persistent state, no network endpoints
|
||
|
|
# exposed at the component level.
|
||
|
|
stateless = {
|
||
|
|
tls = { kind = 'disabled, reason = "no TLS termination at this layer" },
|
||
|
|
dns = { kind = 'disabled, reason = "no DNS records owned by this component" },
|
||
|
|
certs = { kind = 'disabled, reason = "no ACME issuer required" },
|
||
|
|
backup = {
|
||
|
|
kind = 'disabled,
|
||
|
|
reason = "stateless: configuration in git, no runtime data to capture",
|
||
|
|
},
|
||
|
|
observability = _pending_obs,
|
||
|
|
security = _pending_sec,
|
||
|
|
},
|
||
|
|
|
||
|
|
# ── Storage backend with its own backup model ────────────────────────
|
||
|
|
# Longhorn (engine state in SystemBackupDef.longhorn_engine), local-path
|
||
|
|
# provisioner, Hetzner CSI, democratic CSI. Their data is captured by
|
||
|
|
# the system-level backup, not per-component.
|
||
|
|
infra_storage_managed = {
|
||
|
|
tls = { kind = 'disabled, reason = "internal cluster storage, no TLS endpoint" },
|
||
|
|
dns = { kind = 'disabled, reason = "no DNS records owned by this component" },
|
||
|
|
certs = { kind = 'disabled, reason = "no ACME issuer required" },
|
||
|
|
backup = {
|
||
|
|
kind = 'disabled,
|
||
|
|
reason = "engine state captured by SystemBackupDef.longhorn_engine (or equivalent system target)",
|
||
|
|
},
|
||
|
|
observability = _pending_obs,
|
||
|
|
security = _pending_sec,
|
||
|
|
},
|
||
|
|
|
||
|
|
# ── Public service with cert-manager TLS + ACME ──────────────────────
|
||
|
|
# docker-mailserver, odoo, zot, anything that terminates HTTPS or SMTPS
|
||
|
|
# via cert-manager. Tls/Dns/Certs concerns get populated from existing
|
||
|
|
# tls_secret/cluster_issuer/cert/dns_records fields. Backup decided at
|
||
|
|
# workspace level (concerns.backup overridden in infra/<workspace>/components/<x>.ncl).
|
||
|
|
tls_endpoint_with_acme = fun args =>
|
||
|
|
{
|
||
|
|
tls = {
|
||
|
|
kind = 'enabled,
|
||
|
|
tls_impl = {
|
||
|
|
secret_name = args.tls_secret,
|
||
|
|
issuer_ref = args.cluster_issuer,
|
||
|
|
hostnames = args.hostnames,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
dns = {
|
||
|
|
kind = 'enabled,
|
||
|
|
dns_impl = {
|
||
|
|
internal = args.dns_internal,
|
||
|
|
zone = args.dns_zone,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
certs = {
|
||
|
|
kind = 'enabled,
|
||
|
|
certs_impl = {
|
||
|
|
acme_server = args.acme_server,
|
||
|
|
email = args.acme_email,
|
||
|
|
secret_ref = args.cert_secret_ref,
|
||
|
|
provider = args.cert_provider,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
backup = {
|
||
|
|
kind = 'pending,
|
||
|
|
reason = "BackupPolicy declared at workspace level",
|
||
|
|
backlog_ref = args.backup_backlog_ref,
|
||
|
|
},
|
||
|
|
observability = _pending_obs,
|
||
|
|
security = _pending_sec,
|
||
|
|
},
|
||
|
|
|
||
|
|
# ── Observability stack components (Prometheus/Grafana/Loki/Vector) ──
|
||
|
|
# No user data; configuration in git; metric/log data either transient
|
||
|
|
# (Prometheus WAL) or already shipped to S3 (Loki via boltdb-shipper).
|
||
|
|
observability_telemetry = {
|
||
|
|
tls = { kind = 'disabled, reason = "internal cluster service, ingress-level TLS handled separately" },
|
||
|
|
dns = { kind = 'disabled, reason = "no DNS records owned by this component" },
|
||
|
|
certs = { kind = 'disabled, reason = "no ACME issuer required" },
|
||
|
|
backup = {
|
||
|
|
kind = 'disabled,
|
||
|
|
reason = "config in git; runtime data either transient or shipped to S3 backend",
|
||
|
|
},
|
||
|
|
observability = {
|
||
|
|
kind = 'enabled,
|
||
|
|
observability_impl = {
|
||
|
|
metrics = { enabled = true, port = 9090, path = "/metrics" },
|
||
|
|
logs = { enabled = true, sink = 'loki },
|
||
|
|
traces = { enabled = false },
|
||
|
|
alerts = [],
|
||
|
|
},
|
||
|
|
},
|
||
|
|
security = _pending_sec,
|
||
|
|
},
|
||
|
|
|
||
|
|
# ── Infrastructure glue (controllers/operators) ──────────────────────
|
||
|
|
# cilium, hccm, hetzner-csi, ops-controller. State lives in K8s API,
|
||
|
|
# captured by SystemBackupDef.cluster_resources.
|
||
|
|
infrastructure_glue = {
|
||
|
|
tls = { kind = 'disabled, reason = "controller-level RBAC, not TLS endpoint" },
|
||
|
|
dns = { kind = 'disabled, reason = "no DNS records owned by this component" },
|
||
|
|
certs = { kind = 'disabled, reason = "no ACME issuer required" },
|
||
|
|
backup = {
|
||
|
|
kind = 'disabled,
|
||
|
|
reason = "state in K8s API captured by SystemBackupDef.cluster_resources",
|
||
|
|
},
|
||
|
|
observability = _pending_obs,
|
||
|
|
security = _pending_sec,
|
||
|
|
},
|
||
|
|
|
||
|
|
# ── DNS provider service (CoreDNS, external-dns) ─────────────────────
|
||
|
|
# Owns DNS records but typically not TLS endpoint of its own.
|
||
|
|
dns_provider = {
|
||
|
|
tls = { kind = 'disabled, reason = "DNS server, not TLS endpoint" },
|
||
|
|
dns = {
|
||
|
|
kind = 'enabled,
|
||
|
|
dns_impl = {
|
||
|
|
internal = [],
|
||
|
|
zone = "",
|
||
|
|
},
|
||
|
|
},
|
||
|
|
certs = { kind = 'disabled, reason = "no ACME issuer required" },
|
||
|
|
backup = {
|
||
|
|
kind = 'pending,
|
||
|
|
reason = "zone files captured by SystemBackupDef.external_dns",
|
||
|
|
backlog_ref = "BACKUP-DNS-001",
|
||
|
|
},
|
||
|
|
observability = _pending_obs,
|
||
|
|
security = _pending_sec,
|
||
|
|
},
|
||
|
|
|
||
|
|
# ── Database (PostgreSQL, MariaDB, SurrealDB) ─────────────────────────
|
||
|
|
# Backup with database scope + dump strategy. Decided at workspace level.
|
||
|
|
database = {
|
||
|
|
tls = { kind = 'disabled, reason = "internal cluster service, ingress-level TLS handled separately" },
|
||
|
|
dns = { kind = 'disabled, reason = "no public DNS records" },
|
||
|
|
certs = { kind = 'disabled, reason = "no ACME issuer required" },
|
||
|
|
backup = {
|
||
|
|
kind = 'pending,
|
||
|
|
reason = "BackupPolicy with database scope + dump_strategy declared at workspace level",
|
||
|
|
backlog_ref = "BACKUP-DB-001",
|
||
|
|
},
|
||
|
|
observability = _pending_obs,
|
||
|
|
security = _pending_sec,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
|
||
|
|
# ── Helper for components that need to compose a custom ServiceConcerns
|
||
|
|
# from individual variants (rather than picking a preset wholesale).
|
||
|
|
builders = {
|
||
|
|
pending = fun reason backlog => {
|
||
|
|
kind = 'pending,
|
||
|
|
reason = reason,
|
||
|
|
backlog_ref = backlog,
|
||
|
|
},
|
||
|
|
disabled = fun reason => { kind = 'disabled, reason = reason },
|
||
|
|
},
|
||
|
|
}
|