Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
bcbde1a
fix(resources): use conservative 4GB default instead of 256GB
aledbf Dec 30, 2025
99bc051
fix(network): correct defer order for netns handles
aledbf Dec 30, 2025
05d4a16
fix(shim): correct defer order for mount namespace handle
aledbf Dec 30, 2025
07706c9
fix(qemu): replace panic with error return in buildQemuCommandLine
aledbf Dec 30, 2025
1769135
fix(vminit): handle error instead of discarding in Process() call
aledbf Dec 30, 2025
1a05fbe
fix(memhotplug): elevate re-online failure log from Warn to Error
aledbf Dec 30, 2025
37f8290
fix(mounts): return actual error instead of ErrNotImplemented
aledbf Dec 30, 2025
d304464
fix(vminit): add cleanup for container when post-create steps fail
aledbf Dec 30, 2025
aa49c1e
refactor(qemu): centralize TAP file descriptor cleanup
aledbf Dec 30, 2025
78169e6
fix(memhotplug): treat memory online failure as error, not warning
aledbf Dec 30, 2025
acda43a
fix(network): fail CNI parsing when no IP addresses allocated
aledbf Dec 30, 2025
0c2e71b
fix(network): cleanup netns file on catastrophic restore failure
aledbf Dec 30, 2025
b8e580f
refactor(shim): use defer pattern for network cleanup in Create()
aledbf Dec 30, 2025
0121b6a
fix(cpuhotplug): validate all config durations before use
aledbf Dec 30, 2025
3528c18
fix(cpuhotplug): make scaleDown return error consistently
aledbf Dec 30, 2025
d2a88c6
fix(shim): use typed error checking instead of string matching
aledbf Dec 30, 2025
2ae4bd3
fix(lifecycle): use syscall errors instead of string matching for vsock
aledbf Dec 30, 2025
9d25d3d
refactor(qmp): make execute() return response for future use
aledbf Dec 30, 2025
20d8496
Handle netns cleanup errors instead of ignoring
aledbf Dec 30, 2025
d23c350
Reduce repetitive cleanup code with helper function
aledbf Dec 30, 2025
443ce6a
Update outdated comment about CPU target calculation
aledbf Dec 30, 2025
a6896c9
Correct contradictory comment about EnableScaleDown default
aledbf Dec 30, 2025
91af200
Elevate ctrl-alt-del config failure to error level
aledbf Dec 30, 2025
a6017d4
Avoid misleading success logs after teardown failures
aledbf Dec 30, 2025
bb15ca9
Add warnings for time anomalies in CPU sampling
aledbf Dec 30, 2025
e6361ee
Correct typo in tmpfs mount source string
aledbf Dec 30, 2025
7ef707c
Use 'any' instead of 'interface{}' for Go 1.18+ consistency
aledbf Dec 30, 2025
ee5f616
Add comment explaining blank import side effect
aledbf Dec 30, 2025
bdf7774
Replace interface{} with 'any' in QMP code
aledbf Dec 30, 2025
9ac7e07
Remove unnecessary syscall wrappers
aledbf Dec 30, 2025
a2fb2e7
Add container context to generic error messages
aledbf Dec 30, 2025
a663edc
Extract repeated client close pattern to helper function
aledbf Dec 30, 2025
319a46c
Replace magic numbers with named constants
aledbf Dec 30, 2025
22bc242
Assert on error message content instead of just logging
aledbf Dec 30, 2025
59b1a01
Fix formatting: Align struct field definitions for consistency
aledbf Dec 30, 2025
b41f0dc
Replace magic number with named constant for memory slots
aledbf Dec 30, 2025
fb2224f
Replace GOMAXPROCS magic number with named constant
aledbf Dec 30, 2025
5c33a02
Replace hard-coded retry sleep with named constant
aledbf Dec 30, 2025
5f82ef6
Extract repeated tag truncation logic into helper function
aledbf Dec 30, 2025
719016f
Replace dead virtiofs option translation code with stub
aledbf Dec 30, 2025
f28e52f
Replace hard-coded reconnect deadline with named constant
aledbf Dec 30, 2025
a75215d
Replace magic numbers in DefaultConfig with named constants
aledbf Dec 30, 2025
2068a5d
Deduplicate maxSlots magic number into package-level constant
aledbf Dec 30, 2025
e1fd993
Add validation to alignMemory for invalid alignment values
aledbf Dec 30, 2025
9f14d71
Add field documentation to proto message definitions
aledbf Dec 30, 2025
5e945ec
Add service-level and RPC documentation to proto services
aledbf Dec 30, 2025
278724a
Replace test file creation with unix.Access for write permission check
aledbf Dec 30, 2025
186f615
Fix race condition in CPU hotplug controller Start() method
aledbf Dec 30, 2025
80ab436
Add double-start protection to memory hotplug controller
aledbf Dec 30, 2025
a155f32
Log silently swallowed config errors in paths package
aledbf Dec 30, 2025
c345fdd
Remove misleading comment with redundant error discard
aledbf Dec 30, 2025
03e578f
Make isVethConflictError case-insensitive as documented
aledbf Dec 30, 2025
7dc75e9
Make CPU scaleDown error handling consistent with scaleUp
aledbf Dec 30, 2025
ae3e4a9
Extract duplicate closed-check pattern into helper method
aledbf Dec 30, 2025
cd4a218
Add test for config.Get() singleton behavior
aledbf Dec 30, 2025
2bd3cd3
Document API versioning strategy
aledbf Dec 30, 2025
c650108
Return errors instead of nil when VM is not available
aledbf Dec 30, 2025
004a7f5
Fix integration tests and linter issues after I-002 interface changes
aledbf Dec 31, 2025
c07f9e4
Remove side effects from validation function
aledbf Dec 31, 2025
179621d
Simplify LoadNetworkConfig fallback logic and add default for partial…
aledbf Dec 31, 2025
4a4fa19
Extract file scheme handling from setupForwardIO
aledbf Dec 31, 2025
4362f48
Extract duplicate config parsing logic into generic helper
aledbf Dec 31, 2025
72db9c0
Eliminate TOCTOU race in CreateTask using atomic creation flag
aledbf Dec 31, 2025
99e1084
Extract mock process into shared test helper
aledbf Dec 31, 2025
7d884a3
Lint
aledbf Dec 31, 2025
e17b673
Release mutex before closing network connection
aledbf Dec 31, 2025
f57e9eb
Make console FIFO goroutine cancellable
aledbf Dec 31, 2025
80c94b2
Implement proper CPU cpuset parsing
aledbf Dec 31, 2025
55fc6d9
Extract shared network types to common file
aledbf Dec 31, 2025
e70a5a2
Add comprehensive table-driven tests for config validation
aledbf Dec 31, 2025
762ec82
Document pivot root security implications
aledbf Dec 31, 2025
4ae71f4
Add ResetForTesting helper to improve config testability
aledbf Dec 31, 2025
385f94e
Decouple paths package from config singleton
aledbf Dec 31, 2025
0006b38
Add comprehensive resource cleanup verification tests
aledbf Dec 31, 2025
843ee67
Implement QEMU command builder pattern
aledbf Dec 31, 2025
cfe1239
Extract Shutdown responsibilities into helper methods
aledbf Dec 31, 2025
52a2a9f
Split vminitd/main.go into focused packages
aledbf Dec 31, 2025
3453a85
Split guest vminit task service.go into focused modules
aledbf Dec 31, 2025
df5e581
Split QEMU instance.go into focused modules
aledbf Dec 31, 2025
a431b11
Lint
aledbf Dec 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 5 additions & 21 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -1,27 +1,11 @@
{
"permissions": {
"allow": [
"Bash(grep:*)",
"Bash(git mv:*)",
"Bash(find:*)",
"Bash(task proto:*)",
"Bash(task protos:*)",
"Bash(go mod tidy:*)",
"Bash(task build:shim)",
"Bash(go test:*)",
"Bash(GOOS=linux go test:*)",
"Bash(go build:*)",
"Bash(go tool cover:*)",
"Bash(gofmt:*)",
"Bash(golangci-lint run:*)",
"Bash(task lint:*)",
"Bash(GOOS=linux go build:*)",
"Bash(tree:*)",
"Bash(wc:*)",
"Bash(go doc:*)",
"Bash(go list:*)",
"Bash(GOOS=linux go vet:*)",
"Bash(GOOS=linux task lint:*)"
"Bash(*:*)",
"Bash(ls:*)",
"Bash(git add:*)",
"Bash(git commit:*)",
"Bash(payload\" don''t indicate which container failed or which operation,\nmaking troubleshooting difficult.\n\nAdded container ID to all error messages in getCPUStats\\(\\) and\ngetMemoryStats\\(\\) to provide better context for operators:\n- \"missing stats payload\" -> \"container X: missing CPU/memory stats payload\"\n- \"missing CPU/memory stats\" -> \"container X: missing CPU/memory stats in metrics\"\n- Also improved unmarshal error to include context\n\nChanges:\n- internal/shim/resources/vmclient.go: Add containerID to error messages\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")"
]
}
}
104 changes: 104 additions & 0 deletions api/VERSIONING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# API Versioning Policy

