Files
DoGaMa-serv/internal/agent/agent_docker_test.go
T

118 lines
4.2 KiB
Go

package agent
import (
"context"
"encoding/json"
"io"
"net"
"net/http"
"path/filepath"
"strings"
"testing"
"git.zaynet.fr/DoGaMa/DoGaMa-serv/internal/agentwire"
)
func TestDockerPingerUsesConfiguredUnixSocket(t *testing.T) {
socket := filepath.Join(t.TempDir(), "docker.sock")
listener, err := net.Listen("unix", socket)
if err != nil {
t.Fatal(err)
}
server := &http.Server{Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/_ping" {
http.NotFound(w, r)
return
}
_, _ = w.Write([]byte("OK"))
})}
go func() { _ = server.Serve(listener) }()
t.Cleanup(func() { _ = server.Shutdown(context.Background()) })
pinger, err := NewDockerRuntime(socket, "dogama-games")
if err != nil {
t.Fatal(err)
}
if err := pinger.Ping(context.Background()); err != nil {
t.Fatal(err)
}
}
func TestDockerRuntimeCreatesFixedSecurityBaseline(t *testing.T) {
socket := filepath.Join(t.TempDir(), "docker.sock")
listener, err := net.Listen("unix", socket)
if err != nil {
t.Fatal(err)
}
createdBodies := make(chan []byte, 1)
server := &http.Server{Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch {
case r.URL.Path == "/v1.41/images/create":
_, _ = w.Write([]byte("{}\n"))
case r.URL.Path == "/v1.41/containers/json":
_, _ = w.Write([]byte("[]"))
case r.URL.Path == "/v1.41/containers/create":
body, _ := io.ReadAll(r.Body)
createdBodies <- body
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
_, _ = w.Write([]byte(`{"Id":"container-1"}`))
default:
http.NotFound(w, r)
}
})}
go func() { _ = server.Serve(listener) }()
t.Cleanup(func() { _ = server.Shutdown(context.Background()) })
runtime, err := NewDockerRuntime(socket, "dogama-games")
if err != nil {
t.Fatal(err)
}
plan := agentwire.DeploymentPlan{
InstanceID: "abcdefghijklmnopqrstuvwx", TemplateID: "palworld-official", TemplateVersion: "1.0.0", PlanDigest: strings.Repeat("a", 64), Image: "example.invalid/game:1",
Ports: []agentwire.PlanPort{{ID: "game", Protocol: "udp", ContainerPort: 8211, HostPort: 38211, Publish: true}},
Mounts: []agentwire.PlanMount{{ID: "saved", HostPath: "/srv/games/saved", ContainerPath: "/game/saved"}}, Resources: agentwire.PlanResource{CPUCores: 2, MemoryMB: 1024, StorageGB: 10}, Labels: map[string]string{"dashboard.name": "Summer"}, User: "1000:1001",
}
if err := runtime.CheckPorts(context.Background(), plan.Ports); err != nil {
t.Fatal(err)
}
id, err := runtime.Create(context.Background(), plan, []AssetMount{{HostPath: "/srv/games/.dogama/helper", ContainerPath: "/pal/helper.sh"}})
if err != nil {
t.Fatal(err)
}
if id != "container-1" {
t.Fatalf("container ID = %q", id)
}
var payload struct {
User string `json:"User"`
Labels map[string]string `json:"Labels"`
HostConfig struct {
NetworkMode string `json:"NetworkMode"`
CapDrop []string `json:"CapDrop"`
SecurityOpt []string `json:"SecurityOpt"`
Memory int64 `json:"Memory"`
NanoCPUs int64 `json:"NanoCpus"`
} `json:"HostConfig"`
}
if err := json.Unmarshal(<-createdBodies, &payload); err != nil {
t.Fatal(err)
}
if payload.HostConfig.NetworkMode != "dogama-games" || len(payload.HostConfig.CapDrop) != 1 || payload.HostConfig.CapDrop[0] != "ALL" || len(payload.HostConfig.SecurityOpt) != 1 || payload.HostConfig.Memory <= 0 || payload.HostConfig.NanoCPUs <= 0 {
t.Fatalf("insecure Docker host config: %#v", payload.HostConfig)
}
if payload.Labels["io.dogama.instance-id"] != plan.InstanceID || payload.Labels["io.dogama.plan-digest"] != plan.PlanDigest {
t.Fatalf("binding labels = %#v", payload.Labels)
}
if payload.Labels["dashboard.name"] != "Summer" || payload.User != "1000:1001" {
t.Fatalf("custom Docker configuration = %#v user=%q", payload.Labels, payload.User)
}
}
func TestDockerPingerDoesNotExposeConnectionDetails(t *testing.T) {
pinger, err := NewDockerRuntime(filepath.Join(t.TempDir(), "missing.sock"), "dogama-games")
if err != nil {
t.Fatal(err)
}
if err := pinger.Ping(context.Background()); err == nil || err.Error() != "docker daemon is unavailable" {
t.Fatalf("Ping error = %v", err)
}
}