hswaw/kube: add pretalx

Change-Id: Ia7512aa988022c3c7fd89f81927fbad03f933cf1
diff --git a/hswaw/kube/hswaw.jsonnet b/hswaw/kube/hswaw.jsonnet
index ca3890f..806a018 100644
--- a/hswaw/kube/hswaw.jsonnet
+++ b/hswaw/kube/hswaw.jsonnet
@@ -5,6 +5,7 @@
 local ldapweb = import "ldapweb.libsonnet";
 local teleimg = import "teleimg.libsonnet";
 local frab = import "frab.libsonnet";
+local pretalx = import "pretalx.libsonnet";
 
 {
     hswaw(name):: mirko.Environment(name) {
@@ -16,6 +17,7 @@
             ldapweb: ldapweb.cfg,
             teleimg: teleimg.cfg,
             frab: frab.cfg,
+            pretalx: pretalx.cfg,
         },
 
         components: {
@@ -24,6 +26,7 @@
             teleimg: teleimg.teleimg(cfg.teleimg, env),
             lelegram: teleimg.lelegram(cfg.teleimg, env),
             frab: frab.component(cfg.frab, env),
+            pretalx: pretalx.component(cfg.pretalx, env),
         },
     },
 
@@ -52,6 +55,14 @@
                     smtpPassword: std.base64(std.split(importstr "secrets/plain/prod-frab-secret-key-base", "\n")[0]),
                 },
             },
+            pretalx+: {
+                storageClassName: "waw-hdd-redundant-3",
+                webFQDN: "cfp.cebula.camp",
+                smtpPassword: std.base64(std.split(importstr "secrets/plain/prod-pretalx-smtp-password", "\n")[0]),
+                s3+: {
+                    credsSecret: import "secrets/plain/prod-pretalx-s3.json",
+                },
+            },
         },
     },
 }
