Volt CLI: source-available under AGPSL v5.0

Complete infrastructure platform CLI:
- Container runtime (systemd-nspawn)
- VoltVisor VMs (Neutron Stardust / QEMU)
- Stellarium CAS (content-addressed storage)
- ORAS Registry
- GitOps integration
- Landlock LSM security
- Compose orchestration
- Mesh networking

Copyright (c) Armored Gates LLC. All rights reserved.
Licensed under AGPSL v5.0
This commit is contained in:
Karl Clinger
2026-03-21 00:30:23 -05:00
commit 0ebe75b2ca
155 changed files with 63317 additions and 0 deletions

View File

@@ -0,0 +1,347 @@
package proot
import (
"encoding/json"
"os"
"path/filepath"
"testing"
"github.com/armoredgate/volt/pkg/backend"
"gopkg.in/yaml.v3"
)
func TestName(t *testing.T) {
b := New()
if b.Name() != "proot" {
t.Errorf("expected name 'proot', got %q", b.Name())
}
}
func TestCapabilities(t *testing.T) {
b := New()
if b.SupportsVMs() {
t.Error("proot should not support VMs")
}
if b.SupportsServices() {
t.Error("proot should not support services")
}
if !b.SupportsNetworking() {
t.Error("proot should support basic networking")
}
if b.SupportsTuning() {
t.Error("proot should not support tuning")
}
}
func TestInit(t *testing.T) {
tmpDir := t.TempDir()
b := New()
if err := b.Init(tmpDir); err != nil {
t.Fatalf("Init failed: %v", err)
}
// Verify directory structure
for _, sub := range []string{"containers", "images", "tmp"} {
path := filepath.Join(tmpDir, sub)
info, err := os.Stat(path)
if err != nil {
t.Errorf("expected directory %s to exist: %v", sub, err)
continue
}
if !info.IsDir() {
t.Errorf("expected %s to be a directory", sub)
}
}
// Verify tmp has 0777 permissions
info, _ := os.Stat(filepath.Join(tmpDir, "tmp"))
if info.Mode().Perm() != 0777 {
t.Errorf("expected tmp perms 0777, got %o", info.Mode().Perm())
}
}
func TestCreateAndDelete(t *testing.T) {
tmpDir := t.TempDir()
b := New()
b.Init(tmpDir)
// Create a container
opts := backend.CreateOptions{
Name: "test-container",
Memory: "512M",
CPU: 1,
Env: []string{"FOO=bar"},
Ports: []backend.PortMapping{{HostPort: 8080, ContainerPort: 80, Protocol: "tcp"}},
}
if err := b.Create(opts); err != nil {
t.Fatalf("Create failed: %v", err)
}
// Verify container directory structure
cDir := filepath.Join(tmpDir, "containers", "test-container")
for _, sub := range []string{"rootfs", "logs"} {
path := filepath.Join(cDir, sub)
if _, err := os.Stat(path); err != nil {
t.Errorf("expected %s to exist: %v", sub, err)
}
}
// Verify state.json
stateData, err := os.ReadFile(filepath.Join(cDir, "state.json"))
if err != nil {
t.Fatalf("failed to read state.json: %v", err)
}
var state containerState
if err := json.Unmarshal(stateData, &state); err != nil {
t.Fatalf("failed to parse state.json: %v", err)
}
if state.Name != "test-container" {
t.Errorf("expected name 'test-container', got %q", state.Name)
}
if state.Status != "created" {
t.Errorf("expected status 'created', got %q", state.Status)
}
// Verify config.yaml
cfgData, err := os.ReadFile(filepath.Join(cDir, "config.yaml"))
if err != nil {
t.Fatalf("failed to read config.yaml: %v", err)
}
var cfg containerConfig
if err := yaml.Unmarshal(cfgData, &cfg); err != nil {
t.Fatalf("failed to parse config.yaml: %v", err)
}
if cfg.Memory != "512M" {
t.Errorf("expected memory '512M', got %q", cfg.Memory)
}
if len(cfg.Ports) != 1 || cfg.Ports[0].HostPort != 8080 {
t.Errorf("expected port mapping 8080:80, got %+v", cfg.Ports)
}
// Verify duplicate create fails
if err := b.Create(opts); err == nil {
t.Error("expected duplicate create to fail")
}
// List should return one container
containers, err := b.List()
if err != nil {
t.Fatalf("List failed: %v", err)
}
if len(containers) != 1 {
t.Errorf("expected 1 container, got %d", len(containers))
}
// Inspect should work
info, err := b.Inspect("test-container")
if err != nil {
t.Fatalf("Inspect failed: %v", err)
}
if info.Status != "created" {
t.Errorf("expected status 'created', got %q", info.Status)
}
// Delete should work
if err := b.Delete("test-container", false); err != nil {
t.Fatalf("Delete failed: %v", err)
}
// Verify directory removed
if _, err := os.Stat(cDir); !os.IsNotExist(err) {
t.Error("expected container directory to be removed")
}
// List should be empty now
containers, err = b.List()
if err != nil {
t.Fatalf("List failed: %v", err)
}
if len(containers) != 0 {
t.Errorf("expected 0 containers, got %d", len(containers))
}
}
func TestCopyOperations(t *testing.T) {
tmpDir := t.TempDir()
b := New()
b.Init(tmpDir)
// Create a container
opts := backend.CreateOptions{Name: "copy-test"}
if err := b.Create(opts); err != nil {
t.Fatalf("Create failed: %v", err)
}
// Create a source file on "host"
srcFile := filepath.Join(tmpDir, "host-file.txt")
os.WriteFile(srcFile, []byte("hello from host"), 0644)
// Copy to container
if err := b.CopyToContainer("copy-test", srcFile, "/etc/test.txt"); err != nil {
t.Fatalf("CopyToContainer failed: %v", err)
}
// Verify file exists in rootfs
containerFile := filepath.Join(tmpDir, "containers", "copy-test", "rootfs", "etc", "test.txt")
data, err := os.ReadFile(containerFile)
if err != nil {
t.Fatalf("file not found in container: %v", err)
}
if string(data) != "hello from host" {
t.Errorf("expected 'hello from host', got %q", string(data))
}
// Copy from container
dstFile := filepath.Join(tmpDir, "from-container.txt")
if err := b.CopyFromContainer("copy-test", "/etc/test.txt", dstFile); err != nil {
t.Fatalf("CopyFromContainer failed: %v", err)
}
data, err = os.ReadFile(dstFile)
if err != nil {
t.Fatalf("failed to read copied file: %v", err)
}
if string(data) != "hello from host" {
t.Errorf("expected 'hello from host', got %q", string(data))
}
}
func TestLogs(t *testing.T) {
tmpDir := t.TempDir()
b := New()
b.Init(tmpDir)
// Create a container
opts := backend.CreateOptions{Name: "log-test"}
b.Create(opts)
// Write some log lines
logDir := filepath.Join(tmpDir, "containers", "log-test", "logs")
logFile := filepath.Join(logDir, "current.log")
lines := "line1\nline2\nline3\nline4\nline5\n"
os.WriteFile(logFile, []byte(lines), 0644)
// Full logs
content, err := b.Logs("log-test", backend.LogOptions{})
if err != nil {
t.Fatalf("Logs failed: %v", err)
}
if content != lines {
t.Errorf("expected full log content, got %q", content)
}
// Tail 2 lines
content, err = b.Logs("log-test", backend.LogOptions{Tail: 2})
if err != nil {
t.Fatalf("Logs tail failed: %v", err)
}
// Last 2 lines of "line1\nline2\nline3\nline4\nline5\n" split gives 6 elements
// (last is empty after trailing \n), so tail 2 gives "line5\n"
if content == "" {
t.Error("expected some tail output")
}
// No logs available
content, err = b.Logs("nonexistent", backend.LogOptions{})
if err == nil {
// Container doesn't exist, should get error from readState
// but Logs reads file directly, so check
}
}
func TestAvailable(t *testing.T) {
b := New()
// Just verify it doesn't panic
_ = b.Available()
}
func TestProcessAlive(t *testing.T) {
// PID 1 (init) should be alive
if !processAlive(1) {
t.Error("expected PID 1 to be alive")
}
// PID 0 should not be alive
if processAlive(0) {
t.Error("expected PID 0 to not be alive")
}
// Very large PID should not be alive
if processAlive(999999999) {
t.Error("expected PID 999999999 to not be alive")
}
}
func TestDetectOS(t *testing.T) {
tmpDir := t.TempDir()
// No os-release file
result := detectOS(tmpDir)
if result != "-" {
t.Errorf("expected '-' for missing os-release, got %q", result)
}
// Create os-release
etcDir := filepath.Join(tmpDir, "etc")
os.MkdirAll(etcDir, 0755)
osRelease := `NAME="Ubuntu"
VERSION="24.04 LTS (Noble Numbat)"
ID=ubuntu
PRETTY_NAME="Ubuntu 24.04 LTS"
VERSION_ID="24.04"
`
os.WriteFile(filepath.Join(etcDir, "os-release"), []byte(osRelease), 0644)
result = detectOS(tmpDir)
if result != "Ubuntu 24.04 LTS" {
t.Errorf("expected 'Ubuntu 24.04 LTS', got %q", result)
}
}
func TestEntrypointDetection(t *testing.T) {
tmpDir := t.TempDir()
b := New()
cfg := &containerConfig{Name: "test"}
// Empty rootfs — should fallback to /bin/sh
ep, args := b.detectEntrypoint(tmpDir, cfg)
if ep != "/bin/sh" {
t.Errorf("expected /bin/sh fallback, got %q", ep)
}
if len(args) != 0 {
t.Errorf("expected no args for /bin/sh, got %v", args)
}
// Create /init
initPath := filepath.Join(tmpDir, "init")
os.WriteFile(initPath, []byte("#!/bin/sh\nexec /bin/sh"), 0755)
ep, _ = b.detectEntrypoint(tmpDir, cfg)
if ep != "/init" {
t.Errorf("expected /init, got %q", ep)
}
// Remove /init, create nginx
os.Remove(initPath)
nginxDir := filepath.Join(tmpDir, "usr", "sbin")
os.MkdirAll(nginxDir, 0755)
os.WriteFile(filepath.Join(nginxDir, "nginx"), []byte(""), 0755)
ep, args = b.detectEntrypoint(tmpDir, cfg)
if ep != "/usr/sbin/nginx" {
t.Errorf("expected /usr/sbin/nginx, got %q", ep)
}
// With port mapping, should use shell wrapper
cfg.Ports = []backend.PortMapping{{HostPort: 8080, ContainerPort: 80}}
ep, args = b.detectEntrypoint(tmpDir, cfg)
if ep != "/bin/sh" {
t.Errorf("expected /bin/sh wrapper for nginx with ports, got %q", ep)
}
if len(args) != 2 || args[0] != "-c" {
t.Errorf("expected [-c <shellcmd>] for nginx wrapper, got %v", args)
}
}