matrix: add Telegram bridge appservice.
Configuring this one is a bit different from appservice-irc. Notably,
there's no way to give it a registration.yaml to overlay on top of a
config, se we end up using an init container with yq to do that for us.
Also, I had to manually copy the regsitration.yaml in synapse, from
/appservices/telegram-prod/registration.yaml to
/data/appservices/telegram-prod.jsonnet, in order to make it work with
the synapse docker start magic. :/
Otherwise, this is deployed and seems to be working.
Change-Id: Id747a0e310221855556c1d280439376f0c4e5ed6
diff --git a/app/matrix/appservice-telegram.libsonnet b/app/matrix/appservice-telegram.libsonnet
new file mode 100644
index 0000000..b174225
--- /dev/null
+++ b/app/matrix/appservice-telegram.libsonnet
@@ -0,0 +1,157 @@
+local kube = import "../../kube/kube.libsonnet";
+
+{
+ AppServiceTelegram(name):: {
+ local bridge = self,
+ local cfg = bridge.cfg,
+ cfg:: {
+ metadata: {},
+ 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-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: 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" },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+
+ 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" },
+ },
+ // Ow, the edge! We need yq.
+ // See: https://github.com/mikefarah/yq/issues/190#issuecomment-667519015
+ image: "alpine@sha256:156f59dc1cbe233827642e09ed06e259ef6fa1ca9b2e29d52ae14d5e7b79d7f0",
+ 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,
+ },
+ },
+}