1
0
forked from wrenn/wrenn

Add minimal control plane with REST API, database, and reconciler

- REST API (chi router): sandbox CRUD, exec, pause/resume, file write/read
- PostgreSQL persistence via pgx/v5 + sqlc (sandboxes table with goose migration)
- Connect RPC client to host agent for all VM operations
- Reconciler syncs host agent state with DB every 30s (detects TTL-reaped sandboxes)
- OpenAPI 3.1 spec served at /openapi.yaml, Swagger UI at /docs
- Added WriteFile/ReadFile RPCs to hostagent proto and implementations
- File upload via multipart form, download via JSON body POST
- sandbox_id propagated from control plane to host agent on create
This commit is contained in:
2026-03-10 16:50:12 +06:00
parent d7b25b0891
commit ec3360d9ad
46 changed files with 2210 additions and 33 deletions

View File

@ -57,8 +57,11 @@ func New(cfg Config) *Manager {
}
// Create boots a new sandbox: clone rootfs, set up network, start VM, wait for envd.
func (m *Manager) Create(ctx context.Context, template string, vcpus, memoryMB, timeoutSec int) (*models.Sandbox, error) {
sandboxID := id.NewSandboxID()
// If sandboxID is empty, a new ID is generated.
func (m *Manager) Create(ctx context.Context, sandboxID, template string, vcpus, memoryMB, timeoutSec int) (*models.Sandbox, error) {
if sandboxID == "" {
sandboxID = id.NewSandboxID()
}
if vcpus <= 0 {
vcpus = 1
@ -280,6 +283,18 @@ func (m *Manager) Get(sandboxID string) (*models.Sandbox, error) {
return &sb.Sandbox, nil
}
// GetClient returns the envd client for a sandbox.
func (m *Manager) GetClient(sandboxID string) (*envdclient.Client, error) {
sb, err := m.get(sandboxID)
if err != nil {
return nil, err
}
if sb.Status != models.StatusRunning {
return nil, fmt.Errorf("sandbox %s is not running (status: %s)", sandboxID, sb.Status)
}
return sb.client, nil
}
func (m *Manager) get(sandboxID string) (*sandboxState, error) {
m.mu.RLock()
defer m.mu.RUnlock()