metis/pkg/plan/burn.go

48 lines
1.3 KiB
Go

package plan
import (
"fmt"
"os/exec"
"path/filepath"
"metis/pkg/image"
"metis/pkg/inventory"
)
// 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, filepath.Base(p.Image))
if err := image.Download(p.Image, cacheImage); err != nil {
return p, fmt.Errorf("download image: %w", err)
}
if err := image.VerifyChecksum(cacheImage, checksumFromInventory(inv, nodeName)); err != nil {
return p, err
}
if !confirm {
return p, nil
}
if device == "" || device == "/dev/sdX" {
return p, fmt.Errorf("refusing to write to placeholder device")
}
ddCmd := []string{"dd", fmt.Sprintf("if=%s", cacheImage), fmt.Sprintf("of=%s", device), "bs=4M", "status=progress", "conv=fsync"}
cmd := exec.Command(ddCmd[0], ddCmd[1:]...)
cmd.Stdout = nil
cmd.Stderr = nil
if err := cmd.Run(); err != nil {
return p, fmt.Errorf("dd failed: %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
}