Extract imagemgr subpackage with pure image helpers
Moves the stateless helpers of the image subsystem into internal/daemon/imagemgr: paths.go — path validators (ValidateRegisterPaths, ValidatePromotePaths), artifact staging (StageBootArtifacts, StageOptionalArtifactPath), metadata (BuildMetadataPackages, WritePackagesMetadata). build.go — ResizeRootfs, WriteBuildLog, and the full guest provisioning script generator (BuildProvisionScript, BuildModulesCommand and all private script-append helpers) along with the mise/tmux/opencode version constants. The orchestrator methods (BuildImage, RegisterImage, PromoteImage, DeleteImage, runImageBuildNative) stay on *Daemon: they still touch d.store, d.imageOpsMu, d.beginOperation, capability hooks, and fcproc-wrapped Daemon helpers — extracting them needs prerequisite phases (operation protocol, workdisk helpers, tap pool). This commit is strictly the pure-helper extraction that can land cleanly today. imagebuild.go shrinks from 453 -> 225 LOC (half gone). images.go shrinks from 450 -> 374 LOC. imagebuild_test.go updated to call the exported imagemgr.BuildProvisionScript. Zero behavior change; all tests green. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
6e989914dd
commit
c13c8b11af
5 changed files with 380 additions and 326 deletions
|
|
@ -10,6 +10,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"banger/internal/api"
|
||||
"banger/internal/daemon/imagemgr"
|
||||
"banger/internal/imagepreset"
|
||||
"banger/internal/model"
|
||||
"banger/internal/system"
|
||||
|
|
@ -80,12 +81,12 @@ func (d *Daemon) BuildImage(ctx context.Context, params api.ImageBuildParams) (i
|
|||
if err := d.validateImageBuildPrereqs(ctx, baseImage.RootfsPath, kernelSource, initrdSource, modulesSource, params.Size); err != nil {
|
||||
return model.Image{}, err
|
||||
}
|
||||
kernelPath, initrdPath, modulesDir, err := stageManagedBootArtifacts(ctx, d.runner, stageDir, kernelSource, initrdSource, modulesSource)
|
||||
kernelPath, initrdPath, modulesDir, err := imagemgr.StageBootArtifacts(ctx, d.runner, stageDir, kernelSource, initrdSource, modulesSource)
|
||||
if err != nil {
|
||||
return model.Image{}, err
|
||||
}
|
||||
packages := imagepreset.DebianBasePackages()
|
||||
metadataPackages := imageBuildMetadataPackages(params.Docker)
|
||||
metadataPackages := imagemgr.BuildMetadataPackages(params.Docker)
|
||||
spec := imageBuildSpec{
|
||||
ID: id,
|
||||
Name: name,
|
||||
|
|
@ -117,7 +118,7 @@ func (d *Daemon) BuildImage(ctx context.Context, params api.ImageBuildParams) (i
|
|||
return model.Image{}, err
|
||||
}
|
||||
imageBuildStage(ctx, "write_metadata", "writing image metadata")
|
||||
if err := writePackagesMetadata(rootfsPath, metadataPackages); err != nil {
|
||||
if err := imagemgr.WritePackagesMetadata(rootfsPath, metadataPackages); err != nil {
|
||||
_ = logFile.Sync()
|
||||
return model.Image{}, err
|
||||
}
|
||||
|
|
@ -134,8 +135,8 @@ func (d *Daemon) BuildImage(ctx context.Context, params api.ImageBuildParams) (i
|
|||
RootfsPath: filepath.Join(artifactDir, "rootfs.ext4"),
|
||||
WorkSeedPath: filepath.Join(artifactDir, "work-seed.ext4"),
|
||||
KernelPath: filepath.Join(artifactDir, "kernel"),
|
||||
InitrdPath: stageOptionalArtifactPath(artifactDir, initrdPath, "initrd.img"),
|
||||
ModulesDir: stageOptionalArtifactPath(artifactDir, modulesDir, "modules"),
|
||||
InitrdPath: imagemgr.StageOptionalArtifactPath(artifactDir, initrdPath, "initrd.img"),
|
||||
ModulesDir: imagemgr.StageOptionalArtifactPath(artifactDir, modulesDir, "modules"),
|
||||
BuildSize: params.Size,
|
||||
SeededSSHPublicKeyFingerprint: seededSSHPublicKeyFingerprint,
|
||||
Docker: params.Docker,
|
||||
|
|
@ -184,7 +185,7 @@ func (d *Daemon) RegisterImage(ctx context.Context, params api.ImageRegisterPara
|
|||
initrdPath := strings.TrimSpace(params.InitrdPath)
|
||||
modulesDir := strings.TrimSpace(params.ModulesDir)
|
||||
|
||||
if err := validateImageRegisterPaths(rootfsPath, workSeedPath, kernelPath, initrdPath, modulesDir); err != nil {
|
||||
if err := imagemgr.ValidateRegisterPaths(rootfsPath, workSeedPath, kernelPath, initrdPath, modulesDir); err != nil {
|
||||
return model.Image{}, err
|
||||
}
|
||||
|
||||
|
|
@ -251,7 +252,7 @@ func (d *Daemon) PromoteImage(ctx context.Context, idOrName string) (image model
|
|||
if image.Managed {
|
||||
return model.Image{}, fmt.Errorf("image %s is already managed", image.Name)
|
||||
}
|
||||
if err := validateImagePromotePaths(image.RootfsPath, image.KernelPath, image.InitrdPath, image.ModulesDir); err != nil {
|
||||
if err := imagemgr.ValidatePromotePaths(image.RootfsPath, image.KernelPath, image.InitrdPath, image.ModulesDir); err != nil {
|
||||
return model.Image{}, err
|
||||
}
|
||||
if strings.TrimSpace(d.layout.ImagesDir) == "" {
|
||||
|
|
@ -309,7 +310,7 @@ func (d *Daemon) PromoteImage(ctx context.Context, idOrName string) (image model
|
|||
} else {
|
||||
image.SeededSSHPublicKeyFingerprint = ""
|
||||
}
|
||||
_, initrdPath, modulesDir, err := stageManagedBootArtifacts(ctx, d.runner, stageDir, image.KernelPath, image.InitrdPath, image.ModulesDir)
|
||||
_, initrdPath, modulesDir, err := imagemgr.StageBootArtifacts(ctx, d.runner, stageDir, image.KernelPath, image.InitrdPath, image.ModulesDir)
|
||||
if err != nil {
|
||||
return model.Image{}, err
|
||||
}
|
||||
|
|
@ -327,8 +328,8 @@ func (d *Daemon) PromoteImage(ctx context.Context, idOrName string) (image model
|
|||
image.WorkSeedPath = filepath.Join(artifactDir, "work-seed.ext4")
|
||||
}
|
||||
image.KernelPath = filepath.Join(artifactDir, "kernel")
|
||||
image.InitrdPath = stageOptionalArtifactPath(artifactDir, initrdPath, "initrd.img")
|
||||
image.ModulesDir = stageOptionalArtifactPath(artifactDir, modulesDir, "modules")
|
||||
image.InitrdPath = imagemgr.StageOptionalArtifactPath(artifactDir, initrdPath, "initrd.img")
|
||||
image.ModulesDir = imagemgr.StageOptionalArtifactPath(artifactDir, modulesDir, "modules")
|
||||
image.UpdatedAt = model.Now()
|
||||
if err := d.store.UpsertImage(ctx, image); err != nil {
|
||||
_ = os.RemoveAll(artifactDir)
|
||||
|
|
@ -337,43 +338,6 @@ func (d *Daemon) PromoteImage(ctx context.Context, idOrName string) (image model
|
|||
return image, nil
|
||||
}
|
||||
|
||||
func validateImageRegisterPaths(rootfsPath, workSeedPath, kernelPath, initrdPath, modulesDir string) error {
|
||||
checks := system.NewPreflight()
|
||||
checks.RequireFile(rootfsPath, "rootfs image", `pass --rootfs <path>`)
|
||||
checks.RequireFile(kernelPath, "kernel image", `pass --kernel <path>`)
|
||||
if workSeedPath != "" {
|
||||
checks.RequireFile(workSeedPath, "work-seed image", `pass --work-seed <path> or rebuild the image with a work seed`)
|
||||
}
|
||||
if initrdPath != "" {
|
||||
checks.RequireFile(initrdPath, "initrd image", `pass --initrd <path>`)
|
||||
}
|
||||
if modulesDir != "" {
|
||||
checks.RequireDir(modulesDir, "kernel modules dir", `pass --modules <dir>`)
|
||||
}
|
||||
return checks.Err("image register failed")
|
||||
}
|
||||
|
||||
func validateImagePromotePaths(rootfsPath, kernelPath, initrdPath, modulesDir string) error {
|
||||
checks := system.NewPreflight()
|
||||
checks.RequireFile(rootfsPath, "rootfs image", `re-register the image with a valid rootfs`)
|
||||
checks.RequireFile(kernelPath, "kernel image", `re-register the image with a valid kernel`)
|
||||
if initrdPath != "" {
|
||||
checks.RequireFile(initrdPath, "initrd image", `re-register the image with a valid initrd`)
|
||||
}
|
||||
if modulesDir != "" {
|
||||
checks.RequireDir(modulesDir, "kernel modules dir", `re-register the image with a valid modules dir`)
|
||||
}
|
||||
return checks.Err("image promote failed")
|
||||
}
|
||||
|
||||
func writePackagesMetadata(rootfsPath string, packages []string) error {
|
||||
if rootfsPath == "" || len(packages) == 0 {
|
||||
return nil
|
||||
}
|
||||
metadataPath := rootfsPath + ".packages.sha256"
|
||||
return os.WriteFile(metadataPath, []byte(packagesHash(packages)+"\n"), 0o644)
|
||||
}
|
||||
|
||||
func (d *Daemon) DeleteImage(ctx context.Context, idOrName string) (model.Image, error) {
|
||||
d.imageOpsMu.Lock()
|
||||
defer d.imageOpsMu.Unlock()
|
||||
|
|
@ -400,46 +364,6 @@ func (d *Daemon) DeleteImage(ctx context.Context, idOrName string) (model.Image,
|
|||
return image, nil
|
||||
}
|
||||
|
||||
func stageManagedBootArtifacts(ctx context.Context, runner system.CommandRunner, artifactDir, kernelSource, initrdSource, modulesSource string) (string, string, string, error) {
|
||||
kernelPath := filepath.Join(artifactDir, "kernel")
|
||||
if err := system.CopyFilePreferClone(kernelSource, kernelPath); err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
initrdPath := ""
|
||||
if strings.TrimSpace(initrdSource) != "" {
|
||||
initrdPath = filepath.Join(artifactDir, "initrd.img")
|
||||
if err := system.CopyFilePreferClone(initrdSource, initrdPath); err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
}
|
||||
modulesDir := ""
|
||||
if strings.TrimSpace(modulesSource) != "" {
|
||||
modulesDir = filepath.Join(artifactDir, "modules")
|
||||
if err := os.MkdirAll(modulesDir, 0o755); err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
if err := system.CopyDirContents(ctx, runner, modulesSource, modulesDir, false); err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
}
|
||||
return kernelPath, initrdPath, modulesDir, nil
|
||||
}
|
||||
|
||||
func imageBuildMetadataPackages(docker bool) []string {
|
||||
packages := imagepreset.DebianBasePackages()
|
||||
if docker {
|
||||
packages = append(packages, "#feature:docker")
|
||||
}
|
||||
return packages
|
||||
}
|
||||
|
||||
func stageOptionalArtifactPath(artifactDir, stagedPath, name string) string {
|
||||
if strings.TrimSpace(stagedPath) == "" {
|
||||
return ""
|
||||
}
|
||||
return filepath.Join(artifactDir, name)
|
||||
}
|
||||
|
||||
func firstNonEmpty(values ...string) string {
|
||||
for _, value := range values {
|
||||
if strings.TrimSpace(value) != "" {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue