app/matrix: media repo proxy init

This implements media-repo-proxy, a lil' bit of Go to make our
infrastructure work with matrix-media-repo's concept of Host headers.

For some reason, MMR really wants Host: hackerspace.pl instead of Host:
matrix.hackerspace.pl. We'd fix that in their code, but with no tests
and with complex config reload logic it looks very daunting. We'd just
fix that in our Ingress, but that's not easy (no per-rule host
overrides).

So, we commit a tiny little itty bitty war crime and implement a piece
of Go code that serves as a rewriter for this.

This works, tested on boston:

    $ curl -H "Host: matrix.hackerspace.pl" 10.10.12.46:8080/_matrix/media/r0/download/hackerspace.pl/EwVBulPgCWDWNGMKjcOKGGbk | file -
    /dev/stdin: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 650x300, components 3

(this address is media-repo.matrix.svc.k0.hswaw.net)

But hey, at least it has tests.

Change-Id: Ib6af1988fe8e112c9f3a5577506b18b48d80af62
Reviewed-on: https://gerrit.hackerspace.pl/c/hscloud/+/1143
Reviewed-by: q3k <q3k@hackerspace.pl>
diff --git a/app/matrix/lib/media-repo.libsonnet b/app/matrix/lib/media-repo.libsonnet
index 338dc78..90af77b 100644
--- a/app/matrix/lib/media-repo.libsonnet
+++ b/app/matrix/lib/media-repo.libsonnet
@@ -91,7 +91,56 @@
         },
     },
 
-    svc: app.ns.Contain(kube.Service("media-repo")) {
+    // Run //app/matrix/media-repo-proxy, if needed. This rewrites Host headers
+    // from the homeserver's serving Host to the MXID hostname (which
+    // matrix-media-repo expects).
+    // 
+    // Currently we only are able to run one proxy for one homeserver config -
+    // but we don't expect to have multiple homeservers per matrix-media-repo
+    // any time soon.
+    local needProxying = [
+        h
+        for h in cfg.homeservers
+        if "https://%s" % [h.name] != h.csApi
+    ],
+    proxies: if std.length(needProxying) > 1 then error "can only proxy one homeserver" else
+             if std.length(needProxying) == 1 then {
+        local homeserver = needProxying[0],
+
+        local upstreamHost = homeserver.name,
+        local prefix = "https://",
+        local downstreamHost = std.substr(homeserver.csApi, std.length(prefix), std.length(homeserver.csApi)-std.length(prefix)),
+
+        deployment: app.ns.Contain(kube.Deployment("media-repo-proxy")) {
+            spec+: {
+                template+: {
+                    spec+: {
+                        containers_: {
+                            default: kube.Container("default") {
+                                image: "registry.k0.hswaw.net/q3k/media-repo-proxy:1631791816-18609443fffde38a055f504e80f95e44f49d2481",
+                                command: [
+                                    "/app/matrix/media-repo-proxy",
+                                    "-downstream_host", downstreamHost,
+                                    "-upstream_host", upstreamHost,
+                                    "-upstream", app.internalSvc.host_colon_port,
+                                    "-listen", ":8080",
+                                ],
+                                ports_: {
+                                    http: { containerPort: 8080 },
+                                },
+                            },
+                        },
+                    },
+                },
+            },
+        },
+    } else {},
+
+    internalSvc: app.ns.Contain(kube.Service("media-repo-internal")) {
         target_pod:: app.deployment.spec.template,
     },
+
+    svc: if std.length(needProxying) > 0 then app.ns.Contain(kube.Service("media-repo")) {
+        target_pod:: app.proxies.deployment.spec.template,
+    } else app.internalSvc,
 }