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
|
|
@ -179,7 +179,7 @@ func (d *Daemon) RegisterImage(ctx context.Context, params api.ImageRegisterPara
|
|||
}
|
||||
}
|
||||
}
|
||||
kernelPath, initrdPath, modulesDir, err := d.resolveKernelInputs(params.KernelRef, params.KernelPath, params.InitrdPath, params.ModulesDir)
|
||||
kernelPath, initrdPath, modulesDir, err := d.resolveKernelInputs(ctx, params.KernelRef, params.KernelPath, params.InitrdPath, params.ModulesDir)
|
||||
if err != nil {
|
||||
return model.Image{}, err
|
||||
}
|
||||
|
|
@ -374,7 +374,10 @@ func firstNonEmpty(values ...string) string {
|
|||
|
||||
// resolveKernelInputs canonicalises user-supplied kernel info: either direct
|
||||
// paths or a kernel-catalog ref. Shared by RegisterImage and PullImage.
|
||||
func (d *Daemon) resolveKernelInputs(kernelRef, kernelPath, initrdPath, modulesDir string) (string, string, string, error) {
|
||||
// When kernelRef is given but not yet pulled locally, an auto-pull from the
|
||||
// embedded kernelcat catalog fires so the caller doesn't have to manage
|
||||
// kernel/image ordering by hand.
|
||||
func (d *Daemon) resolveKernelInputs(ctx context.Context, kernelRef, kernelPath, initrdPath, modulesDir string) (string, string, string, error) {
|
||||
kernelRef = strings.TrimSpace(kernelRef)
|
||||
kernelPath = strings.TrimSpace(kernelPath)
|
||||
initrdPath = strings.TrimSpace(initrdPath)
|
||||
|
|
@ -384,12 +387,9 @@ func (d *Daemon) resolveKernelInputs(kernelRef, kernelPath, initrdPath, modulesD
|
|||
if kernelPath != "" || initrdPath != "" || modulesDir != "" {
|
||||
return "", "", "", fmt.Errorf("--kernel-ref is mutually exclusive with --kernel/--initrd/--modules")
|
||||
}
|
||||
entry, err := kernelcat.ReadLocal(d.layout.KernelsDir, kernelRef)
|
||||
entry, err := d.readOrAutoPullKernel(ctx, kernelRef)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return "", "", "", fmt.Errorf("kernel %q not found in catalog; run 'banger kernel list' to see available entries", kernelRef)
|
||||
}
|
||||
return "", "", "", fmt.Errorf("resolve kernel %q: %w", kernelRef, err)
|
||||
return "", "", "", err
|
||||
}
|
||||
return entry.KernelPath, entry.InitrdPath, entry.ModulesDir, nil
|
||||
}
|
||||
|
|
@ -399,3 +399,27 @@ func (d *Daemon) resolveKernelInputs(kernelRef, kernelPath, initrdPath, modulesD
|
|||
}
|
||||
return kernelPath, initrdPath, modulesDir, nil
|
||||
}
|
||||
|
||||
// readOrAutoPullKernel tries the local kernelcat first; on miss, checks
|
||||
// the embedded catalog and auto-pulls the bundle.
|
||||
func (d *Daemon) readOrAutoPullKernel(ctx context.Context, kernelRef string) (kernelcat.Entry, error) {
|
||||
entry, err := kernelcat.ReadLocal(d.layout.KernelsDir, kernelRef)
|
||||
if err == nil {
|
||||
return entry, nil
|
||||
}
|
||||
if !os.IsNotExist(err) {
|
||||
return kernelcat.Entry{}, fmt.Errorf("resolve kernel %q: %w", kernelRef, err)
|
||||
}
|
||||
catalog, loadErr := kernelcat.LoadEmbedded()
|
||||
if loadErr != nil {
|
||||
return kernelcat.Entry{}, fmt.Errorf("kernel %q not found locally: %w", kernelRef, loadErr)
|
||||
}
|
||||
if _, lookupErr := catalog.Lookup(kernelRef); lookupErr != nil {
|
||||
return kernelcat.Entry{}, fmt.Errorf("kernel %q not found in catalog; run 'banger kernel list --available' to browse", kernelRef)
|
||||
}
|
||||
vmCreateStage(ctx, "auto_pull_kernel", fmt.Sprintf("pulling kernel %s from catalog", kernelRef))
|
||||
if _, pullErr := d.KernelPull(ctx, api.KernelPullParams{Name: kernelRef}); pullErr != nil {
|
||||
return kernelcat.Entry{}, fmt.Errorf("auto-pull kernel %q: %w", kernelRef, pullErr)
|
||||
}
|
||||
return kernelcat.ReadLocal(d.layout.KernelsDir, kernelRef)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue