Phase 1: local kernel catalog scaffolding
Introduces a read/write kernel catalog on disk without any network dependency, so later phases (image register --kernel-ref, import, pull) can build on a working foundation. Layout: adds KernelsDir to paths.Layout, ensured under ~/.local/state/banger/kernels/. Each cataloged kernel lives at <KernelsDir>/<name>/ with a manifest.json alongside vmlinux and optional initrd.img / modules/. New internal/kernelcat package owns the disk format: - Entry (Name, Distro, Arch, KernelVersion, SHA256, Source, ImportedAt) - ValidateName (alphanumeric + dots/hyphens/underscores, no traversal) - ReadLocal / ListLocal / WriteLocal / DeleteLocal - SumFile helper The daemon exposes three RPC methods dispatched in daemon.go: kernel.list, kernel.show, kernel.delete. Implementations live in a new internal/daemon/kernels.go and are thin wrappers over kernelcat using d.layout.KernelsDir. CLI: new top-level `banger kernel` with list / show / rm subcommands mirroring the image-command pattern (ensureDaemon, RPC call, table or JSON output). No sudo required — kernel ops are user-space only. Users can now manually populate ~/.local/state/banger/kernels/<name>/ and see it via `banger kernel list`. Phase 2 wires --kernel-ref into image register; Phase 3 adds `banger kernel import`; Phase 4 adds remote pulls. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ca4865447c
commit
83cc3aee15
9 changed files with 691 additions and 3 deletions
67
internal/daemon/kernels.go
Normal file
67
internal/daemon/kernels.go
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"banger/internal/api"
|
||||
"banger/internal/kernelcat"
|
||||
)
|
||||
|
||||
func (d *Daemon) KernelList(_ context.Context) (api.KernelListResult, error) {
|
||||
entries, err := kernelcat.ListLocal(d.layout.KernelsDir)
|
||||
if err != nil {
|
||||
return api.KernelListResult{}, err
|
||||
}
|
||||
result := api.KernelListResult{Entries: make([]api.KernelEntry, 0, len(entries))}
|
||||
for _, entry := range entries {
|
||||
result.Entries = append(result.Entries, kernelEntryToAPI(entry))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (d *Daemon) KernelShow(_ context.Context, name string) (api.KernelEntry, error) {
|
||||
entry, err := kernelcat.ReadLocal(d.layout.KernelsDir, name)
|
||||
if err != nil {
|
||||
return api.KernelEntry{}, kernelNotFoundIfMissing(name, err)
|
||||
}
|
||||
return kernelEntryToAPI(entry), nil
|
||||
}
|
||||
|
||||
func (d *Daemon) KernelDelete(_ context.Context, name string) error {
|
||||
if err := kernelcat.ValidateName(name); err != nil {
|
||||
return err
|
||||
}
|
||||
return kernelcat.DeleteLocal(d.layout.KernelsDir, name)
|
||||
}
|
||||
|
||||
func kernelEntryToAPI(entry kernelcat.Entry) api.KernelEntry {
|
||||
importedAt := ""
|
||||
if !entry.ImportedAt.IsZero() {
|
||||
importedAt = entry.ImportedAt.UTC().Format(time.RFC3339)
|
||||
}
|
||||
return api.KernelEntry{
|
||||
Name: entry.Name,
|
||||
Distro: entry.Distro,
|
||||
Arch: entry.Arch,
|
||||
KernelVersion: entry.KernelVersion,
|
||||
SHA256: entry.SHA256,
|
||||
Source: entry.Source,
|
||||
ImportedAt: importedAt,
|
||||
KernelPath: entry.KernelPath,
|
||||
InitrdPath: entry.InitrdPath,
|
||||
ModulesDir: entry.ModulesDir,
|
||||
}
|
||||
}
|
||||
|
||||
func kernelNotFoundIfMissing(name string, err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
return fmt.Errorf("kernel %q not found", name)
|
||||
}
|
||||
return err
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue