Phase 2: daemon PullImage orchestration
(d *Daemon).PullImage downloads an OCI image, flattens it into an
ext4 rootfs, and registers the result as a managed banger image.
Flow (internal/daemon/images_pull.go):
1. Parse + validate the OCI ref via go-containerregistry/name.
2. Derive a friendly default name from the ref ("debian-bookworm")
when --name is omitted.
3. Reject if an image with that name already exists.
4. Resolve kernel info via the new shared resolveKernelInputs
helper (refactored out of RegisterImage); ValidateKernelPaths
checks the kernel triple alone.
5. Acquire imageOpsMu, generate a fresh image id, and stage at
<ImagesDir>/<id>.staging.
6. imagepull.Pull → cache layers under OCICacheDir;
imagepull.Flatten → temp rootfs tree under os.TempDir (so the
state filesystem doesn't temporarily double in size).
7. Default size: max(treeSize × 1.25, 1 GiB); --size override
accepted.
8. imagepull.BuildExt4 produces the rootfs.ext4 in the staging dir.
9. imagemgr.StageBootArtifacts stages the kernel/initrd/modules
into the same dir (reused unchanged).
10. Atomic os.Rename(staging, finalDir) publishes the artifact dir.
11. Persist model.Image with Managed=true. Failure at any step
removes the staging dir; failure post-rename removes finalDir.
The pullAndFlatten field on Daemon is the test seam: tests stub it
to write a fixture tree into destDir and skip the real registry.
Refactor: extracted the "kernel-ref vs direct paths" resolution
out of RegisterImage into d.resolveKernelInputs so PullImage and
RegisterImage share one source of truth for that policy. Split
ValidateRegisterPaths into a kernel-only ValidateKernelPaths so
PullImage (which produces the rootfs itself) can validate just
the kernel triple without the rootfs check.
API: ImagePullParams { Ref, Name, KernelPath, InitrdPath,
ModulesDir, KernelRef, SizeBytes }. RPC dispatch case image.pull
mirrors image.register.
Tests cover: happy-path producing a managed image with all four
artifacts present + staging cleaned up, name-collision rejection,
missing-kernel rejection, and staging cleanup on a failed pull.
defaultImageNameFromRef handles tag/digest/no-suffix cases.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
78376ba6ec
commit
a8c9983542
6 changed files with 467 additions and 25 deletions
|
|
@ -179,29 +179,9 @@ func (d *Daemon) RegisterImage(ctx context.Context, params api.ImageRegisterPara
|
|||
}
|
||||
}
|
||||
}
|
||||
kernelPath := strings.TrimSpace(params.KernelPath)
|
||||
initrdPath := strings.TrimSpace(params.InitrdPath)
|
||||
modulesDir := strings.TrimSpace(params.ModulesDir)
|
||||
kernelRef := strings.TrimSpace(params.KernelRef)
|
||||
|
||||
if kernelRef != "" {
|
||||
if kernelPath != "" || initrdPath != "" || modulesDir != "" {
|
||||
return model.Image{}, fmt.Errorf("--kernel-ref is mutually exclusive with --kernel/--initrd/--modules")
|
||||
}
|
||||
entry, err := kernelcat.ReadLocal(d.layout.KernelsDir, kernelRef)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return model.Image{}, fmt.Errorf("kernel %q not found in catalog; run 'banger kernel list' to see available entries", kernelRef)
|
||||
}
|
||||
return model.Image{}, fmt.Errorf("resolve kernel %q: %w", kernelRef, err)
|
||||
}
|
||||
kernelPath = entry.KernelPath
|
||||
initrdPath = entry.InitrdPath
|
||||
modulesDir = entry.ModulesDir
|
||||
}
|
||||
|
||||
if kernelPath == "" {
|
||||
return model.Image{}, fmt.Errorf("kernel path is required (pass --kernel <path> or --kernel-ref <name>)")
|
||||
kernelPath, initrdPath, modulesDir, err := d.resolveKernelInputs(params.KernelRef, params.KernelPath, params.InitrdPath, params.ModulesDir)
|
||||
if err != nil {
|
||||
return model.Image{}, err
|
||||
}
|
||||
|
||||
if err := imagemgr.ValidateRegisterPaths(rootfsPath, workSeedPath, kernelPath, initrdPath, modulesDir); err != nil {
|
||||
|
|
@ -391,3 +371,31 @@ func firstNonEmpty(values ...string) string {
|
|||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// 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) {
|
||||
kernelRef = strings.TrimSpace(kernelRef)
|
||||
kernelPath = strings.TrimSpace(kernelPath)
|
||||
initrdPath = strings.TrimSpace(initrdPath)
|
||||
modulesDir = strings.TrimSpace(modulesDir)
|
||||
|
||||
if kernelRef != "" {
|
||||
if kernelPath != "" || initrdPath != "" || modulesDir != "" {
|
||||
return "", "", "", fmt.Errorf("--kernel-ref is mutually exclusive with --kernel/--initrd/--modules")
|
||||
}
|
||||
entry, err := kernelcat.ReadLocal(d.layout.KernelsDir, 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 entry.KernelPath, entry.InitrdPath, entry.ModulesDir, nil
|
||||
}
|
||||
|
||||
if kernelPath == "" {
|
||||
return "", "", "", fmt.Errorf("kernel path is required (pass --kernel <path> or --kernel-ref <name>)")
|
||||
}
|
||||
return kernelPath, initrdPath, modulesDir, nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue