48 lines
1.3 KiB
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
|
|
}
|