games/valheim: init

This creates a valheim game server, using a public image but slightly
nerfing it to be able to run it unprivileged.

We also deploy our first server. The password is Well Known To Those
Versed In Hackerspace Lore.

Change-Id: Ic24262a3b02d3c17d2f00aa2967e240ea4eee7fb
diff --git a/games/valheim/README.md b/games/valheim/README.md
new file mode 100644
index 0000000..cf02ce5
--- /dev/null
+++ b/games/valheim/README.md
@@ -0,0 +1,10 @@
+Valheim
+=======
+
+This is our (tiny) Valheim game server infrastructure. We run it on prod on k0, using an existing Docker image.
+
+Updating
+--------
+
+    kubecfg update prod.jsonnet
+
diff --git a/games/valheim/prod.jsonnet b/games/valheim/prod.jsonnet
new file mode 100644
index 0000000..6c10b8b
--- /dev/null
+++ b/games/valheim/prod.jsonnet
@@ -0,0 +1,168 @@
+local kube = import "../../kube/kube.libsonnet";
+
+{
+    local top = self,
+    env(ns, name):: {
+        local env = self,
+        local cfg = env.cfg,
+        cfg:: {
+            name: name,
+            displayName: name,
+            image: "mbround18/valheim:latest",
+            password: error "password must be set",
+            storageClassName: "waw-hdd-redundant-3",
+            port: 2456,
+        },
+
+        local named = function(component) "%s-%s" % [name, component],
+
+        game: {
+            local game = self,
+            pvcs: {
+                backups: ns.Contain(kube.PersistentVolumeClaim(named("backups"))) {
+                    spec+: {
+                        storageClassName: cfg.storageClassName,
+                        accessModes: ["ReadWriteOnce"],
+                        resources: {
+                            requests: { storage: "10Gi" },
+                        },
+                    },
+                },
+                saves: ns.Contain(kube.PersistentVolumeClaim(named("saves"))) {
+                    spec+: {
+                        storageClassName: cfg.storageClassName,
+                        accessModes: ["ReadWriteOnce"],
+                        resources: {
+                            requests: { storage: "10Gi" },
+                        },
+                    },
+                },
+                server: ns.Contain(kube.PersistentVolumeClaim(named("server"))) {
+                    spec+: {
+                        storageClassName: cfg.storageClassName,
+                        accessModes: ["ReadWriteOnce"],
+                        resources: {
+                            requests: { storage: "10Gi" },
+                        },
+                    },
+                },
+            },
+            svc: ns.Contain(kube.Service(named("external"))) {
+                target_pod:: game.deployment.spec.template,
+                spec+: {
+                    ports: kube.mapToNamedList({
+                        zero: { port: cfg.port, targetPort: cfg.port, protocol: "UDP" },
+                        one: { port: cfg.port+1, targetPort: cfg.port+1, protocol: "UDP" },
+                        two: { port: cfg.port+2, targetPort: cfg.port+2, protocol: "UDP" },
+                    }),
+                    type: "LoadBalancer",
+                },
+            },
+
+            scripts: ns.Contain(kube.ConfigMap(named("scripts"))) {
+                data: {
+                    # Based on https://github.com/mbround18/valheim-docker ,
+                    # removed all reliance on running as root (thus removed
+                    # autoupdater/autobackups).
+                    "entrypoint.sh": |||
+                        #!/usr/bin/env bash
+                        log() {
+                            PREFIX="[entrypoint]"
+                            printf "%-16s: %s\n" "${PREFIX}" "$1"
+                        }
+                        line() {
+                            log "==========================================================================="
+                        }
+                        setup_filesystem() {
+                            log "Setting up file systems"
+                            mkdir -p /home/steam/valheim
+                            mkdir -p /home/steam/valheim/logs
+                            mkdir -p /home/steam/backups
+                            mkdir -p /home/steam/scripts
+                            mkdir -p /home/steam/valheim
+                            cp /home/steam/steamcmd/linux64/steamclient.so /home/steam/valheim
+                        }
+                        line
+                        log "Valheim Server - $(date)"
+                        log "Initializing your container..."
+                        line
+                        setup_filesystem
+                        log "Launching the rest of the fucking owl"
+                        cd /home/steam/valheim || exit 1
+                        exec "$@"
+                    |||
+                },
+            },
+            secret: ns.Contain(kube.Secret(named("game"))) {
+                data_: {
+                    # public game password
+                    public: cfg.password,
+                },
+            },
+            deployment: ns.Contain(kube.Deployment(named("game"))) {
+                spec+: {
+                    template+: {
+                        spec+: {
+                            containers_: {
+                                default: kube.Container("default") {
+                                    image: cfg.image,
+                                    command: [
+                                        "/bin/bash", "/scripts/entrypoint.sh", "/home/steam/scripts/start_valheim.sh",
+                                    ],
+                                    volumeMounts_: {
+                                        backups: { mountPath: "/home/steam/backups" },
+                                        saves: { mountPath: "/home/steam/.config/unity3d/IronGate/Valheim" },
+                                        server: { mountPath: "/home/steam/valheim" },
+                                        scripts: { mountPath: "/scripts" },
+                                    },
+                                    ports_: {
+                                        zero: { containerPort: cfg.port },
+                                        one: { containerPort: cfg.port + 1 },
+                                        two: { containerPort: cfg.port + 2 },
+                                    },
+                                    env_: {
+                                        PUBLIC: "1",
+                                        PASSWORD: kube.SecretKeyRef(game.secret, "public"),
+                                        NAME: cfg.displayName,
+                                    },
+                                    resources: {
+                                        requests: {
+                                            cpu: "500m",
+                                            memory: "2Gi",
+                                        },
+                                        limits: {
+                                            cpu: "1000m",
+                                            memory: "4Gi",
+                                        },
+                                    },
+                                },
+                            },
+                            securityContext: {
+                                runAsUser: 1000,
+                                runAsGroup: 1000,
+                                fsGroup: 1000,
+                            },
+                            volumes_: {
+                                backups: kube.PersistentVolumeClaimVolume(game.pvcs.backups),
+                                saves: kube.PersistentVolumeClaimVolume(game.pvcs.saves),
+                                server: kube.PersistentVolumeClaimVolume(game.pvcs.server),
+                                scripts: kube.ConfigMapVolume(game.scripts),
+                            },
+                        },
+                    },
+                },
+            },
+        },
+    },
+
+    ns: kube.Namespace("valheim") {
+    },
+
+    q3k: top.env(top.ns, "q3k") {
+        cfg+: {
+            ns: "valheim",
+            password: (std.split(importstr "secrets/plain/q3k-public", "\n"))[0],
+            displayName: "wypierdol z polski xD",
+        },
+    },
+}
diff --git a/games/valheim/secrets/cipher/q3k-public b/games/valheim/secrets/cipher/q3k-public
new file mode 100644
index 0000000..b95f2a8
--- /dev/null
+++ b/games/valheim/secrets/cipher/q3k-public
@@ -0,0 +1,39 @@
+-----BEGIN PGP MESSAGE-----
+
+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
+=YmoD
+-----END PGP MESSAGE-----
diff --git a/games/valheim/secrets/plain/.gitignore b/games/valheim/secrets/plain/.gitignore
new file mode 100644
index 0000000..72e8ffc
--- /dev/null
+++ b/games/valheim/secrets/plain/.gitignore
@@ -0,0 +1 @@
+*