feat: multi-distro support and tagged golden snapshots

Add Alpine, Debian, and Ubuntu rootfs support to `init [distro]`.
Golden snapshots are now namespaced under `golden/<tag>/` so multiple
baselines can coexist. `spawn [tag] [N]` selects which snapshot to
clone from. Systemd-based distros (Debian, Ubuntu) get a fc-net-init
systemd unit; Alpine keeps its inittab-based init.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-14 20:48:43 +00:00
parent bfc1f47287
commit fb1db7c9ea
10 changed files with 576 additions and 102 deletions

View File

@@ -53,10 +53,11 @@ func Serve(orch *Orchestrator, addr string) error {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(ids) //nolint:errcheck
case http.MethodPost:
// Optional JSON body: {"net": bool}
// Optional JSON body: {"net": bool, "tag": string}
// Defaults to the server's FC_AUTO_NET_CONFIG setting.
var req struct {
Net *bool `json:"net"`
Net *bool `json:"net"`
Tag *string `json:"tag"`
}
if r.ContentLength > 0 {
json.NewDecoder(r.Body).Decode(&req) //nolint:errcheck
@@ -65,7 +66,11 @@ func Serve(orch *Orchestrator, addr string) error {
if req.Net != nil {
net = *req.Net
}
id, err := orch.SpawnSingle(net)
tag := "default"
if req.Tag != nil && *req.Tag != "" {
tag = *req.Tag
}
id, err := orch.SpawnSingle(net, tag)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
@@ -77,6 +82,16 @@ func Serve(orch *Orchestrator, addr string) error {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
}
})
// /tags — list all available golden VM tags
mux.HandleFunc("/tags", func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet && r.Method != "" {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
tags := orch.GoldenTags()
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(tags) //nolint:errcheck
})
// /clones/{id} — destroy (DELETE)
mux.HandleFunc("/clones/", func(w http.ResponseWriter, r *http.Request) {