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 }