## Overview

Qemubox uses semantic versioning for its gRPC/TTRPC APIs to ensure compatibility and smooth upgrades for users.

## Version Format

All API services are versioned using the `/v{N}` suffix in their package names:
- `containerd.vminitd.services.system.v1`
- `containerd.vminitd.services.bundle.v1`
- `containerd.vminitd.services.vmevents.v1`

Where `{N}` is the major version number.

## Compatibility Guarantees

### Within a major version (e.g., v1.0.0 → v1.9.0):
- **Backward compatible changes only**
- Can add new:
- RPC methods
- Message fields (using new field numbers)
- Enum values (except renumbering existing ones)
- Cannot:
- Remove or rename existing RPCs
- Remove or rename existing message fields
- Change field types or numbers
- Remove enum values

### Across major versions (e.g., v1 → v2):
- **Breaking changes allowed**
- New `/v2` package created alongside `/v1`
- Both versions can coexist during migration period
- Deprecated version receives security fixes only

## Adding New Features

### Adding a new RPC method (compatible):
```protobuf
service System {
rpc Info(google.protobuf.Empty) returns (InfoResponse); // Existing

// New method added in v1.2.0
rpc GetMetrics(MetricsRequest) returns (MetricsResponse);
}
```

### Adding new message fields (compatible):
```protobuf
message InfoResponse {
string version = 1; // Existing field
string kernel_version = 2; // Existing field

// New field added in v1.3.0
string hostname = 3;
}
```

