Serge Bazanski | 1572e52 | 2020-12-03 23:19:28 +0100 | [diff] [blame] | 1 | local kube = import "../../../kube/kube.libsonnet"; |
| 2 | |
| 3 | { |
| 4 | local wow = self, |
| 5 | local cfg = wow.cfg, |
| 6 | local ns = wow.ns, |
| 7 | cfg:: { |
| 8 | namespace: error "namespace must be set", |
| 9 | prefix: "", |
| 10 | images: { |
| 11 | acore: "registry.k0.hswaw.net/q3k/azerothcore-wowtlk:1606950998", |
Serge Bazanski | 7ea8e47 | 2020-12-04 10:48:37 +0100 | [diff] [blame] | 12 | panel: "registry.k0.hswaw.net/q3k/panel:1607075221-54d0e977e57cc2c8d949c3a7ecf2ff21abd9d143", |
Serge Bazanski | 1572e52 | 2020-12-03 23:19:28 +0100 | [diff] [blame] | 13 | }, |
| 14 | db: { |
| 15 | local mkConfig = function(name) { |
| 16 | host: error ("db.%s.host must be set" % [name]), |
| 17 | port: error ("db.%s.prt must be set" % [name]), |
| 18 | user: error ("db.%s.user must be set" % [name]), |
| 19 | password: error ("db.%s.password must be set" % [name]), |
| 20 | database: "acore_%s" % [name], |
| 21 | }, |
| 22 | auth: mkConfig("auth"), |
| 23 | world: mkConfig("world"), |
| 24 | characters: mkConfig("characters"), |
| 25 | }, |
| 26 | panel: { |
| 27 | domain: error "panel.domain must be set", |
| 28 | soap: { |
| 29 | username: error "panel.soap.username must be set", |
| 30 | password: error "panel.soap.password must be set", |
| 31 | }, |
| 32 | secret: error "panel.secret must be set", |
| 33 | oauth: { |
| 34 | clientID: error "panel.oauth.clientID must set", |
| 35 | clientSecret: error "panel.oauth.clientSecret must set", |
| 36 | redirectURL: "https://%s/callback" % [cfg.panel.domain], |
| 37 | }, |
| 38 | motd: "", |
| 39 | }, |
| 40 | overrides: { |
| 41 | authserver: {}, |
| 42 | worldserver: {}, |
| 43 | ahbot: {}, |
| 44 | }, |
| 45 | }, |
| 46 | |
| 47 | ns: kube.Namespace(cfg.namespace), |
| 48 | |
| 49 | data: ns.Contain(kube.PersistentVolumeClaim(cfg.prefix + "data")) { |
| 50 | spec+: { |
| 51 | storageClassName: "waw-hdd-redundant-3", |
| 52 | accessModes: ["ReadWriteOnce"], |
| 53 | resources: { |
| 54 | requests: { |
| 55 | storage: "50Gi", |
| 56 | }, |
| 57 | }, |
| 58 | }, |
| 59 | }, |
| 60 | |
| 61 | // Make a *DatabaseInfo string for use by acore config. These are not any real |
| 62 | // standardized DSN format, just some semicolon-delimited proprietary format. |
| 63 | local mkDbString = function(config) ( |
| 64 | "%s;%d;%s;%s;%s" % [ |
| 65 | config.host, |
| 66 | config.port, |
| 67 | config.user, |
| 68 | config.password, |
| 69 | config.database, |
| 70 | ] |
| 71 | ), |
| 72 | |
| 73 | etc: ns.Contain(kube.Secret(cfg.prefix + "etc")) { |
| 74 | data: { |
| 75 | "worldserver.conf": std.base64(std.manifestIni({ |
| 76 | sections: { |
| 77 | worldserver: { |
| 78 | RealmID: 1, |
| 79 | DataDir: "/data/current", |
| 80 | LoginDatabaseInfo: mkDbString(cfg.db.auth), |
| 81 | WorldDatabaseInfo: mkDbString(cfg.db.world), |
| 82 | CharacterDatabaseInfo: mkDbString(cfg.db.characters), |
| 83 | LogLevel: 2, |
| 84 | |
| 85 | "Console.Enable": 0, |
| 86 | "Ra.Enable": 1, |
| 87 | "Ra.IP": "127.0.0.1", |
| 88 | "SOAP.Enabled": 1, |
| 89 | "SOAP.IP": "0.0.0.0", |
| 90 | |
| 91 | } + cfg.overrides.worldserver, |
| 92 | |
| 93 | }, |
| 94 | })), |
| 95 | "mod_ahbot.conf": std.base64(std.manifestIni({ |
| 96 | sections: { |
| 97 | worldserver: cfg.overrides.ahbot, |
| 98 | }, |
| 99 | })), |
| 100 | "authserver.conf": std.base64(std.manifestIni({ |
| 101 | sections: { |
| 102 | authserver: { |
| 103 | LoginDatabaseInfo: mkDbString(cfg.db.auth), |
| 104 | } + cfg.overrides.authserver, |
| 105 | }, |
| 106 | })), |
| 107 | }, |
| 108 | }, |
| 109 | |
| 110 | worldserverDeploy: ns.Contain(kube.Deployment(cfg.prefix + "worldserver")) { |
| 111 | spec+: { |
| 112 | template+: { |
| 113 | spec+: { |
| 114 | containers_: { |
| 115 | default: kube.Container("default") { |
| 116 | image: cfg.images.acore, |
| 117 | volumeMounts: [ |
| 118 | { name: "data", mountPath: "/data" }, |
| 119 | { name: "etc", mountPath: "/azeroth-server/etc/worldserver.conf", subPath: "worldserver.conf", }, |
| 120 | { name: "etc", mountPath: "/azeroth-server/etc/mod_ahbot.conf", subPath: "mod_ahbot.conf", }, |
| 121 | ], |
| 122 | command: [ |
| 123 | "/entrypoint.sh", |
| 124 | "/azeroth-server/bin/worldserver", |
| 125 | ], |
| 126 | }, |
| 127 | }, |
| 128 | securityContext: { |
| 129 | runAsUser: 999, |
| 130 | runAsGroup: 999, |
| 131 | fsGroup: 999, |
| 132 | }, |
| 133 | volumes_: { |
| 134 | data: kube.PersistentVolumeClaimVolume(wow.data), |
| 135 | etc: kube.SecretVolume(wow.etc), |
| 136 | }, |
| 137 | }, |
| 138 | }, |
| 139 | }, |
| 140 | }, |
| 141 | |
| 142 | authserverDeploy: ns.Contain(kube.Deployment(cfg.prefix + "authserver")) { |
| 143 | spec+: { |
| 144 | template+: { |
| 145 | spec+: { |
| 146 | containers_: { |
| 147 | default: kube.Container("default") { |
| 148 | image: cfg.images.acore, |
| 149 | volumeMounts_: { |
| 150 | etc: { mountPath: "/azeroth-server/etc/authserver.conf", subPath: "authserver.conf", }, |
| 151 | }, |
| 152 | command: [ |
| 153 | "/azeroth-server/bin/authserver", |
| 154 | ], |
| 155 | }, |
| 156 | }, |
| 157 | securityContext: { |
| 158 | runAsUser: 999, |
| 159 | runAsGroup: 999, |
| 160 | }, |
| 161 | volumes_: { |
| 162 | etc: kube.SecretVolume(wow.etc), |
| 163 | }, |
| 164 | }, |
| 165 | }, |
| 166 | }, |
| 167 | }, |
| 168 | |
| 169 | soapSvc: ns.Contain(kube.Service(cfg.prefix + "worldserver-soap")) { |
| 170 | target_pod:: wow.worldserverDeploy.spec.template, |
| 171 | spec+: { |
| 172 | ports: [ |
| 173 | { name: "soap", port: 7878, targetPort: 7878, protocol: "TCP" }, |
| 174 | ], |
| 175 | }, |
| 176 | }, |
| 177 | worldserverSvc: ns.Contain(kube.Service(cfg.prefix + "worldserver")) { |
| 178 | target_pod:: wow.worldserverDeploy.spec.template, |
| 179 | metadata+: { |
| 180 | annotations+: { |
| 181 | "metallb.universe.tf/allow-shared-ip": "%s/%ssvc" % [cfg.namespace, cfg.prefix], |
| 182 | }, |
| 183 | }, |
| 184 | spec+: { |
| 185 | ports: [ |
| 186 | { name: "worldserver", port: 8085, targetPort: 8085, protocol: "TCP" }, |
| 187 | ], |
| 188 | type: "LoadBalancer", |
| 189 | externalTrafficPolicy: "Cluster", |
| 190 | loadBalancerIP: cfg.address, |
| 191 | }, |
| 192 | }, |
| 193 | authserverSvc: ns.Contain(kube.Service(cfg.prefix + "authserver")) { |
| 194 | target_pod:: wow.authserverDeploy.spec.template, |
| 195 | metadata+: { |
| 196 | annotations+: { |
| 197 | "metallb.universe.tf/allow-shared-ip": "%s/%ssvc" % [cfg.namespace, cfg.prefix], |
| 198 | }, |
| 199 | }, |
| 200 | spec+: { |
| 201 | ports: [ |
| 202 | { name: "authserver", port: 3724, targetPort: 3724, protocol: "TCP" }, |
| 203 | ], |
| 204 | type: "LoadBalancer", |
| 205 | externalTrafficPolicy: "Cluster", |
| 206 | loadBalancerIP: cfg.address, |
| 207 | }, |
| 208 | }, |
| 209 | |
| 210 | panelSecret: ns.Contain(kube.Secret(cfg.prefix + "panel-secret")) { |
| 211 | data+: { |
| 212 | soapPassword: std.base64(cfg.panel.soap.password), |
| 213 | secret: std.base64(cfg.panel.secret), |
| 214 | oauthSecret: std.base64(cfg.panel.oauth.clientSecret), |
| 215 | "motd.txt": std.base64(cfg.panel.motd), |
| 216 | }, |
| 217 | }, |
| 218 | panelData: ns.Contain(kube.PersistentVolumeClaim(cfg.prefix + "panel-data")) { |
| 219 | spec+: { |
| 220 | storageClassName: "waw-hdd-redundant-3", |
| 221 | accessModes: ["ReadWriteOnce"], |
| 222 | resources: { |
| 223 | requests: { |
| 224 | storage: "128Mi", |
| 225 | }, |
| 226 | }, |
| 227 | }, |
| 228 | }, |
| 229 | panelDeploy: ns.Contain(kube.Deployment(cfg.prefix + "panel")) { |
| 230 | spec+: { |
| 231 | template+: { |
| 232 | spec+: { |
| 233 | containers_: { |
| 234 | default: kube.Container("default") { |
| 235 | image: cfg.images.panel, |
| 236 | env_: { |
| 237 | SOAP_PASSWORD: kube.SecretKeyRef(wow.panelSecret, "soapPassword"), |
| 238 | SECRET: kube.SecretKeyRef(wow.panelSecret, "secret"), |
| 239 | OAUTH_SECRET: kube.SecretKeyRef(wow.panelSecret, "oauthSecret"), |
| 240 | }, |
| 241 | command: [ |
| 242 | "/personal/q3k/wow/panel/panel", |
| 243 | "-listen", "0.0.0.0:8080", |
| 244 | "-db", "/data/panel.db", |
| 245 | "-soap_address", "http://%s" % [wow.soapSvc.host_colon_port], |
| 246 | "-soap_password", "$(SOAP_PASSWORD)", |
| 247 | "-secret", "$(SECRET)", |
| 248 | "-oauth_client_id", cfg.panel.oauth.clientID, |
| 249 | "-oauth_client_secret", "$(OAUTH_SECRET)", |
| 250 | "-oauth_redirect_url", cfg.panel.oauth.redirectURL, |
| 251 | "-motd", "/secret/motd.txt", |
| 252 | ], |
| 253 | volumeMounts_: { |
| 254 | data: { mountPath: "/data" }, |
| 255 | secret: { mountPath: "/secret" }, |
| 256 | }, |
| 257 | }, |
| 258 | }, |
| 259 | volumes_: { |
| 260 | data: kube.PersistentVolumeClaimVolume(wow.panelData), |
| 261 | secret: kube.SecretVolume(wow.panelSecret), |
| 262 | }, |
| 263 | }, |
| 264 | }, |
| 265 | }, |
| 266 | }, |
| 267 | panelSvc: ns.Contain(kube.Service(cfg.prefix + "panel")) { |
| 268 | target_pod:: wow.panelDeploy.spec.template, |
| 269 | spec+: { |
| 270 | ports: [ |
| 271 | { name: "web", port: 8080, targetPort: 8080, protocol: "TCP" }, |
| 272 | ], |
| 273 | }, |
| 274 | }, |
| 275 | panelIngress: ns.Contain(kube.Ingress(cfg.prefix + "panel")) { |
| 276 | metadata+: { |
| 277 | annotations+: { |
| 278 | "kubernetes.io/tls-acme": "true", |
| 279 | "certmanager.k8s.io/cluster-issuer": "letsencrypt-prod", |
| 280 | }, |
| 281 | }, |
| 282 | spec+: { |
| 283 | tls: [ |
| 284 | { |
| 285 | hosts: [cfg.panel.domain], |
| 286 | secretName: cfg.prefix + "panel-tls", |
| 287 | }, |
| 288 | ], |
| 289 | rules: [ |
| 290 | { |
| 291 | host: cfg.panel.domain, |
| 292 | http: { |
| 293 | paths: [ |
| 294 | { path: "/", backend: wow.panelSvc.name_port }, |
| 295 | ], |
| 296 | }, |
| 297 | } |
| 298 | ], |
| 299 | }, |
| 300 | }, |
| 301 | } |