metis/pkg/plan/burn.go

74 lines
1.9 KiB
Go

package plan
import (
"context"
"fmt"
"os"
"path/filepath"
"metis/pkg/image"
"metis/pkg/inventory"
"metis/pkg/mount"
"metis/pkg/writer"
)
// Execute performs a burn if confirm is true. With confirm=false, it only downloads/verifies and returns the plan.
func Execute(inv *inventory.Inventory, nodeName, device, cacheDir string, confirm bool) (*Plan, error) {
p, err := Build(inv, nodeName, device, cacheDir)
if err != nil {
return nil, err
}
cacheImage := filepath.Join(cacheDir, cacheName(p.Image))
cacheImage, err = image.DownloadAndVerify(p.Image, cacheImage, checksumFromInventory(inv, nodeName))
if err != nil {
return p, fmt.Errorf("download image: %w", err)
}
if !confirm {
return p, nil
}
if device == "" || device == "/dev/sdX" {
return p, fmt.Errorf("refusing to write to placeholder device")
}
ctx := context.Background()
if err := writer.WriteImage(ctx, cacheImage, device); err != nil {
return p, fmt.Errorf("write image: %w", err)
}
if err := maybeInject(inv, nodeName); err != nil {
return p, fmt.Errorf("inject config: %w", err)
}
if auto := maybeAutoMount(device); auto != nil {
defer mount.Teardown(auto)
if err := maybeInject(inv, nodeName); err != nil {
return p, fmt.Errorf("inject (auto-mount): %w", err)
}
}
return p, nil
}
func checksumFromInventory(inv *inventory.Inventory, node string) string {
_, cls, err := inv.FindNode(node)
if err != nil || cls == nil {
return ""
}
return cls.Checksum
}
func maybeAutoMount(device string) *mount.LoopMount {
if os.Getenv("METIS_AUTO_MOUNT") == "" {
return nil
}
// Use mount helper against the written device partitions.
m, err := mount.Setup(device)
if err != nil {
return nil
}
// Propagate mount paths for injection.
if m.BootPath != "" {
_ = os.Setenv("METIS_BOOT_PATH", m.BootPath)
}
if m.RootPath != "" {
_ = os.Setenv("METIS_ROOT_PATH", m.RootPath)
}
return m
}