diff --git a/hswaw/kube/pretalx.libsonnet b/hswaw/kube/pretalx.libsonnet
new file mode 100644
index 0000000..2388529
--- /dev/null
+++ b/hswaw/kube/pretalx.libsonnet
@@ -0,0 +1,255 @@
+local mirko = import "../../kube/mirko.libsonnet";
+local kube = import "../../kube/kube.libsonnet";
+local postgres = import "../../kube/postgres.libsonnet";
+local redis = import "../../kube/redis.libsonnet";
+
+// Copy over the secret from the ceph cluster namespace to the environment
+// namespace. Eg.
+//   cluster=ceph-waw3
+//   pool=waw-hdd-redundant-3-object
+//   namespace=hswaw-prod
+//   kubectl get -n $cluster secret rook-ceph-object-user-$pool-$namespace-pretalx-s3 -o json > hswaw/kube/secrets/plain/prod-pretalx-s3.json
+
+{
+    local cfg = self.cfg,
+    cfg:: {
+        // q3k's fork for S3 support (q3k/s3)
+        image: "registry.k0.hswaw.net/q3k/pretalx-docker:20200217-1581977177",
+        storageClassName: error "storageClassName must be set!",
+        webFQDN: error "webFQDN must be set!",
+
+        smtpPassword: error "smtpPassword must be set!",
+
+        s3: {
+            cluster: "ceph-waw3",
+            pool: "waw-hdd-redundant-3-object",
+            credsSecret: error "credsSecret msut be set",
+        },
+
+        smtp: {
+            server: "mail.hackerspace.pl",
+            from: "pretalx@hackerspace.pl",
+            username: "pretalx",
+        },
+    },
+
+    component(cfg, env): mirko.Component(env, "pretalx") {
+        local pretalx = self,
+        cfg+: {
+            image: cfg.image,
+            volumes+: {
+                data: kube.PersistentVolumeClaimVolume(pretalx.volumeData),
+                config: kube.SecretVolume(pretalx.config),
+            },
+
+            pgpass:: { secretKeyRef: { name: pretalx.makeName("-postgres"), key: "postgres_password", } },
+
+            containers:: {
+                default: pretalx.Container("main") {
+                    volumeMounts_+: {
+                        data: { mountPath: "/data", },
+                        config: { mountPath: "/etc/pretalx" },
+                    },
+                    workingDir: "/pretalx/src",
+                    command: [
+                        "gunicorn", "pretalx.wsgi",
+                        "--name", "pretalx",
+                        "--workers", "4",
+                        "--max-requests", "1200",
+                        "--max-requests-jitter", "50",
+                        "--log-level", "info",
+                        "--bind", "0.0.0.0:8080",
+                    ],
+                    env_: {
+                        PRETALX_DB_PASS: pretalx.cfg.pgpass,
+                        HOME: "/pretalx",
+                        PRETALX_DATA_DIR: "/data",
+                    },
+                    resources: {
+                        // thicc Python
+                        requests: {
+                            cpu: "100m",
+                            memory: "512Mi",
+                        },
+                        limits: {
+                            cpu: "1",
+                            memory: "2Gi",
+                        },
+                    },
+                },
+                worker: pretalx.Container("worker") {
+                    volumeMounts_+: {
+                        data: { mountPath: "/data", },
+                        config: { mountPath: "/etc/pretalx" },
+                    },
+                    workingDir: "/pretalx/src",
+                    command: [
+                        "celery", "-A", "pretalx.celery_app", "worker",
+                        "-l", "info",
+                    ],
+                    env_: {
+                        PRETALX_DB_PASS: pretalx.cfg.pgpass,
+                        HOME: "/pretalx",
+                        PRETALX_DATA_DIR: "/data",
+                    },
+                    resources: {
+                        // thicc Python
+                        requests: {
+                            cpu: "100m",
+                            memory: "512Mi",
+                        },
+                        limits: {
+                            cpu: "1",
+                            memory: "2Gi",
+                        },
+                    },
+                },
+            },
+            securityContext: {
+                runAsUser: 999,
+            },
+            ports+: {
+                publicHTTP: {
+                    web: {
+                        port: 8080,
+                        dns: cfg.webFQDN,
+                    },
+                },
+            },
+        },
+
+        secret: kube.Secret(pretalx.makeName("secret")) {
+            metadata+: pretalx.metadata,
+            data: {
+                smtpPassword: cfg.smtpPassword,
+            },
+        },
+
+        cronjob: kube.CronJob(pretalx.makeName("runperiodic")) {
+            metadata+: pretalx.metadata,
+            spec+: {
+                schedule: "*/5 * * * *",
+                jobTemplate+: {
+                    spec+: {
+                        selector:: null,
+                        template+: {
+                            spec+: {
+                                containers_: {
+                                    runperiodic: kube.Container("runperiodic") {
+                                        image: cfg.image,
+                                        workingDir: "/pretalx/src",
+                                        volumeMounts_+: {
+                                            config: { mountPath: "/etc/pretalx" },
+                                        },
+                                        env_: {
+                                            PRETALX_DB_PASS: pretalx.cfg.pgpass,
+                                            HOME: "/pretalx",
+                                            PRETALX_DATA_DIR: "/data",
+                                        },
+                                        command: [
+                                            "python3", "-m", "pretalx",
+                                            "runperiodic",
+                                        ],
+                                    },
+                                },
+                                securityContext: {
+                                    runAsUser: 999,
+                                },
+                                volumes_+: {
+                                    config: kube.SecretVolume(pretalx.config),
+                                },
+                            },
+                        },
+                    },
+                },
+            },
+        },
+
+        config: kube.Secret(pretalx.makeName("-config")) {
+            metadata+: pretalx.metadata,
+            data: {
+                "pretalx.cfg": std.base64(std.manifestIni({
+                    sections: {
+                        filesystem: {
+                            data: "/data", media: "/data/media", logs: "/data/logs",
+                        },
+                        site: {
+                            debug: false,
+                            url: "https://%s" % cfg.webFQDN,
+                        },
+                        s3media: {
+                            bucket: "pretalx-prod",
+                            access_key_id: std.base64Decode(cfg.s3.credsSecret.data.AccessKey),
+                            secret_access_key: std.base64Decode(cfg.s3.credsSecret.data.SecretKey),
+                            endpoint: "https://object.ceph-waw3.hswaw.net",
+                        },
+                        database: {
+                            backend: "postgresql",
+                            name: "pretalx",
+                            user: "pretalx",
+                            // password: ... // provided by environment variable from secret
+                            host: pretalx.postgres.bouncer.svc.host,
+                            //port: 5432
+                        },
+                        mail: {
+                            from: cfg.smtp.from,
+                            host: cfg.smtp.server,
+                            port: 587,
+                            user: cfg.smtp.username,
+                            password: cfg.smtpPassword,
+                            tls: "True",
+                        },
+                        celery: {
+                            backend: "redis://%s/1" % [pretalx.redis.svc.host],
+                            broker: "redis://%s/2" % [pretalx.redis.svc.host],
+                        },
+                    },
+                })),
+            },
+        },
+
+        postgres: postgres {
+            cfg+: {
+                namespace: pretalx.metadata.namespace,
+                appName: pretalx.makeName("-pretalx"),
+                storageClassName: cfg.storageClassName,
+                prefix: pretalx.makeName("-postgres") + "-",
+                database: "pretalx",
+                username: "pretalx",
+                password: pretalx.cfg.pgpass,
+            },
+        },
+
+        redis: redis {
+            cfg+: {
+                namespace: pretalx.metadata.namespace,
+                appName: pretalx.makeName("-pretalx"),
+                storageClassName: cfg.storageClassName,
+                prefix: pretalx.makeName("-redis") + "-",
+            },
+        },
+
+        volumeData: kube.PersistentVolumeClaim(pretalx.makeName("-data")) {
+            metadata+: pretalx.metadata,
+            spec+: {
+                storageClassName: cfg.storageClassName,
+                accessModes: ["ReadWriteOnce"],
+                resources: {
+                    requests: {
+                        storage: "5Gi",
+                    },
+                },
+            },
+        },
+
+        s3: kube.CephObjectStoreUser(pretalx.makeNameGlobal("-s3")) {
+            metadata+: {
+                namespace: cfg.s3.cluster,
+            },
+            spec: {
+                store: cfg.s3.pool,
+                displayName: pretalx.makeNameGlobal("-s3"),
+            },
+        },
+    },
+}
diff --git a/kube/mirko.libsonnet b/kube/mirko.libsonnet
index 9693e24..b35833f 100644
--- a/kube/mirko.libsonnet
+++ b/kube/mirko.libsonnet
@@ -79,6 +79,7 @@
         local cfg = component.cfg,
 
         makeName(suffix):: "%s%s%s" % [cfg.prefix, cfg.name, suffix],
+        makeNameGlobal(suffix):: "%s-%s" % [env.cfg.namespace, component.makeName(suffix)],
 
         metadata:: {
             namespace: env.cfg.namespace,