vm create: auto-pull image and kernel from catalogs if missing
One-command sandbox: `banger vm run` on a fresh host now Just Works. No prior `banger image pull` or `banger kernel pull` needed. Changes: - Default `default_image_name` flips from "default" to "debian-bookworm" so the golden image is the implicit target when `--image` is omitted. - `CreateVM` resolves the image via a new `findOrAutoPullImage`: try the local store first, and on miss fall back to the embedded imagecat catalog + auto-pull. Emits a vm-create progress stage so the user sees "pulling from image catalog" in the create output. - `resolveKernelInputs` gains context + the same pattern via `readOrAutoPullKernel`: try the local kernelcat, and on miss look up the embedded kernelcat and auto-pull. Fires whenever a bundle's manifest references a kernel the user hasn't pulled yet, not just during image pull — any CreateVM with an image that needs a kernel not yet local will resolve it. - `--image` help text updated on both `vm run` and `vm create`. Six tests cover local-hit-no-pull, auto-pull-on-miss, not-in-catalog error propagation, and a non-ENOENT kernel read error does NOT trigger a misleading "not in catalog" claim. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
81a27d6648
commit
e0894376ea
7 changed files with 202 additions and 15 deletions
|
|
@ -8,6 +8,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"banger/internal/api"
|
||||
"banger/internal/imagecat"
|
||||
"banger/internal/model"
|
||||
"banger/internal/vmdns"
|
||||
)
|
||||
|
|
@ -35,7 +36,7 @@ func (d *Daemon) CreateVM(ctx context.Context, params api.VMCreateParams) (vm mo
|
|||
imageName = d.config.DefaultImageName
|
||||
}
|
||||
vmCreateStage(ctx, "resolve_image", "resolving image")
|
||||
image, err := d.FindImage(ctx, imageName)
|
||||
image, err := d.findOrAutoPullImage(ctx, imageName)
|
||||
if err != nil {
|
||||
return model.VMRecord{}, err
|
||||
}
|
||||
|
|
@ -129,3 +130,29 @@ func (d *Daemon) CreateVM(ctx context.Context, params api.VMCreateParams) (vm mo
|
|||
}
|
||||
return d.startVMLocked(ctx, vm, image)
|
||||
}
|
||||
|
||||
// findOrAutoPullImage tries the local image store first; if the name
|
||||
// isn't registered but matches an entry in the embedded imagecat
|
||||
// catalog, it auto-pulls the bundle so `vm create --image foo` (and
|
||||
// therefore `vm run`) works on a fresh host without the user having
|
||||
// to run `image pull` first.
|
||||
func (d *Daemon) findOrAutoPullImage(ctx context.Context, idOrName string) (model.Image, error) {
|
||||
image, err := d.FindImage(ctx, idOrName)
|
||||
if err == nil {
|
||||
return image, nil
|
||||
}
|
||||
catalog, loadErr := imagecat.LoadEmbedded()
|
||||
if loadErr != nil {
|
||||
return model.Image{}, err
|
||||
}
|
||||
entry, lookupErr := catalog.Lookup(idOrName)
|
||||
if lookupErr != nil {
|
||||
// Not in the catalog either — surface the original not-found.
|
||||
return model.Image{}, err
|
||||
}
|
||||
vmCreateStage(ctx, "auto_pull_image", fmt.Sprintf("pulling %s from image catalog", entry.Name))
|
||||
if _, pullErr := d.PullImage(ctx, api.ImagePullParams{Ref: entry.Name}); pullErr != nil {
|
||||
return model.Image{}, fmt.Errorf("auto-pull image %q: %w", entry.Name, pullErr)
|
||||
}
|
||||
return d.FindImage(ctx, idOrName)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue