forked from github-mirrorer/quake-kube
Add yaml server config, restart server when ConfigMap changes
This commit is contained in:
2
Makefile
2
Makefile
@ -9,7 +9,7 @@ q3: gen
|
||||
gen: ## Generate and embed templates
|
||||
@go run tools/genstatic.go public public
|
||||
|
||||
VERSION ?= v1.0.0
|
||||
VERSION ?= v1.0.1
|
||||
IMAGE ?= docker.io/criticalstack/quake:$(VERSION)
|
||||
|
||||
.PHONY: build
|
||||
|
||||
@ -3,13 +3,11 @@ package server
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
quakeclient "github.com/criticalstack/quake-kube/internal/quake/client"
|
||||
"github.com/criticalstack/quake-kube/internal/quake/content"
|
||||
@ -26,7 +24,7 @@ var opts struct {
|
||||
AcceptEula bool
|
||||
AssetsDir string
|
||||
ConfigFile string
|
||||
Maps string
|
||||
WatchInterval time.Duration
|
||||
}
|
||||
|
||||
func NewCommand() *cobra.Command {
|
||||
@ -63,45 +61,19 @@ func NewCommand() *cobra.Command {
|
||||
if err := httputil.GetUntil(opts.ContentServer, ctx.Done()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO(chrism): only download what is in map config
|
||||
if err := content.CopyAssets(csurl, opts.AssetsDir); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := writeDefaultServerConfig(filepath.Join(opts.AssetsDir, "baseq3/server.cfg")); err != nil {
|
||||
return err
|
||||
}
|
||||
if opts.ConfigFile != "" {
|
||||
data, err := ioutil.ReadFile(opts.ConfigFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(filepath.Join(opts.AssetsDir, "baseq3/server.cfg"), data, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := writeDefaultMapConfig(filepath.Join(opts.AssetsDir, "baseq3/maps.cfg")); err != nil {
|
||||
return err
|
||||
}
|
||||
if opts.Maps != "" {
|
||||
data, err := ioutil.ReadFile(opts.Maps)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var maps quakeserver.Maps
|
||||
if err := yaml.Unmarshal(data, &maps); err != nil {
|
||||
return err
|
||||
}
|
||||
data, err = maps.Marshal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(filepath.Join(opts.AssetsDir, "baseq3/maps.cfg"), data, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := quakeserver.Start(ctx, opts.AssetsDir); err != nil {
|
||||
s := quakeserver.Server{
|
||||
Dir: opts.AssetsDir,
|
||||
WatchInterval: opts.WatchInterval,
|
||||
ConfigFile: opts.ConfigFile,
|
||||
}
|
||||
if err := s.Start(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
@ -129,26 +101,6 @@ func NewCommand() *cobra.Command {
|
||||
cmd.Flags().StringVar(&opts.AssetsDir, "assets-dir", "assets", "location for game files")
|
||||
cmd.Flags().StringVar(&opts.ClientAddr, "client-addr", "", "client address <host>:<port>")
|
||||
cmd.Flags().StringVar(&opts.ServerAddr, "server-addr", "", "dedicated server <host>:<port>")
|
||||
cmd.Flags().StringVar(&opts.Maps, "maps", "", "map rotation")
|
||||
cmd.Flags().DurationVar(&opts.WatchInterval, "watch-interval", 15*time.Second, "dedicated server <host>:<port>")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func writeDefaultMapConfig(path string) error {
|
||||
maps := quakeserver.Maps{
|
||||
{Name: "q3dm7", Type: quakeserver.FreeForAll},
|
||||
{Name: "q3dm17", Type: quakeserver.FreeForAll},
|
||||
}
|
||||
data, err := maps.Marshal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(path, data, 0644)
|
||||
}
|
||||
|
||||
func writeDefaultServerConfig(path string) error {
|
||||
data, err := quakeserver.Default().Marshal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(path, data, 0644)
|
||||
}
|
||||
|
||||
40
example.yaml
40
example.yaml
@ -16,12 +16,10 @@ spec:
|
||||
- command:
|
||||
- q3
|
||||
- server
|
||||
- --config=/config/server.cfg
|
||||
- --config=/config/config.yaml
|
||||
- --content-server=http://localhost:9090
|
||||
- --maps=/config/maps.yaml
|
||||
- --agree-eula
|
||||
image: docker.io/criticalstack/quake:v1.0.0
|
||||
imagePullPolicy: Always
|
||||
image: docker.io/criticalstack/quake:v1.0.1
|
||||
name: server
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
@ -39,7 +37,7 @@ spec:
|
||||
- q3
|
||||
- content
|
||||
- --seed-content-url=http://content.quakejs.com
|
||||
image: docker.io/criticalstack/quake:v1.0.0
|
||||
image: docker.io/criticalstack/quake:v1.0.1
|
||||
name: content-server
|
||||
ports:
|
||||
- containerPort: 9090
|
||||
@ -49,7 +47,7 @@ spec:
|
||||
volumes:
|
||||
- name: quake3-server-config
|
||||
configMap:
|
||||
name: default-quake3-server-config
|
||||
name: quake3-server-config
|
||||
- name: quake3-content
|
||||
emptyDir: {}
|
||||
---
|
||||
@ -78,21 +76,23 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: default-quake3-server-config
|
||||
name: quake3-server-config
|
||||
data:
|
||||
server.cfg: |
|
||||
seta sv_hostname "quakekube"
|
||||
seta g_log ""
|
||||
seta sv_maxclients 12
|
||||
seta g_motd "Welcome to Critical Stack"
|
||||
seta g_quadfactor 3
|
||||
seta timelimit 15
|
||||
seta fraglimit 25
|
||||
seta g_weaponrespawn 3
|
||||
seta g_inactivity 600
|
||||
seta g_forcerespawn 0
|
||||
seta rconpassword "changeme"
|
||||
maps.yaml: |
|
||||
config.yaml: |
|
||||
fragLimit: 25
|
||||
timeLimit: 15m
|
||||
game:
|
||||
motd: "Welcome to Critical Stack"
|
||||
type: FreeForAll
|
||||
forceRespawn: false
|
||||
inactivity: 10m
|
||||
quadFactor: 3
|
||||
weaponRespawn: 3
|
||||
server:
|
||||
hostname: "quakekube"
|
||||
maxClients: 12
|
||||
password: "changeme"
|
||||
maps:
|
||||
- name: q3dm7
|
||||
type: FreeForAll
|
||||
- name: q3dm17
|
||||
|
||||
3
go.mod
3
go.mod
@ -4,12 +4,13 @@ go 1.14
|
||||
|
||||
require (
|
||||
github.com/cockroachdb/cmux v0.0.0-20170110192607-30d10be49292
|
||||
github.com/google/go-cmp v0.2.0
|
||||
github.com/google/go-cmp v0.3.0
|
||||
github.com/gorilla/websocket v1.4.0
|
||||
github.com/labstack/echo/v4 v4.1.16
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect
|
||||
github.com/shurcooL/vfsgen v0.0.0-20200627165143-92b8a710ab6c // indirect
|
||||
github.com/spf13/cobra v1.0.0
|
||||
k8s.io/apimachinery v0.18.6
|
||||
sigs.k8s.io/yaml v1.2.0
|
||||
)
|
||||
|
||||
65
go.sum
65
go.sum
@ -1,6 +1,9 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
@ -22,35 +25,61 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
|
||||
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
|
||||
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
|
||||
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
@ -64,6 +93,7 @@ github.com/labstack/echo/v4 v4.1.16/go.mod h1:awO+5TzAjvL8XpibdsfXxPgHr+orhtXZJZ
|
||||
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
|
||||
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
@ -74,8 +104,19 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
@ -105,12 +146,15 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU
|
||||
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
|
||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
@ -132,35 +176,44 @@ golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAak
|
||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
@ -173,11 +226,23 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
k8s.io/apimachinery v0.18.6 h1:RtFHnfGNfd1N0LeSrKCUznz5xtUP1elRGvHJbL3Ntag=
|
||||
k8s.io/apimachinery v0.18.6/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko=
|
||||
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||
k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
|
||||
sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
|
||||
sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||
|
||||
@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type GameType int
|
||||
@ -58,16 +59,19 @@ func (gt *GameType) UnmarshalText(data []byte) error {
|
||||
|
||||
type Config struct {
|
||||
FragLimit int `name:"fraglimit"`
|
||||
TimeLimit time.Duration `name:"timelimit"`
|
||||
TimeLimit metav1.Duration `name:"timelimit"`
|
||||
|
||||
GameConfig
|
||||
ServerConfig
|
||||
GameConfig `json:"game"`
|
||||
FileServerConfig `json:"fs"`
|
||||
ServerConfig `json:"server"`
|
||||
|
||||
Maps
|
||||
}
|
||||
|
||||
type GameConfig struct {
|
||||
ForceRespawn bool `name:"g_forcerespawn"`
|
||||
GameType GameType `name:"g_gametype"`
|
||||
Inactivity time.Duration `name:"g_inactivity"`
|
||||
GameType GameType `json:"type" name:"g_gametype"`
|
||||
Inactivity metav1.Duration `name:"g_inactivity"`
|
||||
Log string `name:"g_log"`
|
||||
MOTD string `name:"g_motd"`
|
||||
QuadFactor int `name:"g_quadfactor"`
|
||||
@ -117,6 +121,14 @@ func writeStruct(v reflect.Value) ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
b.Write(data)
|
||||
case reflect.Slice:
|
||||
switch val := fv.Interface().(type) {
|
||||
case Maps:
|
||||
data, _ := val.Marshal()
|
||||
b.Write(data)
|
||||
default:
|
||||
panic(fmt.Errorf("received unknown type %T", val))
|
||||
}
|
||||
default:
|
||||
tv, ok := v.Type().Field(i).Tag.Lookup("name")
|
||||
if !ok {
|
||||
@ -142,7 +154,7 @@ func toString(name string, v reflect.Value) string {
|
||||
return val
|
||||
case int:
|
||||
return strconv.Itoa(val)
|
||||
case time.Duration:
|
||||
case metav1.Duration:
|
||||
switch name {
|
||||
case "TimeLimit":
|
||||
return fmt.Sprintf("%d", int(val.Minutes()))
|
||||
@ -156,6 +168,9 @@ func toString(name string, v reflect.Value) string {
|
||||
return "0"
|
||||
case GameType:
|
||||
return fmt.Sprintf("%d", val)
|
||||
case Maps:
|
||||
data, _ := val.Marshal()
|
||||
return string(data)
|
||||
default:
|
||||
panic(fmt.Errorf("received unknown type %T", v.Interface()))
|
||||
}
|
||||
@ -163,15 +178,15 @@ func toString(name string, v reflect.Value) string {
|
||||
|
||||
func Default() *Config {
|
||||
return &Config{
|
||||
TimeLimit: 15 * time.Minute,
|
||||
FragLimit: 25,
|
||||
TimeLimit: metav1.Duration{Duration: 15 * time.Minute},
|
||||
GameConfig: GameConfig{
|
||||
Log: "",
|
||||
MOTD: "Welcome to Critical Stack",
|
||||
QuadFactor: 3,
|
||||
GameType: FreeForAll,
|
||||
WeaponRespawn: 3,
|
||||
Inactivity: 10 * time.Minute,
|
||||
Inactivity: metav1.Duration{Duration: 10 * time.Minute},
|
||||
ForceRespawn: false,
|
||||
},
|
||||
ServerConfig: ServerConfig{
|
||||
@ -179,9 +194,22 @@ func Default() *Config {
|
||||
Hostname: "quakekube",
|
||||
Password: "changeme",
|
||||
},
|
||||
Maps: Maps{
|
||||
{Name: "q3dm7", Type: FreeForAll},
|
||||
{Name: "q3dm17", Type: FreeForAll},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type Map struct {
|
||||
Name string `json:"name"`
|
||||
Type GameType `json:"type"`
|
||||
|
||||
CaptureLimit int `json:"captureLimit"`
|
||||
FragLimit int `json:"fragLimit"`
|
||||
TimeLimit time.Duration `json:"timeLimit"`
|
||||
}
|
||||
|
||||
type Maps []Map
|
||||
|
||||
func (maps Maps) Marshal() ([]byte, error) {
|
||||
@ -210,12 +238,3 @@ func (maps Maps) Marshal() ([]byte, error) {
|
||||
b.WriteString("vstr d0")
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
type Map struct {
|
||||
Name string `json:"name"`
|
||||
Type GameType `json:"type"`
|
||||
|
||||
CaptureLimit int `json:"captureLimit"`
|
||||
FragLimit int `json:"fragLimit"`
|
||||
TimeLimit time.Duration `json:"timeLimit"`
|
||||
}
|
||||
|
||||
@ -8,35 +8,22 @@ import (
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
const expectedConfig = `seta fraglimit "25"
|
||||
seta timelimit "15"
|
||||
seta g_forcerespawn "0"
|
||||
seta g_gametype "0"
|
||||
seta g_inactivity "600"
|
||||
seta g_log ""
|
||||
seta g_motd "Welcome to Critical Stack"
|
||||
seta g_quadfactor "3"
|
||||
seta g_weaponrespawn "3"
|
||||
seta sv_allowDownload "0"
|
||||
seta sv_hostname "quakekube"
|
||||
seta sv_maxclients "12"
|
||||
seta rconpassword "changeme"
|
||||
`
|
||||
|
||||
func TestConfigMarshal(t *testing.T) {
|
||||
c := Default()
|
||||
|
||||
data, err := c.Marshal()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Printf("data = %s\n", data)
|
||||
if diff := cmp.Diff(string(data), expectedConfig); diff != "" {
|
||||
t.Fatalf(diff)
|
||||
}
|
||||
}
|
||||
|
||||
const mapConfig = `- name: q3dm7
|
||||
const config = `
|
||||
fragLimit: 25
|
||||
timeLimit: 15m
|
||||
game:
|
||||
motd: "Welcome to Critical Stack"
|
||||
type: FreeForAll
|
||||
forceRespawn: false
|
||||
inactivity: 10m
|
||||
quadFactor: 3
|
||||
weaponRespawn: 3
|
||||
server:
|
||||
hostname: "quakekube"
|
||||
maxClients: 12
|
||||
password: "changeme"
|
||||
maps:
|
||||
- name: q3dm7
|
||||
type: FreeForAll
|
||||
- name: q3dm17
|
||||
type: FreeForAll
|
||||
@ -52,7 +39,24 @@ const mapConfig = `- name: q3dm7
|
||||
type: Tournament
|
||||
`
|
||||
|
||||
const expectedMapConfig = `set d0 "seta g_gametype 0 ; map q3dm7 ; set nextmap vstr d1"
|
||||
const expectedConfig = `seta fraglimit "25"
|
||||
seta g_forcerespawn "0"
|
||||
seta g_gametype "0"
|
||||
seta g_log ""
|
||||
seta g_motd "Welcome to Critical Stack"
|
||||
seta g_quadfactor "3"
|
||||
seta g_weaponrespawn "3"
|
||||
seta fs_basegame ""
|
||||
seta fs_basepath ""
|
||||
seta fs_copyfiles "0"
|
||||
seta fs_debug "0"
|
||||
seta fs_game ""
|
||||
seta fs_homepath ""
|
||||
seta sv_allowDownload "0"
|
||||
seta sv_hostname "quakekube"
|
||||
seta sv_maxclients "12"
|
||||
seta rconpassword "changeme"
|
||||
set d0 "seta g_gametype 0 ; map q3dm7 ; set nextmap vstr d1"
|
||||
set d1 "seta g_gametype 0 ; map q3dm17 ; set nextmap vstr d2"
|
||||
set d2 "seta g_gametype 4 ; capturelimit 8 ; map q3wctf1 ; set nextmap vstr d3"
|
||||
set d3 "seta g_gametype 1 ; map q3tourney2 ; set nextmap vstr d4"
|
||||
@ -60,21 +64,18 @@ set d4 "seta g_gametype 4 ; capturelimit 8 ; map q3wctf3 ; set nextmap vstr d5"
|
||||
set d5 "seta g_gametype 1 ; map ztn3tourney1 ; set nextmap vstr d0"
|
||||
vstr d0`
|
||||
|
||||
func TestMapRead(t *testing.T) {
|
||||
var maps Maps
|
||||
if err := yaml.Unmarshal([]byte(mapConfig), &maps); err != nil {
|
||||
func TestConfigMarshal(t *testing.T) {
|
||||
var cfg *Config
|
||||
if err := yaml.Unmarshal([]byte(config), &cfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, m := range maps {
|
||||
fmt.Printf("m = %+v\n", m)
|
||||
}
|
||||
data, err := maps.Marshal()
|
||||
data, err := cfg.Marshal()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(string(data), expectedMapConfig); diff != "" {
|
||||
fmt.Printf("%s\n", data)
|
||||
if diff := cmp.Diff(string(data), expectedConfig); diff != "" {
|
||||
t.Fatalf(diff)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2,17 +2,126 @@ package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/criticalstack/quake-kube/internal/util/exec"
|
||||
)
|
||||
|
||||
func Start(ctx context.Context, dir string) error {
|
||||
cmd := exec.CommandContext(ctx, "ioq3ded", "+set", "dedicated", "1", "+exec", "server.cfg", "+exec", "maps.cfg")
|
||||
cmd.Dir = dir
|
||||
type Server struct {
|
||||
Dir string
|
||||
WatchInterval time.Duration
|
||||
ConfigFile string
|
||||
}
|
||||
|
||||
func (s *Server) Start(ctx context.Context) error {
|
||||
cmd := exec.CommandContext(ctx, "ioq3ded", "+set", "dedicated", "1", "+exec", "server.cfg")
|
||||
cmd.Dir = s.Dir
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
if s.ConfigFile == "" {
|
||||
cfg := Default()
|
||||
data, err := cfg.Marshal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(filepath.Join(s.Dir, "baseq3/server.cfg"), data, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
return cmd.Wait()
|
||||
}
|
||||
|
||||
if err := s.reload(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := cmd.Wait(); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}()
|
||||
|
||||
ch, err := s.watch(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ch:
|
||||
if err := s.reload(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.Restart(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
if err := cmd.Wait(); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}()
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) reload() error {
|
||||
data, err := ioutil.ReadFile(s.ConfigFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var cfg *Config
|
||||
if err := yaml.Unmarshal(data, &cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
data, err = cfg.Marshal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(filepath.Join(s.Dir, "baseq3/server.cfg"), data, 0644)
|
||||
}
|
||||
|
||||
func (s *Server) watch(ctx context.Context) (<-chan struct{}, error) {
|
||||
if s.WatchInterval == 0 {
|
||||
s.WatchInterval = 15 * time.Second
|
||||
}
|
||||
cur, err := os.Stat(s.ConfigFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ch := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
ticker := time.NewTicker(s.WatchInterval)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
if fi, err := os.Stat(s.ConfigFile); err == nil {
|
||||
if fi.ModTime().After(cur.ModTime()) {
|
||||
ch <- struct{}{}
|
||||
}
|
||||
cur = fi
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
return ch, nil
|
||||
}
|
||||
|
||||
30
internal/util/exec/exec.go
Normal file
30
internal/util/exec/exec.go
Normal file
@ -0,0 +1,30 @@
|
||||
package exec
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
type Cmd struct {
|
||||
*exec.Cmd
|
||||
}
|
||||
|
||||
func (cmd *Cmd) Restart(ctx context.Context) error {
|
||||
if cmd.Process != nil {
|
||||
if err := cmd.Process.Kill(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
newCmd := exec.CommandContext(ctx, cmd.Args[0], cmd.Args[1:]...)
|
||||
newCmd.Dir = cmd.Dir
|
||||
newCmd.Env = cmd.Env
|
||||
newCmd.Stdin = cmd.Stdin
|
||||
newCmd.Stdout = cmd.Stdout
|
||||
newCmd.Stderr = cmd.Stderr
|
||||
cmd.Cmd = newCmd
|
||||
return cmd.Start()
|
||||
}
|
||||
|
||||
func CommandContext(ctx context.Context, name string, args ...string) *Cmd {
|
||||
return &Cmd{Cmd: exec.CommandContext(ctx, name, args...)}
|
||||
}
|
||||
Reference in New Issue
Block a user