Reduce the control plane's dependency on helper scripts while keeping the hard Linux integration points in the approved shell-out layer. Replace the bash-driven image build path with a native Go builder that clones and optionally resizes the rootfs, boots a temporary Firecracker VM, provisions the guest over SSH, installs packages and modules, and preserves the package-manifest sidecar. Also replace a few small convenience shell-outs with Go helpers: read process stats from /proc, use os.Truncate for ext4 image growth, add file-clone and normalized-line helpers, drop the sh -c work-disk flattening path, and launch Firecracker via a direct sudo command. Add tests for the new SSH/archive and system helpers, plus a policy test that keeps os/exec imports confined to cli/firecracker/system. Update the docs to describe customize.sh as a manual helper rather than the daemon's image-build backend. Validated with go mod tidy, go test ./..., and make build.
58 lines
1.4 KiB
Go
58 lines
1.4 KiB
Go
package guest
|
|
|
|
import (
|
|
"archive/tar"
|
|
"bytes"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func TestWriteTarArchiveKeepsTopLevelDirectory(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
sourceDir := filepath.Join(t.TempDir(), "6.8.0-test")
|
|
if err := os.MkdirAll(filepath.Join(sourceDir, "kernel"), 0o755); err != nil {
|
|
t.Fatalf("MkdirAll: %v", err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(sourceDir, "modules.dep"), []byte("deps"), 0o644); err != nil {
|
|
t.Fatalf("WriteFile modules.dep: %v", err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(sourceDir, "kernel", "module.ko"), []byte("ko"), 0o644); err != nil {
|
|
t.Fatalf("WriteFile module.ko: %v", err)
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
if err := writeTarArchive(&buf, sourceDir); err != nil {
|
|
t.Fatalf("writeTarArchive: %v", err)
|
|
}
|
|
|
|
tr := tar.NewReader(bytes.NewReader(buf.Bytes()))
|
|
var names []string
|
|
for {
|
|
header, err := tr.Next()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("tar.Next: %v", err)
|
|
}
|
|
names = append(names, header.Name)
|
|
}
|
|
|
|
want := map[string]struct{}{
|
|
"6.8.0-test": {},
|
|
"6.8.0-test/modules.dep": {},
|
|
"6.8.0-test/kernel": {},
|
|
"6.8.0-test/kernel/module.ko": {},
|
|
}
|
|
if len(names) != len(want) {
|
|
t.Fatalf("archive names = %v, want %d entries", names, len(want))
|
|
}
|
|
for _, name := range names {
|
|
if _, ok := want[name]; !ok {
|
|
t.Fatalf("unexpected archive entry %q in %v", name, names)
|
|
}
|
|
}
|
|
}
|