local kube = import "../../../kube/kube.libsonnet"; { local wow = self, local cfg = wow.cfg, local ns = wow.ns, cfg:: { namespace: error "namespace must be set", prefix: "", images: { acore: "registry.k0.hswaw.net/q3k/azerothcore-wowtlk:1606950998", panel: "registry.k0.hswaw.net/q3k/panel:1607075221-54d0e977e57cc2c8d949c3a7ecf2ff21abd9d143", }, db: { local mkConfig = function(name) { host: error ("db.%s.host must be set" % [name]), port: error ("db.%s.prt must be set" % [name]), user: error ("db.%s.user must be set" % [name]), password: error ("db.%s.password must be set" % [name]), database: "acore_%s" % [name], }, auth: mkConfig("auth"), world: mkConfig("world"), characters: mkConfig("characters"), }, panel: { domain: error "panel.domain must be set", soap: { username: error "panel.soap.username must be set", password: error "panel.soap.password must be set", }, secret: error "panel.secret must be set", oauth: { clientID: error "panel.oauth.clientID must set", clientSecret: error "panel.oauth.clientSecret must set", redirectURL: "https://%s/callback" % [cfg.panel.domain], }, motd: "", }, overrides: { authserver: {}, worldserver: {}, ahbot: {}, }, }, ns: kube.Namespace(cfg.namespace), data: ns.Contain(kube.PersistentVolumeClaim(cfg.prefix + "data")) { spec+: { storageClassName: "waw-hdd-redundant-3", accessModes: ["ReadWriteOnce"], resources: { requests: { storage: "50Gi", }, }, }, }, // Make a *DatabaseInfo string for use by acore config. These are not any real // standardized DSN format, just some semicolon-delimited proprietary format. local mkDbString = function(config) ( "%s;%d;%s;%s;%s" % [ config.host, config.port, config.user, config.password, config.database, ] ), etc: ns.Contain(kube.Secret(cfg.prefix + "etc")) { data: { "worldserver.conf": std.base64(std.manifestIni({ sections: { worldserver: { RealmID: 1, DataDir: "/data/current", LoginDatabaseInfo: mkDbString(cfg.db.auth), WorldDatabaseInfo: mkDbString(cfg.db.world), CharacterDatabaseInfo: mkDbString(cfg.db.characters), LogLevel: 2, "Console.Enable": 0, "Ra.Enable": 1, "Ra.IP": "127.0.0.1", "SOAP.Enabled": 1, "SOAP.IP": "0.0.0.0", } + cfg.overrides.worldserver, }, })), "mod_ahbot.conf": std.base64(std.manifestIni({ sections: { worldserver: cfg.overrides.ahbot, }, })), "authserver.conf": std.base64(std.manifestIni({ sections: { authserver: { LoginDatabaseInfo: mkDbString(cfg.db.auth), } + cfg.overrides.authserver, }, })), }, }, worldserverDeploy: ns.Contain(kube.Deployment(cfg.prefix + "worldserver")) { spec+: { template+: { spec+: { containers_: { default: kube.Container("default") { image: cfg.images.acore, volumeMounts: [ { name: "data", mountPath: "/data" }, { name: "etc", mountPath: "/azeroth-server/etc/worldserver.conf", subPath: "worldserver.conf", }, { name: "etc", mountPath: "/azeroth-server/etc/mod_ahbot.conf", subPath: "mod_ahbot.conf", }, ], command: [ "/entrypoint.sh", "/azeroth-server/bin/worldserver", ], }, }, securityContext: { runAsUser: 999, runAsGroup: 999, fsGroup: 999, }, volumes_: { data: kube.PersistentVolumeClaimVolume(wow.data), etc: kube.SecretVolume(wow.etc), }, }, }, }, }, authserverDeploy: ns.Contain(kube.Deployment(cfg.prefix + "authserver")) { spec+: { template+: { spec+: { containers_: { default: kube.Container("default") { image: cfg.images.acore, volumeMounts_: { etc: { mountPath: "/azeroth-server/etc/authserver.conf", subPath: "authserver.conf", }, }, command: [ "/azeroth-server/bin/authserver", ], }, }, securityContext: { runAsUser: 999, runAsGroup: 999, }, volumes_: { etc: kube.SecretVolume(wow.etc), }, }, }, }, }, soapSvc: ns.Contain(kube.Service(cfg.prefix + "worldserver-soap")) { target_pod:: wow.worldserverDeploy.spec.template, spec+: { ports: [ { name: "soap", port: 7878, targetPort: 7878, protocol: "TCP" }, ], }, }, worldserverSvc: ns.Contain(kube.Service(cfg.prefix + "worldserver")) { target_pod:: wow.worldserverDeploy.spec.template, metadata+: { annotations+: { "metallb.universe.tf/allow-shared-ip": "%s/%ssvc" % [cfg.namespace, cfg.prefix], }, }, spec+: { ports: [ { name: "worldserver", port: 8085, targetPort: 8085, protocol: "TCP" }, ], type: "LoadBalancer", externalTrafficPolicy: "Cluster", loadBalancerIP: cfg.address, }, }, authserverSvc: ns.Contain(kube.Service(cfg.prefix + "authserver")) { target_pod:: wow.authserverDeploy.spec.template, metadata+: { annotations+: { "metallb.universe.tf/allow-shared-ip": "%s/%ssvc" % [cfg.namespace, cfg.prefix], }, }, spec+: { ports: [ { name: "authserver", port: 3724, targetPort: 3724, protocol: "TCP" }, ], type: "LoadBalancer", externalTrafficPolicy: "Cluster", loadBalancerIP: cfg.address, }, }, panelSecret: ns.Contain(kube.Secret(cfg.prefix + "panel-secret")) { data+: { soapPassword: std.base64(cfg.panel.soap.password), secret: std.base64(cfg.panel.secret), oauthSecret: std.base64(cfg.panel.oauth.clientSecret), "motd.txt": std.base64(cfg.panel.motd), }, }, panelData: ns.Contain(kube.PersistentVolumeClaim(cfg.prefix + "panel-data")) { spec+: { storageClassName: "waw-hdd-redundant-3", accessModes: ["ReadWriteOnce"], resources: { requests: { storage: "128Mi", }, }, }, }, panelDeploy: ns.Contain(kube.Deployment(cfg.prefix + "panel")) { spec+: { template+: { spec+: { containers_: { default: kube.Container("default") { image: cfg.images.panel, env_: { SOAP_PASSWORD: kube.SecretKeyRef(wow.panelSecret, "soapPassword"), SECRET: kube.SecretKeyRef(wow.panelSecret, "secret"), OAUTH_SECRET: kube.SecretKeyRef(wow.panelSecret, "oauthSecret"), }, command: [ "/personal/q3k/wow/panel/panel", "-listen", "0.0.0.0:8080", "-db", "/data/panel.db", "-soap_address", "http://%s" % [wow.soapSvc.host_colon_port], "-soap_password", "$(SOAP_PASSWORD)", "-secret", "$(SECRET)", "-oauth_client_id", cfg.panel.oauth.clientID, "-oauth_client_secret", "$(OAUTH_SECRET)", "-oauth_redirect_url", cfg.panel.oauth.redirectURL, "-motd", "/secret/motd.txt", ], volumeMounts_: { data: { mountPath: "/data" }, secret: { mountPath: "/secret" }, }, }, }, volumes_: { data: kube.PersistentVolumeClaimVolume(wow.panelData), secret: kube.SecretVolume(wow.panelSecret), }, }, }, }, }, panelSvc: ns.Contain(kube.Service(cfg.prefix + "panel")) { target_pod:: wow.panelDeploy.spec.template, spec+: { ports: [ { name: "web", port: 8080, targetPort: 8080, protocol: "TCP" }, ], }, }, panelIngress: ns.Contain(kube.Ingress(cfg.prefix + "panel")) { metadata+: { annotations+: { "kubernetes.io/tls-acme": "true", "cert-manager.io/cluster-issuer": "letsencrypt-prod", }, }, spec+: { tls: [ { hosts: [cfg.panel.domain], secretName: cfg.prefix + "panel-tls", }, ], rules: [ { host: cfg.panel.domain, http: { paths: [ { path: "/", backend: wow.panelSvc.name_port }, ], }, } ], }, }, }