v0.20.0: golden stacks-dir bind + per-guest hostname/CT + bake base-infra images
build-golden.sh: same-path /opt/docker/stacks host bind (Section-G fix, breaks all bind-mounted stacks without it) + --hostname <customer-id> from bootstrap.json (portable sed parse, no jq) + bake the 3 pinned public base-infra images with a manifest-inspect hard gate. Provision --selftest defaults -hostname to the DNS-safe-sanitized customer-id so the CT/LXC is named meaningfully. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -42,7 +42,7 @@ import (
|
||||
|
||||
// version is the agent version. Overridable at build time with
|
||||
// -ldflags "-X main.version=<v>"; defaults to the in-repo CHANGELOG version.
|
||||
var version = "0.19.0"
|
||||
var version = "0.20.0"
|
||||
|
||||
func main() {
|
||||
var (
|
||||
@@ -966,6 +966,30 @@ type provisionArgs struct {
|
||||
hubPassword string // the customer's hub retrieval passphrase (SECRET) — baked into bootstrap
|
||||
}
|
||||
|
||||
// sanitizeHostname makes s a DNS-safe LXC hostname (RFC 1123 label-ish): lowercase, any run of
|
||||
// invalid characters collapses to a single '-', leading/trailing '-' stripped, capped at 63 chars.
|
||||
// Returns "" if nothing usable remains (caller then sets no hostname). PVE itself validates, but a
|
||||
// customer id can legitimately contain characters (e.g. '_' or spaces) that a hostname cannot.
|
||||
func sanitizeHostname(s string) string {
|
||||
s = strings.ToLower(strings.TrimSpace(s))
|
||||
var b strings.Builder
|
||||
prevDash := false
|
||||
for _, r := range s {
|
||||
if (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') {
|
||||
b.WriteRune(r)
|
||||
prevDash = false
|
||||
} else if !prevDash && b.Len() > 0 {
|
||||
b.WriteByte('-')
|
||||
prevDash = true
|
||||
}
|
||||
}
|
||||
out := strings.Trim(b.String(), "-")
|
||||
if len(out) > 63 {
|
||||
out = strings.Trim(out[:63], "-")
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// runSelftestProvision runs the FULL slice-8A provisioning chain on-demand: the slice-7 bring-up
|
||||
// FRONT half (provision mode, golden) + the slice-8A BACK half (mint per-guest token → render the
|
||||
// stable bootstrap.json → write 0600 → chown to the mapped guest-root → attach the read-only bind
|
||||
@@ -1033,12 +1057,20 @@ func runSelftestProvision(ctx context.Context, cfg config.Config, logger *slog.L
|
||||
API: px, Queue: queue, Journal: journal, Gate: gate, HostID: cfg.Hub.HostID, Logger: logger,
|
||||
})
|
||||
|
||||
fmt.Printf("=== felhom-agent %s selftest=provision (vmid=%d customer=%s) ===\n", version, a.vmid, a.customerID)
|
||||
// Default the guest hostname to the customer id (DNS-safe-sanitized) when not explicitly given,
|
||||
// so the CT/LXC is named meaningfully (e.g. "demo-felhom") instead of inheriting the golden's
|
||||
// baked "felhom-golden". An explicit -hostname always wins.
|
||||
hostname := a.hostname
|
||||
if hostname == "" {
|
||||
hostname = sanitizeHostname(a.customerID)
|
||||
}
|
||||
|
||||
fmt.Printf("=== felhom-agent %s selftest=provision (vmid=%d customer=%s hostname=%s) ===\n", version, a.vmid, a.customerID, hostname)
|
||||
engine.Recover(ctx)
|
||||
fmt.Printf(" --- front half: bring-up (provision) %s → vmid %d ---\n", a.archive, a.vmid)
|
||||
res := engine.RunBringUp(ctx, reconcile.BringUpSpec{
|
||||
Mode: reconcile.ModeProvision, Archive: a.archive, VMID: a.vmid,
|
||||
RestoreStorage: cfg.Backup.RestoreStorage, Hostname: a.hostname,
|
||||
RestoreStorage: cfg.Backup.RestoreStorage, Hostname: hostname,
|
||||
})
|
||||
if res.Err != nil || !res.Pass {
|
||||
fmt.Fprintf(os.Stderr, " [FAIL] front-half bring-up (vmid %d): %v\n", a.vmid, res.Err)
|
||||
|
||||
Reference in New Issue
Block a user