mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-09-23 02:34:17 +00:00
The scanner shared the hold's 1 GB host and thrashed it twice: 11 hours on 2026-09-12 and again on the 13th (644 MiB resident plus 1.9 GB of swap, 504 on every repo page). It is memory-bound, not CPU-bound, so it now gets a dedicated STARTER-2xCPU-4GB server: own state entry, own plan flag (pinned name, shape match if UpCloud renames the tier again, picker last), own cloud-init, firewall, `update scanner`, `ssh scanner`, status, backup and teardown. Its config reaches the hold over the private network and its unit sets MemorySwapMax=0 so an overshoot is an OOM kill and a restart, not a wedged host. The hold's cloud-init and update paths no longer carry it. Three defects the first provision run exposed, all fixed here: - Frontend HTTP/2 defaulted to on and was reconciled onto the LB every run. Re-enabling it on the 12th stranded the appview<->hold connections for 25 minutes. Default is now off and reconciled off, with a guard test. - The TLS step requested Let's Encrypt bundles for every registry domain, re-adding the .cr ones that were removed when those moved behind Bunny. It now skips any domain whose DNS does not resolve to the LB. - Each prompt built its own bufio.Scanner on stdin, so the first swallowed every piped answer and the second read EOF and took the default, which re-ran cloud-init on the production hold. One shared reader, and no answer now means skip. Also: STARTER- plans take standard storage (maxiops fails with TIER_INVALID), and the cloud-init wait polls for up to 20 minutes instead of one SSH call capped at five, which a first boot with npm exceeds. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Hho5da4daoCoPBJ9tCrL7s
79 lines
2.6 KiB
Go
79 lines
2.6 KiB
Go
package main
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestBackupSpecForAppviewIncludesDatabaseAndLabeler(t *testing.T) {
|
|
naming := Naming{ClientName: "seamark"}
|
|
state := &InfraState{LabelerEnabled: true, ScannerEnabled: true}
|
|
now := time.Date(2026, 9, 11, 23, 0, 5, 0, time.UTC)
|
|
|
|
s := backupSpecFor("appview", naming, state, now, 5)
|
|
if s.Dir() != "/var/lib/seamark/predeploy-20260911-230005" {
|
|
t.Fatalf("dir = %q", s.Dir())
|
|
}
|
|
if s.SQLiteDB != "/var/lib/seamark/ui.db" {
|
|
t.Fatalf("SQLiteDB = %q", s.SQLiteDB)
|
|
}
|
|
want := []string{"/opt/seamark/bin/seamark-appview", "/opt/seamark/bin/seamark-labeler"}
|
|
if strings.Join(s.Binaries, ",") != strings.Join(want, ",") {
|
|
t.Fatalf("Binaries = %v", s.Binaries)
|
|
}
|
|
if strings.Join(s.Units, ",") != "seamark-appview,seamark-labeler" {
|
|
t.Fatalf("Units = %v", s.Units)
|
|
}
|
|
|
|
h := backupSpecFor("hold", naming, state, now, 5)
|
|
if h.SQLiteDB != "" {
|
|
t.Fatalf("hold backup must not snapshot a database, got %q", h.SQLiteDB)
|
|
}
|
|
if strings.Join(h.Binaries, ",") != "/opt/seamark/bin/seamark-hold" {
|
|
t.Fatalf("hold Binaries = %v (the scanner has its own server and its own backup)", h.Binaries)
|
|
}
|
|
|
|
sc := backupSpecFor("scanner", naming, state, now, 5)
|
|
if strings.Join(sc.Binaries, ",") != "/opt/seamark/bin/seamark-scanner" {
|
|
t.Fatalf("scanner Binaries = %v", sc.Binaries)
|
|
}
|
|
if strings.Join(sc.Configs, ",") != "/etc/seamark/scanner.yaml" || strings.Join(sc.Units, ",") != "seamark-scanner" {
|
|
t.Fatalf("scanner Configs = %v Units = %v", sc.Configs, sc.Units)
|
|
}
|
|
}
|
|
|
|
func TestRenderBackupScript(t *testing.T) {
|
|
s := backupSpec{
|
|
BaseDir: "/var/lib/seamark",
|
|
Stamp: "20260911-230005",
|
|
Binaries: []string{"/opt/seamark/bin/seamark-appview"},
|
|
Configs: []string{"/etc/seamark/appview.yaml"},
|
|
Units: []string{"seamark-appview"},
|
|
SQLiteDB: "/var/lib/seamark/ui.db",
|
|
Keep: 5,
|
|
}
|
|
script := renderBackupScript(s)
|
|
for _, want := range []string{
|
|
`DIR="/var/lib/seamark/predeploy-20260911-230005"`,
|
|
`cp -p "/opt/seamark/bin/seamark-appview" "$DIR/bin/"`,
|
|
`vcs.revision=`,
|
|
`cp -p "/etc/seamark/appview.yaml" "$DIR/etc/"`,
|
|
`cp -p "/etc/systemd/system/seamark-appview.service" "$DIR/systemd/"`,
|
|
`sqlite3 "/var/lib/seamark/ui.db" ".backup`,
|
|
`head -n -5 | xargs -r rm -rf`,
|
|
`echo "BACKUP_OK $DIR"`,
|
|
} {
|
|
if !strings.Contains(script, want) {
|
|
t.Errorf("script missing %q\n%s", want, script)
|
|
}
|
|
}
|
|
|
|
s.SQLiteDB = ""
|
|
s.Keep = 0
|
|
script = renderBackupScript(s)
|
|
if strings.Contains(script, "sqlite3") || strings.Contains(script, "xargs -r rm -rf") {
|
|
t.Errorf("no database and no pruning expected without SQLiteDB/Keep:\n%s", script)
|
|
}
|
|
}
|