local kube = import "../../../kube/kube.libsonnet"; { AppServiceTelegram(name):: { local bridge = self, local cfg = bridge.cfg, cfg:: { metadata: {}, // Whether the bootstrap job should be created/updated. Kubernetes // doesn't like changing the configuration of jobs, so once this // appservice has been set up, this flag should be flipped to // false. bootstrapJob: true, image: error "image must be set", storageClassName: error "storageClassName must be set", // Data that will be serialized into the appservice's config.yaml. // This is taken straight from a YAML that was generated by // dock.mau.dev/tulir/mautrix-telegram:v0.8.2. We override here // fields that we know are strictly necessary to be configured when // instantiating this template. config: (std.native("parseYaml")(importstr "appservice/appservice-telegram.yaml")[0]) + { homeserver+: { address: error "homeserver.address must be set", domain: error "homeserver.domain must be set", }, appservice+: { address: bridge.svc.http_url, // We disable this. I have no idea what it does, but it // wants a secret. ~q3k provisioning+: { enabled: false, shared_secret: if self.enabled then error "appservice.provisioning.shared_secret must be set" else "hackme", }, id: error "appservice.id must be set", as_token: "This value is generated when generating the registration", hs_token: "This value is generated when generating the registration", }, telegram+: { api_id: error "telegram.api_id must be set", api_hash: error "telegram.api_hash must be set", bot_token: error "telegram.bot_token must be set", }, bridge+: { permissions: { '*': "relaybot", }, }, }, }, config: kube.Secret("appservice-telegram-%s" % [name]) { metadata+: cfg.metadata, data: { "config.yaml": std.base64(std.manifestYamlDoc(cfg.config)), }, }, dataVolume: kube.PersistentVolumeClaim("appservice-telegram-%s" % [name]) { metadata+: cfg.metadata, spec+: { storageClassName: cfg.storageClassName, accessModes: [ "ReadWriteOnce" ], resources: { requests: { storage: "10Gi", }, }, }, }, bootstrapJob: if cfg.bootstrapJob then (kube.Job("appservice-telegram-%s-bootstrap" % [name]) { metadata+: cfg.metadata { labels: { "job-name": "appservice-telegram-%s-bootstrap" % [name], }, }, spec+: { template+: { spec+: { volumes_: { config: kube.SecretVolume(bridge.config), }, containers_: { bootstrap: kube.Container("appservice-telegram-%s-bootstrap" % [name]) { image: cfg.image, command: [ "sh", "-c", "python3 -m mautrix_telegram -g -c /config/config.yaml -r /tmp/registration.yaml && echo SNIPSNIP && cat /tmp/registration.yaml", ], volumeMounts_: { config: { mountPath: "/config" }, }, }, }, }, }, }, }) else {}, deployment: kube.Deployment("appservice-telegram-%s" % [name]) { metadata+: cfg.metadata, spec+: { replicas: 1, template+: { spec+: { volumes_: { config: kube.SecretVolume(bridge.config), data: kube.PersistentVolumeClaimVolume(bridge.dataVolume), registration: { secret: { secretName: "appservice-telegram-%s-registration" % [name] } }, }, initContainers: [ // This container takes the stateless config from the Secret, and // updates it with the registration secrets from the registration token. kube.Container("generate-config") { volumeMounts_: { config: { mountPath: "/config", }, registration: { mountPath: "/registration", }, data: { mountPath: "/data" }, }, image: "alpine:3.13", command: [ "sh", "-c", ||| set -e -x apk add --no-cache yq cp /config/config.yaml /data/config.yaml yq w -i /data/config.yaml appservice.as_token $(yq r /registration/registration.yaml as_token) yq w -i /data/config.yaml appservice.hs_token $(yq r /registration/registration.yaml hs_token) ||| ], }, ], containers_: { appserviceIrc: kube.Container("appservice-telegram-%s" % [name]) { image: cfg.image, command: [ "sh", "-c", ||| alembic -x config=/data/config.yaml upgrade head python3 -m mautrix_telegram -n -c /data/config.yaml ||| ], ports_: { http: { containerPort: 29317 }, }, volumeMounts_: { data: { mountPath: "/data" }, }, }, }, }, }, }, }, svc: kube.Service("appservice-telegram-%s" % [name]) { metadata+: cfg.metadata, target_pod:: bridge.deployment.spec.template, }, }, }