### Breaking changes require new major version:
```protobuf
// OLD: api/services/system/v1/info.proto
package containerd.vminitd.services.system.v1;

// NEW: api/services/system/v2/info.proto
package containerd.vminitd.services.system.v2;
```

## Proto3 Field Evolution

Proto3 provides natural evolution:
- Unknown fields are preserved during deserialization
- Clients ignore unknown fields from newer servers
- Servers ignore unknown fields from older clients

## Deprecation Process

1. **Announce deprecation** in release notes
2. **Mark deprecated** in proto with comment:
```protobuf
// Deprecated: Use NewMethod instead. Will be removed in v2.
rpc OldMethod(OldRequest) returns (OldResponse);
```
3. **Maintain for 2+ minor versions** before major version bump
4. **Remove in next major version**

## Version Detection

Clients can detect API version via:
- `Info()` RPC returns `version` field (e.g., "1.2.0")
- gRPC metadata (if needed for version negotiation)

## Current Version

- **Bundle Service (`bundle/v1`)**: v1.0.0
- **System Service (`system/v1`)**: v1.0.0
- **VM Events Service (`vmevents/v1`)**: v1.0.0

All services are currently in v1 and follow backward-compatibility guarantees outlined above.

## References

- [Protobuf Language Guide - Updating](https://protobuf.dev/programming-guides/proto3/#updating)
- [gRPC Versioning Guide](https://grpc.io/docs/guides/versioning/)
- [Semantic Versioning 2.0.0](https://semver.org/)
18 changes: 18 additions & 0 deletions api/services/bundle/v1/bundle.proto
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,33 @@ package containerd.vminitd.services.bundle.v1;

option go_package = "github.com/aledbf/qemubox/containerd/api/services/bundle/v1;bundle";

// Bundle service manages OCI bundle creation inside the VM.
// This service is exposed by vminitd over vsock to the host shim.
service Bundle {
// Create creates an OCI bundle from the provided files.
//
// The bundle directory is created at /run/qemubox/{namespace}/{id}/
// and populated with the files from the request (e.g., config.json,
// hostname, hosts, resolv.conf).
//
// Returns:
// - INVALID_ARGUMENT: id is empty or files map is empty
// - ALREADY_EXISTS: bundle with this id already exists
// - INTERNAL: failed to create bundle directory or write files
rpc Create(CreateRequest) returns (CreateResponse);
}

message CreateRequest {
// id is the unique identifier for the bundle to create.
string id = 1;

// files is a map of filename to file contents.
// Keys are relative paths within the bundle (e.g., "config.json", "hosts", "resolv.conf").
// Values are the file contents as raw bytes.
map<string, bytes> files = 2;
}

message CreateResponse {
// bundle is the absolute path to the created bundle directory on the VM filesystem.
string bundle = 1;
}
48 changes: 48 additions & 0 deletions api/services/system/v1/info.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,79 @@ import "google/protobuf/empty.proto";

option go_package = "github.com/aledbf/qemubox/containerd/api/services/system/v1;system";

// System service provides VM system information and CPU/memory hotplug operations.
// This service is exposed by vminitd over vsock to the host shim for dynamic
// resource management.
service System {
// Info returns VM system information (vminitd version, kernel version).
// This is called during VM initialization to verify the guest is ready.
rpc Info(google.protobuf.Empty) returns (InfoResponse);

// OfflineCPU takes a CPU offline via sysfs before hot-unplug.
// The CPU must have been previously onlined and cannot be CPU 0 (boot CPU).
//
// Returns:
// - INVALID_ARGUMENT: cpu_id is 0 (cannot offline boot CPU)
// - NOT_FOUND: cpu_id does not exist in /sys/devices/system/cpu/
// - FAILED_PRECONDITION: CPU is already offline or in use
// - INTERNAL: failed to write to sysfs
rpc OfflineCPU(OfflineCPURequest) returns (google.protobuf.Empty);

// OnlineCPU brings a CPU online via sysfs after hot-plug.
// The CPU must have been previously hot-plugged via QEMU QMP.
//
// Returns:
// - NOT_FOUND: cpu_id does not exist (not yet hot-plugged via QMP)
// - FAILED_PRECONDITION: CPU is already online
// - INTERNAL: failed to write to sysfs
rpc OnlineCPU(OnlineCPURequest) returns (google.protobuf.Empty);

// OfflineMemory takes a memory block offline via sysfs before hot-unplug.
//
// Returns:
// - NOT_FOUND: memory_id does not exist in /sys/devices/system/memory/
// - FAILED_PRECONDITION: memory block is already offline or contains kernel memory
// - INTERNAL: failed to write to sysfs
rpc OfflineMemory(OfflineMemoryRequest) returns (google.protobuf.Empty);

// OnlineMemory brings a memory block online via sysfs after hot-plug.
// The memory block must have been previously hot-plugged via QEMU QMP.
//
// Returns:
// - NOT_FOUND: memory_id does not exist (not yet hot-plugged via QMP)
// - FAILED_PRECONDITION: memory block is already online
// - INTERNAL: failed to write to sysfs
rpc OnlineMemory(OnlineMemoryRequest) returns (google.protobuf.Empty);
}

message InfoResponse {
// version is the qemubox vminitd version (e.g., "1.0.0").
string version = 1;

// kernel_version is the Linux kernel version running in the VM (e.g., "6.1.0").
string kernel_version = 2;
}

message OfflineCPURequest {
// cpu_id is the logical CPU ID to offline (zero-indexed, e.g., 0, 1, 2).
// This corresponds to /sys/devices/system/cpu/cpu{N}.
uint32 cpu_id = 1;
}

message OnlineCPURequest {
// cpu_id is the logical CPU ID to online (zero-indexed, e.g., 0, 1, 2).
// This corresponds to /sys/devices/system/cpu/cpu{N}.
uint32 cpu_id = 1;
}

message OfflineMemoryRequest {
// memory_id is the memory block ID to offline (zero-indexed).
// This corresponds to the QMP memory slot number.
uint32 memory_id = 1;
}

message OnlineMemoryRequest {
// memory_id is the memory block ID to online (zero-indexed).
// This corresponds to the QMP memory slot number.
uint32 memory_id = 1;
}
1 change: 1 addition & 0 deletions cmd/containerd-shim-qemubox-v1/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/aledbf/qemubox/containerd/internal/config"
"github.com/aledbf/qemubox/containerd/internal/shim/manager"

// Register shim plugin with containerd runtime
_ "github.com/aledbf/qemubox/containerd/internal/shim"
)

Expand Down
Loading