Files
orca/internal/traefik/install_test.go
T
Jon Chery dea472f443 feat(P2): podman traefik reconciler + TLS model fix (REQ-172)
Replace internal/traefik/install.go binary+systemd installer with a
podman-container reconciler (R-024). The reconciler is idempotent:
inspect → start-if-stopped → pull+run-if-absent.

Container run flags (research-validated):
  --restart=unless-stopped (not always; research Topic 6)
  --network host (binds 127.0.0.1:8080/8443 on host/LXC loopback)
  -v /etc/traefik/traefik.yml:ro (overrides baked default; C-58)
  -v /etc/traefik/dynamic:ro (orca writes atomically via SSH-push)
  -v /etc/orca/step-ca-root.crt:ro (future mTLS; v0.14 uses tls:{})
  No :Z SELinux flag (research Topic 7)

C-50: ensurePodmanLocal/Remote installs podman if absent.
C-57: removeLegacySystemdUnitLocal/Remote stops+disables+removes
  the v0.13 orca-traefik.service + /usr/local/bin/traefik before
  starting the podman container (upgrade path).
  upgrade.go cutover rewritten to use the reconciler.

TLS model fix (research Topic 4): drop certResolver: orca from
dynamic config (traefik v3.3 only supports acme/tailscale resolvers,
not CA-file-based). Emit tls: {} instead. Real mTLS via dynamic
tls.certificates + clientAuth.caFiles deferred to v0.15 (grill
G-003, confidence 0.55 < 0.60).

Callsites updated:
  init.go: installTraefikLocal → ensureTraefikContainerLocal
  linux/bootstrap.go: traefik.InstallRemote → EnsureTraefikContainerRemote
  proxmox/bootstrap.go: same
  traefik_install.go: wrapper updated

Tests: internal/traefik/install_test.go (new) — ImageRef, podmanRunArgs,
  container-running/stopped/absent paths, legacy systemd removal (C-57).

---ci---
project: orca
phase: 2
milestone: v0.14
status: execute
---/ci---
2026-08-10 20:04:20 +00:00

167 lines
4.8 KiB
Go

package traefik
import (
"context"
"strings"
"testing"
)
func TestImageRef(t *testing.T) {
tests := []struct {
version string
want string
}{
{"v0.13.1", "git.cloudinit.dev/coreci/orca-traefik:v0.13.1"},
{"0.13.1", "git.cloudinit.dev/coreci/orca-traefik:v0.13.1"},
{"", "git.cloudinit.dev/coreci/orca-traefik:latest"},
{"dev", "git.cloudinit.dev/coreci/orca-traefik:latest"},
{"0.1.0-dev", "git.cloudinit.dev/coreci/orca-traefik:latest"},
{"v1.2.3-dev", "git.cloudinit.dev/coreci/orca-traefik:latest"},
}
for _, tt := range tests {
got := ImageRef(tt.version)
if got != tt.want {
t.Errorf("ImageRef(%q) = %q, want %q", tt.version, got, tt.want)
}
}
}
func TestPodmanRunArgs(t *testing.T) {
args := podmanRunArgs("git.cloudinit.dev/coreci/orca-traefik:v0.13.1")
joined := strings.Join(args, " ")
checks := []string{
"run -d",
"--name orca-traefik",
"--restart=unless-stopped",
"--network host",
"/etc/traefik/traefik.yml:/etc/traefik/traefik.yml:ro",
"/etc/traefik/dynamic:/etc/traefik/dynamic:ro",
"/etc/orca/step-ca-root.crt:/etc/orca/step-ca-root.crt:ro",
"git.cloudinit.dev/coreci/orca-traefik:v0.13.1",
}
for _, c := range checks {
if !strings.Contains(joined, c) {
t.Errorf("podmanRunArgs missing %q\nfull: %s", c, joined)
}
}
// Ensure no :Z flag (research Topic 7)
if strings.Contains(joined, ":Z") {
t.Errorf("podmanRunArgs should NOT contain :Z SELinux flag\nfull: %s", joined)
}
// Ensure --restart=always is NOT used (research Topic 6)
if strings.Contains(joined, "--restart=always") {
t.Errorf("podmanRunArgs should use --restart=unless-stopped, not --restart=always\nfull: %s", joined)
}
}
func TestEnsureTraefikContainerRemote_ContainerRunning(t *testing.T) {
var cmds []string
execFn := func(cmd string) ([]byte, error) {
cmds = append(cmds, cmd)
if strings.Contains(cmd, "podman inspect") {
return []byte("true\n"), nil
}
return []byte(""), nil
}
err := EnsureTraefikContainerRemote(context.Background(), "v0.13.1", execFn)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
// Should have checked inspect and found it running — no pull/run.
if len(cmds) < 1 {
t.Fatal("expected at least 1 command (inspect)")
}
for _, c := range cmds {
if strings.Contains(c, "podman pull") {
t.Errorf("should not pull when container is running: %s", c)
}
if strings.Contains(c, "podman run") {
t.Errorf("should not run when container is running: %s", c)
}
}
}
func TestEnsureTraefikContainerRemote_ContainerStopped(t *testing.T) {
var cmds []string
execFn := func(cmd string) ([]byte, error) {
cmds = append(cmds, cmd)
if strings.Contains(cmd, "podman inspect") {
return []byte("false\n"), nil // stopped
}
return []byte(""), nil
}
err := EnsureTraefikContainerRemote(context.Background(), "v0.13.1", execFn)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
// Should have started the container.
foundStart := false
for _, c := range cmds {
if strings.Contains(c, "podman start orca-traefik") {
foundStart = true
}
}
if !foundStart {
t.Errorf("expected 'podman start orca-traefik' when container is stopped\ncommands: %v", cmds)
}
}
func TestEnsureTraefikContainerRemote_ContainerAbsent(t *testing.T) {
var cmds []string
execFn := func(cmd string) ([]byte, error) {
cmds = append(cmds, cmd)
if strings.Contains(cmd, "podman inspect") {
return nil, &execError{"inspect failed: no such container"}
}
return []byte(""), nil
}
err := EnsureTraefikContainerRemote(context.Background(), "v0.13.1", execFn)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
// Should have pulled and run.
foundPull := false
foundRun := false
for _, c := range cmds {
if strings.Contains(c, "podman pull") {
foundPull = true
}
if strings.Contains(c, "podman run -d") {
foundRun = true
}
}
if !foundPull {
t.Errorf("expected 'podman pull' when container is absent\ncommands: %v", cmds)
}
if !foundRun {
t.Errorf("expected 'podman run -d' when container is absent\ncommands: %v", cmds)
}
}
func TestEnsureTraefikContainerRemote_LegacySystemdRemoval(t *testing.T) {
var cmds []string
execFn := func(cmd string) ([]byte, error) {
cmds = append(cmds, cmd)
if strings.Contains(cmd, "podman inspect") {
return []byte("true\n"), nil // container running
}
return []byte(""), nil
}
_ = EnsureTraefikContainerRemote(context.Background(), "v0.13.1", execFn)
// Should include legacy systemd unit removal command (C-57).
foundLegacyRemoval := false
for _, c := range cmds {
if strings.Contains(c, "orca-traefik.service") && strings.Contains(c, "stop") {
foundLegacyRemoval = true
}
}
if !foundLegacyRemoval {
t.Errorf("expected legacy systemd unit removal command (C-57)\ncommands: %v", cmds)
}
}
// execError is a simple error type for testing.
type execError struct{ msg string }
func (e *execError) Error() string { return e.msg }