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:
@ -30,7 +30,7 @@ func (s *Server) CreateSandbox(
|
||||
) (*connect.Response[pb.CreateSandboxResponse], error) {
|
||||
msg := req.Msg
|
||||
|
||||
sb, err := s.mgr.Create(ctx, msg.Template, int(msg.Vcpus), int(msg.MemoryMb), int(msg.TimeoutSec))
|
||||
sb, err := s.mgr.Create(ctx, msg.SandboxId, msg.Template, int(msg.Vcpus), int(msg.MemoryMb), int(msg.TimeoutSec))
|
||||
if err != nil {
|
||||
return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("create sandbox: %w", err))
|
||||
}
|
||||
@ -98,6 +98,43 @@ func (s *Server) Exec(
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) WriteFile(
|
||||
ctx context.Context,
|
||||
req *connect.Request[pb.WriteFileRequest],
|
||||
) (*connect.Response[pb.WriteFileResponse], error) {
|
||||
msg := req.Msg
|
||||
|
||||
client, err := s.mgr.GetClient(msg.SandboxId)
|
||||
if err != nil {
|
||||
return nil, connect.NewError(connect.CodeNotFound, err)
|
||||
}
|
||||
|
||||
if err := client.WriteFile(ctx, msg.Path, msg.Content); err != nil {
|
||||
return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("write file: %w", err))
|
||||
}
|
||||
|
||||
return connect.NewResponse(&pb.WriteFileResponse{}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ReadFile(
|
||||
ctx context.Context,
|
||||
req *connect.Request[pb.ReadFileRequest],
|
||||
) (*connect.Response[pb.ReadFileResponse], error) {
|
||||
msg := req.Msg
|
||||
|
||||
client, err := s.mgr.GetClient(msg.SandboxId)
|
||||
if err != nil {
|
||||
return nil, connect.NewError(connect.CodeNotFound, err)
|
||||
}
|
||||
|
||||
content, err := client.ReadFile(ctx, msg.Path)
|
||||
if err != nil {
|
||||
return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("read file: %w", err))
|
||||
}
|
||||
|
||||
return connect.NewResponse(&pb.ReadFileResponse{Content: content}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ListSandboxes(
|
||||
ctx context.Context,
|
||||
req *connect.Request[pb.ListSandboxesRequest],
|
||||
|
||||
Reference in New Issue
Block a user