forked from wrenn/wrenn
Add background process execution API
Start long-running processes (web servers, daemons) without blocking the
HTTP request. Leverages envd's existing background process support
(context.Background(), List, Connect, SendSignal RPCs) and wires it
through the host agent and control plane layers.
New API surface:
- POST /v1/capsules/{id}/exec with background:true → 202 {pid, tag}
- GET /v1/capsules/{id}/processes → list running processes
- DELETE /v1/capsules/{id}/processes/{selector} → kill by PID or tag
- WS /v1/capsules/{id}/processes/{selector}/stream → reconnect to output
The {selector} param auto-detects: numeric = PID, string = tag.
Tags are auto-generated as "proc-" + 8 hex chars if not provided.
This commit is contained in:
@ -29,9 +29,13 @@ func newExecHandler(db *db.Queries, pool *lifecycle.HostClientPool) *execHandler
|
||||
}
|
||||
|
||||
type execRequest struct {
|
||||
Cmd string `json:"cmd"`
|
||||
Args []string `json:"args"`
|
||||
TimeoutSec int32 `json:"timeout_sec"`
|
||||
Cmd string `json:"cmd"`
|
||||
Args []string `json:"args"`
|
||||
TimeoutSec int32 `json:"timeout_sec"`
|
||||
Background bool `json:"background"`
|
||||
Tag string `json:"tag"`
|
||||
Envs map[string]string `json:"envs"`
|
||||
Cwd string `json:"cwd"`
|
||||
}
|
||||
|
||||
type execResponse struct {
|
||||
@ -45,6 +49,13 @@ type execResponse struct {
|
||||
Encoding string `json:"encoding"`
|
||||
}
|
||||
|
||||
type backgroundExecResponse struct {
|
||||
SandboxID string `json:"sandbox_id"`
|
||||
Cmd string `json:"cmd"`
|
||||
PID uint32 `json:"pid"`
|
||||
Tag string `json:"tag"`
|
||||
}
|
||||
|
||||
// Exec handles POST /v1/capsules/{id}/exec.
|
||||
func (h *execHandler) Exec(w http.ResponseWriter, r *http.Request) {
|
||||
sandboxIDStr := chi.URLParam(r, "id")
|
||||
@ -78,14 +89,54 @@ func (h *execHandler) Exec(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
|
||||
agent, err := agentForHost(ctx, h.db, h.pool, sb.HostID)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusServiceUnavailable, "host_unavailable", "sandbox host is not reachable")
|
||||
return
|
||||
}
|
||||
|
||||
// Background mode: start process and return immediately.
|
||||
if req.Background {
|
||||
tag := req.Tag
|
||||
if tag == "" {
|
||||
tag = "proc-" + id.NewPtyTag()
|
||||
}
|
||||
|
||||
bgResp, err := agent.StartBackground(ctx, connect.NewRequest(&pb.StartBackgroundRequest{
|
||||
SandboxId: sandboxIDStr,
|
||||
Tag: tag,
|
||||
Cmd: req.Cmd,
|
||||
Args: req.Args,
|
||||
Envs: req.Envs,
|
||||
Cwd: req.Cwd,
|
||||
}))
|
||||
if err != nil {
|
||||
status, code, msg := agentErrToHTTP(err)
|
||||
writeError(w, status, code, msg)
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.db.UpdateLastActive(ctx, db.UpdateLastActiveParams{
|
||||
ID: sandboxID,
|
||||
LastActiveAt: pgtype.Timestamptz{
|
||||
Time: time.Now(),
|
||||
Valid: true,
|
||||
},
|
||||
}); err != nil {
|
||||
slog.Warn("failed to update last_active_at", "id", sandboxIDStr, "error", err)
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusAccepted, backgroundExecResponse{
|
||||
SandboxID: sandboxIDStr,
|
||||
Cmd: req.Cmd,
|
||||
PID: bgResp.Msg.Pid,
|
||||
Tag: bgResp.Msg.Tag,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
|
||||
resp, err := agent.Exec(ctx, connect.NewRequest(&pb.ExecRequest{
|
||||
SandboxId: sandboxIDStr,
|
||||
Cmd: req.Cmd,
|
||||
|
||||
266
internal/api/handlers_process.go
Normal file
266
internal/api/handlers_process.go
Normal file
@ -0,0 +1,266 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
|
||||
"git.omukk.dev/wrenn/wrenn/internal/auth"
|
||||
"git.omukk.dev/wrenn/wrenn/internal/db"
|
||||
"git.omukk.dev/wrenn/wrenn/internal/id"
|
||||
"git.omukk.dev/wrenn/wrenn/internal/lifecycle"
|
||||
pb "git.omukk.dev/wrenn/wrenn/proto/hostagent/gen"
|
||||
)
|
||||
|
||||
type processHandler struct {
|
||||
db *db.Queries
|
||||
pool *lifecycle.HostClientPool
|
||||
}
|
||||
|
||||
func newProcessHandler(db *db.Queries, pool *lifecycle.HostClientPool) *processHandler {
|
||||
return &processHandler{db: db, pool: pool}
|
||||
}
|
||||
|
||||
// processResponse is a single entry in the process list.
|
||||
type processResponse struct {
|
||||
PID uint32 `json:"pid"`
|
||||
Tag string `json:"tag,omitempty"`
|
||||
Cmd string `json:"cmd"`
|
||||
Args []string `json:"args,omitempty"`
|
||||
}
|
||||
|
||||
// processListResponse wraps the list of processes.
|
||||
type processListResponse struct {
|
||||
Processes []processResponse `json:"processes"`
|
||||
}
|
||||
|
||||
// ListProcesses handles GET /v1/capsules/{id}/processes.
|
||||
func (h *processHandler) ListProcesses(w http.ResponseWriter, r *http.Request) {
|
||||
sandboxIDStr := chi.URLParam(r, "id")
|
||||
ctx := r.Context()
|
||||
ac := auth.MustFromContext(ctx)
|
||||
|
||||
sandboxID, err := id.ParseSandboxID(sandboxIDStr)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid_request", "invalid sandbox ID")
|
||||
return
|
||||
}
|
||||
|
||||
sb, err := h.db.GetSandboxByTeam(ctx, db.GetSandboxByTeamParams{ID: sandboxID, TeamID: ac.TeamID})
|
||||
if err != nil {
|
||||
writeError(w, http.StatusNotFound, "not_found", "sandbox not found")
|
||||
return
|
||||
}
|
||||
if sb.Status != "running" {
|
||||
writeError(w, http.StatusConflict, "invalid_state", "sandbox is not running (status: "+sb.Status+")")
|
||||
return
|
||||
}
|
||||
|
||||
agent, err := agentForHost(ctx, h.db, h.pool, sb.HostID)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusServiceUnavailable, "host_unavailable", "sandbox host is not reachable")
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := agent.ListProcesses(ctx, connect.NewRequest(&pb.ListProcessesRequest{
|
||||
SandboxId: sandboxIDStr,
|
||||
}))
|
||||
if err != nil {
|
||||
status, code, msg := agentErrToHTTP(err)
|
||||
writeError(w, status, code, msg)
|
||||
return
|
||||
}
|
||||
|
||||
procs := make([]processResponse, 0, len(resp.Msg.Processes))
|
||||
for _, p := range resp.Msg.Processes {
|
||||
procs = append(procs, processResponse{
|
||||
PID: p.Pid,
|
||||
Tag: p.Tag,
|
||||
Cmd: p.Cmd,
|
||||
Args: p.Args,
|
||||
})
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, processListResponse{Processes: procs})
|
||||
}
|
||||
|
||||
// KillProcess handles DELETE /v1/capsules/{id}/processes/{selector}.
|
||||
// The selector can be a numeric PID or a string tag.
|
||||
func (h *processHandler) KillProcess(w http.ResponseWriter, r *http.Request) {
|
||||
sandboxIDStr := chi.URLParam(r, "id")
|
||||
selectorStr := chi.URLParam(r, "selector")
|
||||
ctx := r.Context()
|
||||
ac := auth.MustFromContext(ctx)
|
||||
|
||||
sandboxID, err := id.ParseSandboxID(sandboxIDStr)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid_request", "invalid sandbox ID")
|
||||
return
|
||||
}
|
||||
|
||||
sb, err := h.db.GetSandboxByTeam(ctx, db.GetSandboxByTeamParams{ID: sandboxID, TeamID: ac.TeamID})
|
||||
if err != nil {
|
||||
writeError(w, http.StatusNotFound, "not_found", "sandbox not found")
|
||||
return
|
||||
}
|
||||
if sb.Status != "running" {
|
||||
writeError(w, http.StatusConflict, "invalid_state", "sandbox is not running (status: "+sb.Status+")")
|
||||
return
|
||||
}
|
||||
|
||||
agent, err := agentForHost(ctx, h.db, h.pool, sb.HostID)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusServiceUnavailable, "host_unavailable", "sandbox host is not reachable")
|
||||
return
|
||||
}
|
||||
|
||||
// Build the kill request with PID or tag selector.
|
||||
killReq := &pb.KillProcessRequest{
|
||||
SandboxId: sandboxIDStr,
|
||||
Signal: "SIGKILL",
|
||||
}
|
||||
if sig := r.URL.Query().Get("signal"); sig == "SIGTERM" {
|
||||
killReq.Signal = "SIGTERM"
|
||||
}
|
||||
|
||||
if pid, err := strconv.ParseUint(selectorStr, 10, 32); err == nil {
|
||||
killReq.Selector = &pb.KillProcessRequest_Pid{Pid: uint32(pid)}
|
||||
} else {
|
||||
killReq.Selector = &pb.KillProcessRequest_Tag{Tag: selectorStr}
|
||||
}
|
||||
|
||||
if _, err := agent.KillProcess(ctx, connect.NewRequest(killReq)); err != nil {
|
||||
status, code, msg := agentErrToHTTP(err)
|
||||
writeError(w, status, code, msg)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// wsProcessOut is the JSON message sent to the WebSocket client.
|
||||
type wsProcessOut struct {
|
||||
Type string `json:"type"` // "start", "stdout", "stderr", "exit", "error"
|
||||
PID uint32 `json:"pid,omitempty"` // only for "start"
|
||||
Data string `json:"data,omitempty"` // only for "stdout", "stderr", "error"
|
||||
ExitCode *int32 `json:"exit_code,omitempty"` // only for "exit"
|
||||
}
|
||||
|
||||
// ConnectProcess handles WS /v1/capsules/{id}/processes/{selector}/stream.
|
||||
func (h *processHandler) ConnectProcess(w http.ResponseWriter, r *http.Request) {
|
||||
sandboxIDStr := chi.URLParam(r, "id")
|
||||
selectorStr := chi.URLParam(r, "selector")
|
||||
ctx := r.Context()
|
||||
ac := auth.MustFromContext(ctx)
|
||||
|
||||
sandboxID, err := id.ParseSandboxID(sandboxIDStr)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid_request", "invalid sandbox ID")
|
||||
return
|
||||
}
|
||||
|
||||
sb, err := h.db.GetSandboxByTeam(ctx, db.GetSandboxByTeamParams{ID: sandboxID, TeamID: ac.TeamID})
|
||||
if err != nil {
|
||||
writeError(w, http.StatusNotFound, "not_found", "sandbox not found")
|
||||
return
|
||||
}
|
||||
if sb.Status != "running" {
|
||||
writeError(w, http.StatusConflict, "invalid_state", "sandbox is not running (status: "+sb.Status+")")
|
||||
return
|
||||
}
|
||||
|
||||
agent, err := agentForHost(ctx, h.db, h.pool, sb.HostID)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusServiceUnavailable, "host_unavailable", "sandbox host is not reachable")
|
||||
return
|
||||
}
|
||||
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
slog.Error("process stream websocket upgrade failed", "error", err)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// Build the connect request with PID or tag selector.
|
||||
connectReq := &pb.ConnectProcessRequest{
|
||||
SandboxId: sandboxIDStr,
|
||||
}
|
||||
if pid, err := strconv.ParseUint(selectorStr, 10, 32); err == nil {
|
||||
connectReq.Selector = &pb.ConnectProcessRequest_Pid{Pid: uint32(pid)}
|
||||
} else {
|
||||
connectReq.Selector = &pb.ConnectProcessRequest_Tag{Tag: selectorStr}
|
||||
}
|
||||
|
||||
streamCtx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
stream, err := agent.ConnectProcess(streamCtx, connect.NewRequest(connectReq))
|
||||
if err != nil {
|
||||
sendProcessWSError(conn, "failed to connect to process: "+err.Error())
|
||||
return
|
||||
}
|
||||
defer stream.Close()
|
||||
|
||||
// Listen for client disconnect in a goroutine.
|
||||
go func() {
|
||||
for {
|
||||
_, _, err := conn.ReadMessage()
|
||||
if err != nil {
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Forward stream events to WebSocket.
|
||||
for stream.Receive() {
|
||||
resp := stream.Msg()
|
||||
switch ev := resp.Event.(type) {
|
||||
case *pb.ConnectProcessResponse_Start:
|
||||
writeWSJSON(conn, wsProcessOut{Type: "start", PID: ev.Start.Pid})
|
||||
|
||||
case *pb.ConnectProcessResponse_Data:
|
||||
switch o := ev.Data.Output.(type) {
|
||||
case *pb.ExecStreamData_Stdout:
|
||||
writeWSJSON(conn, wsProcessOut{Type: "stdout", Data: string(o.Stdout)})
|
||||
case *pb.ExecStreamData_Stderr:
|
||||
writeWSJSON(conn, wsProcessOut{Type: "stderr", Data: string(o.Stderr)})
|
||||
}
|
||||
|
||||
case *pb.ConnectProcessResponse_End:
|
||||
exitCode := ev.End.ExitCode
|
||||
writeWSJSON(conn, wsProcessOut{Type: "exit", ExitCode: &exitCode})
|
||||
}
|
||||
}
|
||||
|
||||
if err := stream.Err(); err != nil {
|
||||
if streamCtx.Err() == nil {
|
||||
sendProcessWSError(conn, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Update last active using a fresh context.
|
||||
updateCtx, updateCancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer updateCancel()
|
||||
if err := h.db.UpdateLastActive(updateCtx, db.UpdateLastActiveParams{
|
||||
ID: sandboxID,
|
||||
LastActiveAt: pgtype.Timestamptz{
|
||||
Time: time.Now(),
|
||||
Valid: true,
|
||||
},
|
||||
}); err != nil {
|
||||
slog.Warn("failed to update last active after process stream", "sandbox_id", sandboxIDStr, "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func sendProcessWSError(conn *websocket.Conn, msg string) {
|
||||
writeWSJSON(conn, wsProcessOut{Type: "error", Data: msg})
|
||||
}
|
||||
@ -699,11 +699,17 @@ paths:
|
||||
$ref: "#/components/schemas/ExecRequest"
|
||||
responses:
|
||||
"200":
|
||||
description: Command output
|
||||
description: Command output (foreground exec)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ExecResponse"
|
||||
"202":
|
||||
description: Background process started
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/BackgroundExecResponse"
|
||||
"404":
|
||||
description: Capsule not found
|
||||
content:
|
||||
@ -717,6 +723,122 @@ paths:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
|
||||
/v1/capsules/{id}/processes:
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
|
||||
get:
|
||||
summary: List running processes
|
||||
operationId: listProcesses
|
||||
tags: [capsules]
|
||||
security:
|
||||
- apiKeyAuth: []
|
||||
description: |
|
||||
Returns all running processes inside the capsule, including background
|
||||
processes and any processes started by templates or init scripts.
|
||||
responses:
|
||||
"200":
|
||||
description: Process list
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ProcessListResponse"
|
||||
"404":
|
||||
description: Capsule not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
"409":
|
||||
description: Capsule not running
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
|
||||
/v1/capsules/{id}/processes/{selector}:
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: selector
|
||||
in: path
|
||||
required: true
|
||||
description: Process PID (numeric) or tag (string)
|
||||
schema:
|
||||
type: string
|
||||
|
||||
delete:
|
||||
summary: Kill a process
|
||||
operationId: killProcess
|
||||
tags: [capsules]
|
||||
security:
|
||||
- apiKeyAuth: []
|
||||
parameters:
|
||||
- name: signal
|
||||
in: query
|
||||
required: false
|
||||
description: Signal to send (SIGKILL or SIGTERM, default SIGKILL)
|
||||
schema:
|
||||
type: string
|
||||
enum: [SIGKILL, SIGTERM]
|
||||
default: SIGKILL
|
||||
responses:
|
||||
"204":
|
||||
description: Process killed
|
||||
"404":
|
||||
description: Capsule or process not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
"409":
|
||||
description: Capsule not running
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
|
||||
/v1/capsules/{id}/processes/{selector}/stream:
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: selector
|
||||
in: path
|
||||
required: true
|
||||
description: Process PID (numeric) or tag (string)
|
||||
schema:
|
||||
type: string
|
||||
|
||||
get:
|
||||
summary: Stream process output via WebSocket
|
||||
operationId: connectProcess
|
||||
tags: [capsules]
|
||||
security:
|
||||
- apiKeyAuth: []
|
||||
description: |
|
||||
Opens a WebSocket connection to stream stdout/stderr from a running
|
||||
background process. The selector can be a numeric PID or a string tag.
|
||||
|
||||
Server sends JSON messages:
|
||||
- `{"type": "start", "pid": 42}` — connected to process
|
||||
- `{"type": "stdout", "data": "..."}` — stdout output
|
||||
- `{"type": "stderr", "data": "..."}` — stderr output
|
||||
- `{"type": "exit", "exit_code": 0}` — process exited
|
||||
- `{"type": "error", "data": "..."}` — error message
|
||||
responses:
|
||||
"101":
|
||||
description: WebSocket upgrade
|
||||
|
||||
/v1/capsules/{id}/ping:
|
||||
parameters:
|
||||
- name: id
|
||||
@ -2153,6 +2275,56 @@ components:
|
||||
timeout_sec:
|
||||
type: integer
|
||||
default: 30
|
||||
description: Timeout in seconds (foreground exec only, default 30)
|
||||
background:
|
||||
type: boolean
|
||||
default: false
|
||||
description: If true, starts the process in the background and returns immediately with a PID and tag (HTTP 202)
|
||||
tag:
|
||||
type: string
|
||||
description: Optional user-chosen tag for the background process. Auto-generated if omitted. Only used when background is true.
|
||||
envs:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: Environment variables for the process (background exec only)
|
||||
cwd:
|
||||
type: string
|
||||
description: Working directory for the process (background exec only)
|
||||
|
||||
BackgroundExecResponse:
|
||||
type: object
|
||||
properties:
|
||||
sandbox_id:
|
||||
type: string
|
||||
cmd:
|
||||
type: string
|
||||
pid:
|
||||
type: integer
|
||||
tag:
|
||||
type: string
|
||||
|
||||
ProcessEntry:
|
||||
type: object
|
||||
properties:
|
||||
pid:
|
||||
type: integer
|
||||
tag:
|
||||
type: string
|
||||
cmd:
|
||||
type: string
|
||||
args:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
|
||||
ProcessListResponse:
|
||||
type: object
|
||||
properties:
|
||||
processes:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/ProcessEntry"
|
||||
|
||||
ExecResponse:
|
||||
type: object
|
||||
|
||||
@ -74,6 +74,7 @@ func New(
|
||||
buildH := newBuildHandler(buildSvc, queries, pool)
|
||||
channelH := newChannelHandler(channelSvc, al)
|
||||
ptyH := newPtyHandler(queries, pool)
|
||||
processH := newProcessHandler(queries, pool)
|
||||
adminCapsules := newAdminCapsuleHandler(sandboxSvc, queries, pool, al)
|
||||
|
||||
// OpenAPI spec and docs.
|
||||
@ -141,6 +142,9 @@ func New(
|
||||
r.Post("/files/remove", fsH.Remove)
|
||||
r.Get("/metrics", metricsH.GetMetrics)
|
||||
r.Get("/pty", ptyH.PtySession)
|
||||
r.Get("/processes", processH.ListProcesses)
|
||||
r.Delete("/processes/{selector}", processH.KillProcess)
|
||||
r.Get("/processes/{selector}/stream", processH.ConnectProcess)
|
||||
})
|
||||
})
|
||||
|
||||
@ -224,6 +228,9 @@ func New(
|
||||
r.Post("/files/remove", fsH.Remove)
|
||||
r.Get("/metrics", metricsH.GetMetrics)
|
||||
r.Get("/pty", ptyH.PtySession)
|
||||
r.Get("/processes", processH.ListProcesses)
|
||||
r.Delete("/processes/{selector}", processH.KillProcess)
|
||||
r.Get("/processes/{selector}/stream", processH.ConnectProcess)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
187
internal/envdclient/process.go
Normal file
187
internal/envdclient/process.go
Normal file
@ -0,0 +1,187 @@
|
||||
package envdclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
|
||||
envdpb "git.omukk.dev/wrenn/wrenn/proto/envd/gen"
|
||||
)
|
||||
|
||||
// ProcessInfo holds metadata about a running process inside the sandbox.
|
||||
type ProcessInfo struct {
|
||||
PID uint32
|
||||
Tag string
|
||||
Cmd string
|
||||
Args []string
|
||||
}
|
||||
|
||||
// StartBackground starts a process that runs independently of the RPC stream.
|
||||
// It opens a Start stream, reads the first StartEvent to obtain the PID,
|
||||
// then closes the stream. The process continues running inside the VM because
|
||||
// envd binds it to context.Background().
|
||||
func (c *Client) StartBackground(ctx context.Context, tag, cmd string, args []string, envs map[string]string, cwd string) (uint32, error) {
|
||||
stdin := false
|
||||
cfg := &envdpb.ProcessConfig{
|
||||
Cmd: cmd,
|
||||
Args: args,
|
||||
Envs: envs,
|
||||
}
|
||||
if cwd != "" {
|
||||
cfg.Cwd = &cwd
|
||||
}
|
||||
|
||||
req := connect.NewRequest(&envdpb.StartRequest{
|
||||
Process: cfg,
|
||||
Tag: &tag,
|
||||
Stdin: &stdin,
|
||||
})
|
||||
|
||||
stream, err := c.process.Start(ctx, req)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("start background process: %w", err)
|
||||
}
|
||||
defer stream.Close()
|
||||
|
||||
// Read events until we get the StartEvent with the PID.
|
||||
for stream.Receive() {
|
||||
msg := stream.Msg()
|
||||
if msg.Event == nil {
|
||||
continue
|
||||
}
|
||||
if start, ok := msg.Event.GetEvent().(*envdpb.ProcessEvent_Start); ok {
|
||||
return start.Start.GetPid(), nil
|
||||
}
|
||||
}
|
||||
|
||||
if err := stream.Err(); err != nil && err != io.EOF {
|
||||
return 0, fmt.Errorf("start background process stream: %w", err)
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("start background process: no start event received")
|
||||
}
|
||||
|
||||
// ConnectProcess re-attaches to a running process by PID or tag and returns
|
||||
// a channel of streaming events. The channel is closed when the process ends
|
||||
// or the context is cancelled.
|
||||
func (c *Client) ConnectProcess(ctx context.Context, pid uint32, tag string) (<-chan ExecStreamEvent, error) {
|
||||
var selector *envdpb.ProcessSelector
|
||||
if tag != "" {
|
||||
selector = &envdpb.ProcessSelector{
|
||||
Selector: &envdpb.ProcessSelector_Tag{Tag: tag},
|
||||
}
|
||||
} else {
|
||||
selector = &envdpb.ProcessSelector{
|
||||
Selector: &envdpb.ProcessSelector_Pid{Pid: pid},
|
||||
}
|
||||
}
|
||||
|
||||
stream, err := c.process.Connect(ctx, connect.NewRequest(&envdpb.ConnectRequest{
|
||||
Process: selector,
|
||||
}))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("connect process: %w", err)
|
||||
}
|
||||
|
||||
ch := make(chan ExecStreamEvent, 16)
|
||||
go func() {
|
||||
defer close(ch)
|
||||
defer stream.Close()
|
||||
|
||||
for stream.Receive() {
|
||||
msg := stream.Msg()
|
||||
if msg.Event == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var ev ExecStreamEvent
|
||||
switch e := msg.Event.GetEvent().(type) {
|
||||
case *envdpb.ProcessEvent_Start:
|
||||
ev = ExecStreamEvent{Type: "start", PID: e.Start.GetPid()}
|
||||
|
||||
case *envdpb.ProcessEvent_Data:
|
||||
switch o := e.Data.GetOutput().(type) {
|
||||
case *envdpb.ProcessEvent_DataEvent_Stdout:
|
||||
ev = ExecStreamEvent{Type: "stdout", Data: o.Stdout}
|
||||
case *envdpb.ProcessEvent_DataEvent_Stderr:
|
||||
ev = ExecStreamEvent{Type: "stderr", Data: o.Stderr}
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
case *envdpb.ProcessEvent_End:
|
||||
ev = ExecStreamEvent{Type: "end", ExitCode: e.End.GetExitCode()}
|
||||
if e.End.Error != nil {
|
||||
ev.Error = e.End.GetError()
|
||||
}
|
||||
|
||||
case *envdpb.ProcessEvent_Keepalive:
|
||||
continue
|
||||
}
|
||||
|
||||
select {
|
||||
case ch <- ev:
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err := stream.Err(); err != nil && err != io.EOF {
|
||||
slog.Debug("connect process stream error", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
return ch, nil
|
||||
}
|
||||
|
||||
// ListProcesses returns all running processes inside the sandbox.
|
||||
func (c *Client) ListProcesses(ctx context.Context) ([]ProcessInfo, error) {
|
||||
resp, err := c.process.List(ctx, connect.NewRequest(&envdpb.ListRequest{}))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list processes: %w", err)
|
||||
}
|
||||
|
||||
procs := make([]ProcessInfo, 0, len(resp.Msg.Processes))
|
||||
for _, p := range resp.Msg.Processes {
|
||||
info := ProcessInfo{
|
||||
PID: p.Pid,
|
||||
}
|
||||
if p.Tag != nil {
|
||||
info.Tag = *p.Tag
|
||||
}
|
||||
if p.Config != nil {
|
||||
info.Cmd = p.Config.Cmd
|
||||
info.Args = p.Config.Args
|
||||
}
|
||||
procs = append(procs, info)
|
||||
}
|
||||
|
||||
return procs, nil
|
||||
}
|
||||
|
||||
// KillProcess sends a signal to a process identified by PID or tag.
|
||||
func (c *Client) KillProcess(ctx context.Context, pid uint32, tag string, signal envdpb.Signal) error {
|
||||
var selector *envdpb.ProcessSelector
|
||||
if tag != "" {
|
||||
selector = &envdpb.ProcessSelector{
|
||||
Selector: &envdpb.ProcessSelector_Tag{Tag: tag},
|
||||
}
|
||||
} else {
|
||||
selector = &envdpb.ProcessSelector{
|
||||
Selector: &envdpb.ProcessSelector_Pid{Pid: pid},
|
||||
}
|
||||
}
|
||||
|
||||
_, err := c.process.SendSignal(ctx, connect.NewRequest(&envdpb.SendSignalRequest{
|
||||
Process: selector,
|
||||
Signal: signal,
|
||||
}))
|
||||
if err != nil {
|
||||
return fmt.Errorf("kill process: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -752,3 +752,152 @@ func entryInfoToPB(e *envdpb.EntryInfo) *pb.FileEntry {
|
||||
|
||||
return entry
|
||||
}
|
||||
|
||||
// ── Background Processes ────────────────────────────────────────────
|
||||
|
||||
func (s *Server) StartBackground(
|
||||
ctx context.Context,
|
||||
req *connect.Request[pb.StartBackgroundRequest],
|
||||
) (*connect.Response[pb.StartBackgroundResponse], error) {
|
||||
msg := req.Msg
|
||||
|
||||
pid, err := s.mgr.StartBackground(ctx, msg.SandboxId, msg.Tag, msg.Cmd, msg.Args, msg.Envs, msg.Cwd)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "not found") {
|
||||
return nil, connect.NewError(connect.CodeNotFound, err)
|
||||
}
|
||||
return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("start background: %w", err))
|
||||
}
|
||||
|
||||
return connect.NewResponse(&pb.StartBackgroundResponse{
|
||||
Pid: pid,
|
||||
Tag: msg.Tag,
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ListProcesses(
|
||||
ctx context.Context,
|
||||
req *connect.Request[pb.ListProcessesRequest],
|
||||
) (*connect.Response[pb.ListProcessesResponse], error) {
|
||||
procs, err := s.mgr.ListProcesses(ctx, req.Msg.SandboxId)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "not found") {
|
||||
return nil, connect.NewError(connect.CodeNotFound, err)
|
||||
}
|
||||
return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("list processes: %w", err))
|
||||
}
|
||||
|
||||
entries := make([]*pb.ProcessEntry, 0, len(procs))
|
||||
for _, p := range procs {
|
||||
entries = append(entries, &pb.ProcessEntry{
|
||||
Pid: p.PID,
|
||||
Tag: p.Tag,
|
||||
Cmd: p.Cmd,
|
||||
Args: p.Args,
|
||||
})
|
||||
}
|
||||
|
||||
return connect.NewResponse(&pb.ListProcessesResponse{
|
||||
Processes: entries,
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) KillProcess(
|
||||
ctx context.Context,
|
||||
req *connect.Request[pb.KillProcessRequest],
|
||||
) (*connect.Response[pb.KillProcessResponse], error) {
|
||||
msg := req.Msg
|
||||
|
||||
// Resolve PID/tag selector.
|
||||
var pid uint32
|
||||
var tag string
|
||||
switch sel := msg.Selector.(type) {
|
||||
case *pb.KillProcessRequest_Pid:
|
||||
pid = sel.Pid
|
||||
case *pb.KillProcessRequest_Tag:
|
||||
tag = sel.Tag
|
||||
default:
|
||||
return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("pid or tag is required"))
|
||||
}
|
||||
|
||||
// Map signal string to envd enum.
|
||||
var signal envdpb.Signal
|
||||
switch msg.Signal {
|
||||
case "", "SIGKILL":
|
||||
signal = envdpb.Signal_SIGNAL_SIGKILL
|
||||
case "SIGTERM":
|
||||
signal = envdpb.Signal_SIGNAL_SIGTERM
|
||||
default:
|
||||
return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("unsupported signal: %s (use SIGKILL or SIGTERM)", msg.Signal))
|
||||
}
|
||||
|
||||
if err := s.mgr.KillProcess(ctx, msg.SandboxId, pid, tag, signal); err != nil {
|
||||
if strings.Contains(err.Error(), "not found") {
|
||||
return nil, connect.NewError(connect.CodeNotFound, err)
|
||||
}
|
||||
return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("kill process: %w", err))
|
||||
}
|
||||
|
||||
return connect.NewResponse(&pb.KillProcessResponse{}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ConnectProcess(
|
||||
ctx context.Context,
|
||||
req *connect.Request[pb.ConnectProcessRequest],
|
||||
stream *connect.ServerStream[pb.ConnectProcessResponse],
|
||||
) error {
|
||||
msg := req.Msg
|
||||
|
||||
var pid uint32
|
||||
var tag string
|
||||
switch sel := msg.Selector.(type) {
|
||||
case *pb.ConnectProcessRequest_Pid:
|
||||
pid = sel.Pid
|
||||
case *pb.ConnectProcessRequest_Tag:
|
||||
tag = sel.Tag
|
||||
default:
|
||||
return connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("pid or tag is required"))
|
||||
}
|
||||
|
||||
events, err := s.mgr.ConnectProcess(ctx, msg.SandboxId, pid, tag)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "not found") {
|
||||
return connect.NewError(connect.CodeNotFound, err)
|
||||
}
|
||||
return connect.NewError(connect.CodeInternal, fmt.Errorf("connect process: %w", err))
|
||||
}
|
||||
|
||||
for ev := range events {
|
||||
var resp pb.ConnectProcessResponse
|
||||
switch ev.Type {
|
||||
case "start":
|
||||
resp.Event = &pb.ConnectProcessResponse_Start{
|
||||
Start: &pb.ExecStreamStart{Pid: ev.PID},
|
||||
}
|
||||
case "stdout":
|
||||
resp.Event = &pb.ConnectProcessResponse_Data{
|
||||
Data: &pb.ExecStreamData{
|
||||
Output: &pb.ExecStreamData_Stdout{Stdout: ev.Data},
|
||||
},
|
||||
}
|
||||
case "stderr":
|
||||
resp.Event = &pb.ConnectProcessResponse_Data{
|
||||
Data: &pb.ExecStreamData{
|
||||
Output: &pb.ExecStreamData_Stderr{Stderr: ev.Data},
|
||||
},
|
||||
}
|
||||
case "end":
|
||||
resp.Event = &pb.ConnectProcessResponse_End{
|
||||
End: &pb.ExecStreamEnd{
|
||||
ExitCode: ev.ExitCode,
|
||||
Error: ev.Error,
|
||||
},
|
||||
}
|
||||
}
|
||||
if err := stream.Send(&resp); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -24,12 +24,13 @@ import (
|
||||
"git.omukk.dev/wrenn/wrenn/internal/snapshot"
|
||||
"git.omukk.dev/wrenn/wrenn/internal/uffd"
|
||||
"git.omukk.dev/wrenn/wrenn/internal/vm"
|
||||
envdpb "git.omukk.dev/wrenn/wrenn/proto/envd/gen"
|
||||
)
|
||||
|
||||
// Config holds the paths and defaults for the sandbox manager.
|
||||
type Config struct {
|
||||
WrennDir string // root directory (e.g. /var/lib/wrenn); all sub-paths derived via layout package
|
||||
EnvdTimeout time.Duration
|
||||
WrennDir string // root directory (e.g. /var/lib/wrenn); all sub-paths derived via layout package
|
||||
EnvdTimeout time.Duration
|
||||
DefaultRootfsSizeMB int // target size for template rootfs images; 0 → DefaultDiskSizeMB
|
||||
}
|
||||
|
||||
@ -1328,6 +1329,74 @@ func (m *Manager) PtyKill(ctx context.Context, sandboxID, tag string) error {
|
||||
return sb.client.PtyKill(ctx, tag)
|
||||
}
|
||||
|
||||
// StartBackground starts a background process inside a sandbox.
|
||||
func (m *Manager) StartBackground(ctx context.Context, sandboxID, tag, cmd string, args []string, envs map[string]string, cwd string) (uint32, error) {
|
||||
sb, err := m.get(sandboxID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if sb.Status != models.StatusRunning {
|
||||
return 0, fmt.Errorf("sandbox %s is not running (status: %s)", sandboxID, sb.Status)
|
||||
}
|
||||
|
||||
m.mu.Lock()
|
||||
sb.LastActiveAt = time.Now()
|
||||
m.mu.Unlock()
|
||||
|
||||
return sb.client.StartBackground(ctx, tag, cmd, args, envs, cwd)
|
||||
}
|
||||
|
||||
// ConnectProcess re-attaches to a running process inside a sandbox.
|
||||
func (m *Manager) ConnectProcess(ctx context.Context, sandboxID string, pid uint32, tag string) (<-chan envdclient.ExecStreamEvent, 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)
|
||||
}
|
||||
|
||||
m.mu.Lock()
|
||||
sb.LastActiveAt = time.Now()
|
||||
m.mu.Unlock()
|
||||
|
||||
return sb.client.ConnectProcess(ctx, pid, tag)
|
||||
}
|
||||
|
||||
// ListProcesses returns all running processes inside a sandbox.
|
||||
func (m *Manager) ListProcesses(ctx context.Context, sandboxID string) ([]envdclient.ProcessInfo, 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)
|
||||
}
|
||||
|
||||
m.mu.Lock()
|
||||
sb.LastActiveAt = time.Now()
|
||||
m.mu.Unlock()
|
||||
|
||||
return sb.client.ListProcesses(ctx)
|
||||
}
|
||||
|
||||
// KillProcess sends a signal to a process inside a sandbox.
|
||||
func (m *Manager) KillProcess(ctx context.Context, sandboxID string, pid uint32, tag string, signal envdpb.Signal) error {
|
||||
sb, err := m.get(sandboxID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if sb.Status != models.StatusRunning {
|
||||
return fmt.Errorf("sandbox %s is not running (status: %s)", sandboxID, sb.Status)
|
||||
}
|
||||
|
||||
m.mu.Lock()
|
||||
sb.LastActiveAt = time.Now()
|
||||
m.mu.Unlock()
|
||||
|
||||
return sb.client.KillProcess(ctx, pid, tag, signal)
|
||||
}
|
||||
|
||||
// AcquireProxyConn atomically looks up a sandbox by ID and registers an
|
||||
// in-flight proxy connection. Returns the sandbox's host-reachable IP, the
|
||||
// connection tracker, and true on success. The caller must call
|
||||
|
||||
@ -3461,6 +3461,623 @@ func (*PtyKillResponse) Descriptor() ([]byte, []int) {
|
||||
return file_hostagent_proto_rawDescGZIP(), []int{59}
|
||||
}
|
||||
|
||||
type StartBackgroundRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
SandboxId string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"`
|
||||
Cmd string `protobuf:"bytes,2,opt,name=cmd,proto3" json:"cmd,omitempty"`
|
||||
Args []string `protobuf:"bytes,3,rep,name=args,proto3" json:"args,omitempty"`
|
||||
// User-chosen tag for the process. If empty, the host agent generates one.
|
||||
Tag string `protobuf:"bytes,4,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||
Envs map[string]string `protobuf:"bytes,5,rep,name=envs,proto3" json:"envs,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
|
||||
Cwd string `protobuf:"bytes,6,opt,name=cwd,proto3" json:"cwd,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *StartBackgroundRequest) Reset() {
|
||||
*x = StartBackgroundRequest{}
|
||||
mi := &file_hostagent_proto_msgTypes[60]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *StartBackgroundRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*StartBackgroundRequest) ProtoMessage() {}
|
||||
|
||||
func (x *StartBackgroundRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_hostagent_proto_msgTypes[60]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use StartBackgroundRequest.ProtoReflect.Descriptor instead.
|
||||
func (*StartBackgroundRequest) Descriptor() ([]byte, []int) {
|
||||
return file_hostagent_proto_rawDescGZIP(), []int{60}
|
||||
}
|
||||
|
||||
func (x *StartBackgroundRequest) GetSandboxId() string {
|
||||
if x != nil {
|
||||
return x.SandboxId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *StartBackgroundRequest) GetCmd() string {
|
||||
if x != nil {
|
||||
return x.Cmd
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *StartBackgroundRequest) GetArgs() []string {
|
||||
if x != nil {
|
||||
return x.Args
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *StartBackgroundRequest) GetTag() string {
|
||||
if x != nil {
|
||||
return x.Tag
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *StartBackgroundRequest) GetEnvs() map[string]string {
|
||||
if x != nil {
|
||||
return x.Envs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *StartBackgroundRequest) GetCwd() string {
|
||||
if x != nil {
|
||||
return x.Cwd
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type StartBackgroundResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"`
|
||||
Tag string `protobuf:"bytes,2,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *StartBackgroundResponse) Reset() {
|
||||
*x = StartBackgroundResponse{}
|
||||
mi := &file_hostagent_proto_msgTypes[61]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *StartBackgroundResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*StartBackgroundResponse) ProtoMessage() {}
|
||||
|
||||
func (x *StartBackgroundResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_hostagent_proto_msgTypes[61]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use StartBackgroundResponse.ProtoReflect.Descriptor instead.
|
||||
func (*StartBackgroundResponse) Descriptor() ([]byte, []int) {
|
||||
return file_hostagent_proto_rawDescGZIP(), []int{61}
|
||||
}
|
||||
|
||||
func (x *StartBackgroundResponse) GetPid() uint32 {
|
||||
if x != nil {
|
||||
return x.Pid
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *StartBackgroundResponse) GetTag() string {
|
||||
if x != nil {
|
||||
return x.Tag
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ListProcessesRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
SandboxId string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ListProcessesRequest) Reset() {
|
||||
*x = ListProcessesRequest{}
|
||||
mi := &file_hostagent_proto_msgTypes[62]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListProcessesRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListProcessesRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ListProcessesRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_hostagent_proto_msgTypes[62]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ListProcessesRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ListProcessesRequest) Descriptor() ([]byte, []int) {
|
||||
return file_hostagent_proto_rawDescGZIP(), []int{62}
|
||||
}
|
||||
|
||||
func (x *ListProcessesRequest) GetSandboxId() string {
|
||||
if x != nil {
|
||||
return x.SandboxId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ProcessEntry struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"`
|
||||
Tag string `protobuf:"bytes,2,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||
Cmd string `protobuf:"bytes,3,opt,name=cmd,proto3" json:"cmd,omitempty"`
|
||||
Args []string `protobuf:"bytes,4,rep,name=args,proto3" json:"args,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ProcessEntry) Reset() {
|
||||
*x = ProcessEntry{}
|
||||
mi := &file_hostagent_proto_msgTypes[63]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ProcessEntry) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ProcessEntry) ProtoMessage() {}
|
||||
|
||||
func (x *ProcessEntry) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_hostagent_proto_msgTypes[63]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ProcessEntry.ProtoReflect.Descriptor instead.
|
||||
func (*ProcessEntry) Descriptor() ([]byte, []int) {
|
||||
return file_hostagent_proto_rawDescGZIP(), []int{63}
|
||||
}
|
||||
|
||||
func (x *ProcessEntry) GetPid() uint32 {
|
||||
if x != nil {
|
||||
return x.Pid
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ProcessEntry) GetTag() string {
|
||||
if x != nil {
|
||||
return x.Tag
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ProcessEntry) GetCmd() string {
|
||||
if x != nil {
|
||||
return x.Cmd
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ProcessEntry) GetArgs() []string {
|
||||
if x != nil {
|
||||
return x.Args
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ListProcessesResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Processes []*ProcessEntry `protobuf:"bytes,1,rep,name=processes,proto3" json:"processes,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ListProcessesResponse) Reset() {
|
||||
*x = ListProcessesResponse{}
|
||||
mi := &file_hostagent_proto_msgTypes[64]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListProcessesResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListProcessesResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ListProcessesResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_hostagent_proto_msgTypes[64]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ListProcessesResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ListProcessesResponse) Descriptor() ([]byte, []int) {
|
||||
return file_hostagent_proto_rawDescGZIP(), []int{64}
|
||||
}
|
||||
|
||||
func (x *ListProcessesResponse) GetProcesses() []*ProcessEntry {
|
||||
if x != nil {
|
||||
return x.Processes
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type KillProcessRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
SandboxId string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"`
|
||||
// Types that are valid to be assigned to Selector:
|
||||
//
|
||||
// *KillProcessRequest_Pid
|
||||
// *KillProcessRequest_Tag
|
||||
Selector isKillProcessRequest_Selector `protobuf_oneof:"selector"`
|
||||
// Signal to send: "SIGTERM" or "SIGKILL" (default: "SIGKILL").
|
||||
Signal string `protobuf:"bytes,4,opt,name=signal,proto3" json:"signal,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *KillProcessRequest) Reset() {
|
||||
*x = KillProcessRequest{}
|
||||
mi := &file_hostagent_proto_msgTypes[65]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *KillProcessRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*KillProcessRequest) ProtoMessage() {}
|
||||
|
||||
func (x *KillProcessRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_hostagent_proto_msgTypes[65]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use KillProcessRequest.ProtoReflect.Descriptor instead.
|
||||
func (*KillProcessRequest) Descriptor() ([]byte, []int) {
|
||||
return file_hostagent_proto_rawDescGZIP(), []int{65}
|
||||
}
|
||||
|
||||
func (x *KillProcessRequest) GetSandboxId() string {
|
||||
if x != nil {
|
||||
return x.SandboxId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *KillProcessRequest) GetSelector() isKillProcessRequest_Selector {
|
||||
if x != nil {
|
||||
return x.Selector
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *KillProcessRequest) GetPid() uint32 {
|
||||
if x != nil {
|
||||
if x, ok := x.Selector.(*KillProcessRequest_Pid); ok {
|
||||
return x.Pid
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *KillProcessRequest) GetTag() string {
|
||||
if x != nil {
|
||||
if x, ok := x.Selector.(*KillProcessRequest_Tag); ok {
|
||||
return x.Tag
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *KillProcessRequest) GetSignal() string {
|
||||
if x != nil {
|
||||
return x.Signal
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type isKillProcessRequest_Selector interface {
|
||||
isKillProcessRequest_Selector()
|
||||
}
|
||||
|
||||
type KillProcessRequest_Pid struct {
|
||||
Pid uint32 `protobuf:"varint,2,opt,name=pid,proto3,oneof"`
|
||||
}
|
||||
|
||||
type KillProcessRequest_Tag struct {
|
||||
Tag string `protobuf:"bytes,3,opt,name=tag,proto3,oneof"`
|
||||
}
|
||||
|
||||
func (*KillProcessRequest_Pid) isKillProcessRequest_Selector() {}
|
||||
|
||||
func (*KillProcessRequest_Tag) isKillProcessRequest_Selector() {}
|
||||
|
||||
type KillProcessResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *KillProcessResponse) Reset() {
|
||||
*x = KillProcessResponse{}
|
||||
mi := &file_hostagent_proto_msgTypes[66]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *KillProcessResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*KillProcessResponse) ProtoMessage() {}
|
||||
|
||||
func (x *KillProcessResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_hostagent_proto_msgTypes[66]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use KillProcessResponse.ProtoReflect.Descriptor instead.
|
||||
func (*KillProcessResponse) Descriptor() ([]byte, []int) {
|
||||
return file_hostagent_proto_rawDescGZIP(), []int{66}
|
||||
}
|
||||
|
||||
type ConnectProcessRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
SandboxId string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"`
|
||||
// Types that are valid to be assigned to Selector:
|
||||
//
|
||||
// *ConnectProcessRequest_Pid
|
||||
// *ConnectProcessRequest_Tag
|
||||
Selector isConnectProcessRequest_Selector `protobuf_oneof:"selector"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ConnectProcessRequest) Reset() {
|
||||
*x = ConnectProcessRequest{}
|
||||
mi := &file_hostagent_proto_msgTypes[67]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ConnectProcessRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ConnectProcessRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ConnectProcessRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_hostagent_proto_msgTypes[67]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ConnectProcessRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ConnectProcessRequest) Descriptor() ([]byte, []int) {
|
||||
return file_hostagent_proto_rawDescGZIP(), []int{67}
|
||||
}
|
||||
|
||||
func (x *ConnectProcessRequest) GetSandboxId() string {
|
||||
if x != nil {
|
||||
return x.SandboxId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ConnectProcessRequest) GetSelector() isConnectProcessRequest_Selector {
|
||||
if x != nil {
|
||||
return x.Selector
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ConnectProcessRequest) GetPid() uint32 {
|
||||
if x != nil {
|
||||
if x, ok := x.Selector.(*ConnectProcessRequest_Pid); ok {
|
||||
return x.Pid
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ConnectProcessRequest) GetTag() string {
|
||||
if x != nil {
|
||||
if x, ok := x.Selector.(*ConnectProcessRequest_Tag); ok {
|
||||
return x.Tag
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type isConnectProcessRequest_Selector interface {
|
||||
isConnectProcessRequest_Selector()
|
||||
}
|
||||
|
||||
type ConnectProcessRequest_Pid struct {
|
||||
Pid uint32 `protobuf:"varint,2,opt,name=pid,proto3,oneof"`
|
||||
}
|
||||
|
||||
type ConnectProcessRequest_Tag struct {
|
||||
Tag string `protobuf:"bytes,3,opt,name=tag,proto3,oneof"`
|
||||
}
|
||||
|
||||
func (*ConnectProcessRequest_Pid) isConnectProcessRequest_Selector() {}
|
||||
|
||||
func (*ConnectProcessRequest_Tag) isConnectProcessRequest_Selector() {}
|
||||
|
||||
// Reuses ExecStream event types for symmetry.
|
||||
type ConnectProcessResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// Types that are valid to be assigned to Event:
|
||||
//
|
||||
// *ConnectProcessResponse_Start
|
||||
// *ConnectProcessResponse_Data
|
||||
// *ConnectProcessResponse_End
|
||||
Event isConnectProcessResponse_Event `protobuf_oneof:"event"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ConnectProcessResponse) Reset() {
|
||||
*x = ConnectProcessResponse{}
|
||||
mi := &file_hostagent_proto_msgTypes[68]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ConnectProcessResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ConnectProcessResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ConnectProcessResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_hostagent_proto_msgTypes[68]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ConnectProcessResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ConnectProcessResponse) Descriptor() ([]byte, []int) {
|
||||
return file_hostagent_proto_rawDescGZIP(), []int{68}
|
||||
}
|
||||
|
||||
func (x *ConnectProcessResponse) GetEvent() isConnectProcessResponse_Event {
|
||||
if x != nil {
|
||||
return x.Event
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ConnectProcessResponse) GetStart() *ExecStreamStart {
|
||||
if x != nil {
|
||||
if x, ok := x.Event.(*ConnectProcessResponse_Start); ok {
|
||||
return x.Start
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ConnectProcessResponse) GetData() *ExecStreamData {
|
||||
if x != nil {
|
||||
if x, ok := x.Event.(*ConnectProcessResponse_Data); ok {
|
||||
return x.Data
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ConnectProcessResponse) GetEnd() *ExecStreamEnd {
|
||||
if x != nil {
|
||||
if x, ok := x.Event.(*ConnectProcessResponse_End); ok {
|
||||
return x.End
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type isConnectProcessResponse_Event interface {
|
||||
isConnectProcessResponse_Event()
|
||||
}
|
||||
|
||||
type ConnectProcessResponse_Start struct {
|
||||
Start *ExecStreamStart `protobuf:"bytes,1,opt,name=start,proto3,oneof"`
|
||||
}
|
||||
|
||||
type ConnectProcessResponse_Data struct {
|
||||
Data *ExecStreamData `protobuf:"bytes,2,opt,name=data,proto3,oneof"`
|
||||
}
|
||||
|
||||
type ConnectProcessResponse_End struct {
|
||||
End *ExecStreamEnd `protobuf:"bytes,3,opt,name=end,proto3,oneof"`
|
||||
}
|
||||
|
||||
func (*ConnectProcessResponse_Start) isConnectProcessResponse_Event() {}
|
||||
|
||||
func (*ConnectProcessResponse_Data) isConnectProcessResponse_Event() {}
|
||||
|
||||
func (*ConnectProcessResponse_End) isConnectProcessResponse_Event() {}
|
||||
|
||||
var File_hostagent_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_hostagent_proto_rawDesc = "" +
|
||||
@ -3725,7 +4342,52 @@ const file_hostagent_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"sandbox_id\x18\x01 \x01(\tR\tsandboxId\x12\x10\n" +
|
||||
"\x03tag\x18\x02 \x01(\tR\x03tag\"\x11\n" +
|
||||
"\x0fPtyKillResponse2\xe6\x10\n" +
|
||||
"\x0fPtyKillResponse\"\xfe\x01\n" +
|
||||
"\x16StartBackgroundRequest\x12\x1d\n" +
|
||||
"\n" +
|
||||
"sandbox_id\x18\x01 \x01(\tR\tsandboxId\x12\x10\n" +
|
||||
"\x03cmd\x18\x02 \x01(\tR\x03cmd\x12\x12\n" +
|
||||
"\x04args\x18\x03 \x03(\tR\x04args\x12\x10\n" +
|
||||
"\x03tag\x18\x04 \x01(\tR\x03tag\x12B\n" +
|
||||
"\x04envs\x18\x05 \x03(\v2..hostagent.v1.StartBackgroundRequest.EnvsEntryR\x04envs\x12\x10\n" +
|
||||
"\x03cwd\x18\x06 \x01(\tR\x03cwd\x1a7\n" +
|
||||
"\tEnvsEntry\x12\x10\n" +
|
||||
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
||||
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"=\n" +
|
||||
"\x17StartBackgroundResponse\x12\x10\n" +
|
||||
"\x03pid\x18\x01 \x01(\rR\x03pid\x12\x10\n" +
|
||||
"\x03tag\x18\x02 \x01(\tR\x03tag\"5\n" +
|
||||
"\x14ListProcessesRequest\x12\x1d\n" +
|
||||
"\n" +
|
||||
"sandbox_id\x18\x01 \x01(\tR\tsandboxId\"X\n" +
|
||||
"\fProcessEntry\x12\x10\n" +
|
||||
"\x03pid\x18\x01 \x01(\rR\x03pid\x12\x10\n" +
|
||||
"\x03tag\x18\x02 \x01(\tR\x03tag\x12\x10\n" +
|
||||
"\x03cmd\x18\x03 \x01(\tR\x03cmd\x12\x12\n" +
|
||||
"\x04args\x18\x04 \x03(\tR\x04args\"Q\n" +
|
||||
"\x15ListProcessesResponse\x128\n" +
|
||||
"\tprocesses\x18\x01 \x03(\v2\x1a.hostagent.v1.ProcessEntryR\tprocesses\"\x7f\n" +
|
||||
"\x12KillProcessRequest\x12\x1d\n" +
|
||||
"\n" +
|
||||
"sandbox_id\x18\x01 \x01(\tR\tsandboxId\x12\x12\n" +
|
||||
"\x03pid\x18\x02 \x01(\rH\x00R\x03pid\x12\x12\n" +
|
||||
"\x03tag\x18\x03 \x01(\tH\x00R\x03tag\x12\x16\n" +
|
||||
"\x06signal\x18\x04 \x01(\tR\x06signalB\n" +
|
||||
"\n" +
|
||||
"\bselector\"\x15\n" +
|
||||
"\x13KillProcessResponse\"j\n" +
|
||||
"\x15ConnectProcessRequest\x12\x1d\n" +
|
||||
"\n" +
|
||||
"sandbox_id\x18\x01 \x01(\tR\tsandboxId\x12\x12\n" +
|
||||
"\x03pid\x18\x02 \x01(\rH\x00R\x03pid\x12\x12\n" +
|
||||
"\x03tag\x18\x03 \x01(\tH\x00R\x03tagB\n" +
|
||||
"\n" +
|
||||
"\bselector\"\xbd\x01\n" +
|
||||
"\x16ConnectProcessResponse\x125\n" +
|
||||
"\x05start\x18\x01 \x01(\v2\x1d.hostagent.v1.ExecStreamStartH\x00R\x05start\x122\n" +
|
||||
"\x04data\x18\x02 \x01(\v2\x1c.hostagent.v1.ExecStreamDataH\x00R\x04data\x12/\n" +
|
||||
"\x03end\x18\x03 \x01(\v2\x1b.hostagent.v1.ExecStreamEndH\x00R\x03endB\a\n" +
|
||||
"\x05event2\xd3\x13\n" +
|
||||
"\x10HostAgentService\x12X\n" +
|
||||
"\rCreateSandbox\x12\".hostagent.v1.CreateSandboxRequest\x1a#.hostagent.v1.CreateSandboxResponse\x12[\n" +
|
||||
"\x0eDestroySandbox\x12#.hostagent.v1.DestroySandboxRequest\x1a$.hostagent.v1.DestroySandboxResponse\x12U\n" +
|
||||
@ -3753,7 +4415,11 @@ const file_hostagent_proto_rawDesc = "" +
|
||||
"\tPtyAttach\x12\x1e.hostagent.v1.PtyAttachRequest\x1a\x1f.hostagent.v1.PtyAttachResponse0\x01\x12U\n" +
|
||||
"\fPtySendInput\x12!.hostagent.v1.PtySendInputRequest\x1a\".hostagent.v1.PtySendInputResponse\x12L\n" +
|
||||
"\tPtyResize\x12\x1e.hostagent.v1.PtyResizeRequest\x1a\x1f.hostagent.v1.PtyResizeResponse\x12F\n" +
|
||||
"\aPtyKill\x12\x1c.hostagent.v1.PtyKillRequest\x1a\x1d.hostagent.v1.PtyKillResponseB\xae\x01\n" +
|
||||
"\aPtyKill\x12\x1c.hostagent.v1.PtyKillRequest\x1a\x1d.hostagent.v1.PtyKillResponse\x12^\n" +
|
||||
"\x0fStartBackground\x12$.hostagent.v1.StartBackgroundRequest\x1a%.hostagent.v1.StartBackgroundResponse\x12X\n" +
|
||||
"\rListProcesses\x12\".hostagent.v1.ListProcessesRequest\x1a#.hostagent.v1.ListProcessesResponse\x12R\n" +
|
||||
"\vKillProcess\x12 .hostagent.v1.KillProcessRequest\x1a!.hostagent.v1.KillProcessResponse\x12]\n" +
|
||||
"\x0eConnectProcess\x12#.hostagent.v1.ConnectProcessRequest\x1a$.hostagent.v1.ConnectProcessResponse0\x01B\xae\x01\n" +
|
||||
"\x10com.hostagent.v1B\x0eHostagentProtoP\x01Z9git.omukk.dev/wrenn/wrenn/proto/hostagent/gen;hostagentv1\xa2\x02\x03HXX\xaa\x02\fHostagent.V1\xca\x02\fHostagent\\V1\xe2\x02\x18Hostagent\\V1\\GPBMetadata\xea\x02\rHostagent::V1b\x06proto3"
|
||||
|
||||
var (
|
||||
@ -3768,7 +4434,7 @@ func file_hostagent_proto_rawDescGZIP() []byte {
|
||||
return file_hostagent_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_hostagent_proto_msgTypes = make([]protoimpl.MessageInfo, 63)
|
||||
var file_hostagent_proto_msgTypes = make([]protoimpl.MessageInfo, 73)
|
||||
var file_hostagent_proto_goTypes = []any{
|
||||
(*CreateSandboxRequest)(nil), // 0: hostagent.v1.CreateSandboxRequest
|
||||
(*CreateSandboxResponse)(nil), // 1: hostagent.v1.CreateSandboxResponse
|
||||
@ -3830,13 +4496,23 @@ var file_hostagent_proto_goTypes = []any{
|
||||
(*PtyResizeResponse)(nil), // 57: hostagent.v1.PtyResizeResponse
|
||||
(*PtyKillRequest)(nil), // 58: hostagent.v1.PtyKillRequest
|
||||
(*PtyKillResponse)(nil), // 59: hostagent.v1.PtyKillResponse
|
||||
nil, // 60: hostagent.v1.CreateSandboxRequest.DefaultEnvEntry
|
||||
nil, // 61: hostagent.v1.ResumeSandboxRequest.DefaultEnvEntry
|
||||
nil, // 62: hostagent.v1.PtyAttachRequest.EnvsEntry
|
||||
(*StartBackgroundRequest)(nil), // 60: hostagent.v1.StartBackgroundRequest
|
||||
(*StartBackgroundResponse)(nil), // 61: hostagent.v1.StartBackgroundResponse
|
||||
(*ListProcessesRequest)(nil), // 62: hostagent.v1.ListProcessesRequest
|
||||
(*ProcessEntry)(nil), // 63: hostagent.v1.ProcessEntry
|
||||
(*ListProcessesResponse)(nil), // 64: hostagent.v1.ListProcessesResponse
|
||||
(*KillProcessRequest)(nil), // 65: hostagent.v1.KillProcessRequest
|
||||
(*KillProcessResponse)(nil), // 66: hostagent.v1.KillProcessResponse
|
||||
(*ConnectProcessRequest)(nil), // 67: hostagent.v1.ConnectProcessRequest
|
||||
(*ConnectProcessResponse)(nil), // 68: hostagent.v1.ConnectProcessResponse
|
||||
nil, // 69: hostagent.v1.CreateSandboxRequest.DefaultEnvEntry
|
||||
nil, // 70: hostagent.v1.ResumeSandboxRequest.DefaultEnvEntry
|
||||
nil, // 71: hostagent.v1.PtyAttachRequest.EnvsEntry
|
||||
nil, // 72: hostagent.v1.StartBackgroundRequest.EnvsEntry
|
||||
}
|
||||
var file_hostagent_proto_depIdxs = []int32{
|
||||
60, // 0: hostagent.v1.CreateSandboxRequest.default_env:type_name -> hostagent.v1.CreateSandboxRequest.DefaultEnvEntry
|
||||
61, // 1: hostagent.v1.ResumeSandboxRequest.default_env:type_name -> hostagent.v1.ResumeSandboxRequest.DefaultEnvEntry
|
||||
69, // 0: hostagent.v1.CreateSandboxRequest.default_env:type_name -> hostagent.v1.CreateSandboxRequest.DefaultEnvEntry
|
||||
70, // 1: hostagent.v1.ResumeSandboxRequest.default_env:type_name -> hostagent.v1.ResumeSandboxRequest.DefaultEnvEntry
|
||||
16, // 2: hostagent.v1.ListSandboxesResponse.sandboxes:type_name -> hostagent.v1.SandboxInfo
|
||||
23, // 3: hostagent.v1.ExecStreamResponse.start:type_name -> hostagent.v1.ExecStreamStart
|
||||
24, // 4: hostagent.v1.ExecStreamResponse.data:type_name -> hostagent.v1.ExecStreamData
|
||||
@ -3848,65 +4524,78 @@ var file_hostagent_proto_depIdxs = []int32{
|
||||
42, // 10: hostagent.v1.FlushSandboxMetricsResponse.points_10m:type_name -> hostagent.v1.MetricPoint
|
||||
42, // 11: hostagent.v1.FlushSandboxMetricsResponse.points_2h:type_name -> hostagent.v1.MetricPoint
|
||||
42, // 12: hostagent.v1.FlushSandboxMetricsResponse.points_24h:type_name -> hostagent.v1.MetricPoint
|
||||
62, // 13: hostagent.v1.PtyAttachRequest.envs:type_name -> hostagent.v1.PtyAttachRequest.EnvsEntry
|
||||
71, // 13: hostagent.v1.PtyAttachRequest.envs:type_name -> hostagent.v1.PtyAttachRequest.EnvsEntry
|
||||
51, // 14: hostagent.v1.PtyAttachResponse.started:type_name -> hostagent.v1.PtyStarted
|
||||
52, // 15: hostagent.v1.PtyAttachResponse.output:type_name -> hostagent.v1.PtyOutput
|
||||
53, // 16: hostagent.v1.PtyAttachResponse.exited:type_name -> hostagent.v1.PtyExited
|
||||
0, // 17: hostagent.v1.HostAgentService.CreateSandbox:input_type -> hostagent.v1.CreateSandboxRequest
|
||||
2, // 18: hostagent.v1.HostAgentService.DestroySandbox:input_type -> hostagent.v1.DestroySandboxRequest
|
||||
4, // 19: hostagent.v1.HostAgentService.PauseSandbox:input_type -> hostagent.v1.PauseSandboxRequest
|
||||
6, // 20: hostagent.v1.HostAgentService.ResumeSandbox:input_type -> hostagent.v1.ResumeSandboxRequest
|
||||
12, // 21: hostagent.v1.HostAgentService.Exec:input_type -> hostagent.v1.ExecRequest
|
||||
14, // 22: hostagent.v1.HostAgentService.ListSandboxes:input_type -> hostagent.v1.ListSandboxesRequest
|
||||
17, // 23: hostagent.v1.HostAgentService.WriteFile:input_type -> hostagent.v1.WriteFileRequest
|
||||
19, // 24: hostagent.v1.HostAgentService.ReadFile:input_type -> hostagent.v1.ReadFileRequest
|
||||
31, // 25: hostagent.v1.HostAgentService.ListDir:input_type -> hostagent.v1.ListDirRequest
|
||||
34, // 26: hostagent.v1.HostAgentService.MakeDir:input_type -> hostagent.v1.MakeDirRequest
|
||||
36, // 27: hostagent.v1.HostAgentService.RemovePath:input_type -> hostagent.v1.RemovePathRequest
|
||||
8, // 28: hostagent.v1.HostAgentService.CreateSnapshot:input_type -> hostagent.v1.CreateSnapshotRequest
|
||||
10, // 29: hostagent.v1.HostAgentService.DeleteSnapshot:input_type -> hostagent.v1.DeleteSnapshotRequest
|
||||
21, // 30: hostagent.v1.HostAgentService.ExecStream:input_type -> hostagent.v1.ExecStreamRequest
|
||||
26, // 31: hostagent.v1.HostAgentService.WriteFileStream:input_type -> hostagent.v1.WriteFileStreamRequest
|
||||
29, // 32: hostagent.v1.HostAgentService.ReadFileStream:input_type -> hostagent.v1.ReadFileStreamRequest
|
||||
38, // 33: hostagent.v1.HostAgentService.PingSandbox:input_type -> hostagent.v1.PingSandboxRequest
|
||||
40, // 34: hostagent.v1.HostAgentService.Terminate:input_type -> hostagent.v1.TerminateRequest
|
||||
43, // 35: hostagent.v1.HostAgentService.GetSandboxMetrics:input_type -> hostagent.v1.GetSandboxMetricsRequest
|
||||
45, // 36: hostagent.v1.HostAgentService.FlushSandboxMetrics:input_type -> hostagent.v1.FlushSandboxMetricsRequest
|
||||
47, // 37: hostagent.v1.HostAgentService.FlattenRootfs:input_type -> hostagent.v1.FlattenRootfsRequest
|
||||
49, // 38: hostagent.v1.HostAgentService.PtyAttach:input_type -> hostagent.v1.PtyAttachRequest
|
||||
54, // 39: hostagent.v1.HostAgentService.PtySendInput:input_type -> hostagent.v1.PtySendInputRequest
|
||||
56, // 40: hostagent.v1.HostAgentService.PtyResize:input_type -> hostagent.v1.PtyResizeRequest
|
||||
58, // 41: hostagent.v1.HostAgentService.PtyKill:input_type -> hostagent.v1.PtyKillRequest
|
||||
1, // 42: hostagent.v1.HostAgentService.CreateSandbox:output_type -> hostagent.v1.CreateSandboxResponse
|
||||
3, // 43: hostagent.v1.HostAgentService.DestroySandbox:output_type -> hostagent.v1.DestroySandboxResponse
|
||||
5, // 44: hostagent.v1.HostAgentService.PauseSandbox:output_type -> hostagent.v1.PauseSandboxResponse
|
||||
7, // 45: hostagent.v1.HostAgentService.ResumeSandbox:output_type -> hostagent.v1.ResumeSandboxResponse
|
||||
13, // 46: hostagent.v1.HostAgentService.Exec:output_type -> hostagent.v1.ExecResponse
|
||||
15, // 47: hostagent.v1.HostAgentService.ListSandboxes:output_type -> hostagent.v1.ListSandboxesResponse
|
||||
18, // 48: hostagent.v1.HostAgentService.WriteFile:output_type -> hostagent.v1.WriteFileResponse
|
||||
20, // 49: hostagent.v1.HostAgentService.ReadFile:output_type -> hostagent.v1.ReadFileResponse
|
||||
32, // 50: hostagent.v1.HostAgentService.ListDir:output_type -> hostagent.v1.ListDirResponse
|
||||
35, // 51: hostagent.v1.HostAgentService.MakeDir:output_type -> hostagent.v1.MakeDirResponse
|
||||
37, // 52: hostagent.v1.HostAgentService.RemovePath:output_type -> hostagent.v1.RemovePathResponse
|
||||
9, // 53: hostagent.v1.HostAgentService.CreateSnapshot:output_type -> hostagent.v1.CreateSnapshotResponse
|
||||
11, // 54: hostagent.v1.HostAgentService.DeleteSnapshot:output_type -> hostagent.v1.DeleteSnapshotResponse
|
||||
22, // 55: hostagent.v1.HostAgentService.ExecStream:output_type -> hostagent.v1.ExecStreamResponse
|
||||
28, // 56: hostagent.v1.HostAgentService.WriteFileStream:output_type -> hostagent.v1.WriteFileStreamResponse
|
||||
30, // 57: hostagent.v1.HostAgentService.ReadFileStream:output_type -> hostagent.v1.ReadFileStreamResponse
|
||||
39, // 58: hostagent.v1.HostAgentService.PingSandbox:output_type -> hostagent.v1.PingSandboxResponse
|
||||
41, // 59: hostagent.v1.HostAgentService.Terminate:output_type -> hostagent.v1.TerminateResponse
|
||||
44, // 60: hostagent.v1.HostAgentService.GetSandboxMetrics:output_type -> hostagent.v1.GetSandboxMetricsResponse
|
||||
46, // 61: hostagent.v1.HostAgentService.FlushSandboxMetrics:output_type -> hostagent.v1.FlushSandboxMetricsResponse
|
||||
48, // 62: hostagent.v1.HostAgentService.FlattenRootfs:output_type -> hostagent.v1.FlattenRootfsResponse
|
||||
50, // 63: hostagent.v1.HostAgentService.PtyAttach:output_type -> hostagent.v1.PtyAttachResponse
|
||||
55, // 64: hostagent.v1.HostAgentService.PtySendInput:output_type -> hostagent.v1.PtySendInputResponse
|
||||
57, // 65: hostagent.v1.HostAgentService.PtyResize:output_type -> hostagent.v1.PtyResizeResponse
|
||||
59, // 66: hostagent.v1.HostAgentService.PtyKill:output_type -> hostagent.v1.PtyKillResponse
|
||||
42, // [42:67] is the sub-list for method output_type
|
||||
17, // [17:42] is the sub-list for method input_type
|
||||
17, // [17:17] is the sub-list for extension type_name
|
||||
17, // [17:17] is the sub-list for extension extendee
|
||||
0, // [0:17] is the sub-list for field type_name
|
||||
72, // 17: hostagent.v1.StartBackgroundRequest.envs:type_name -> hostagent.v1.StartBackgroundRequest.EnvsEntry
|
||||
63, // 18: hostagent.v1.ListProcessesResponse.processes:type_name -> hostagent.v1.ProcessEntry
|
||||
23, // 19: hostagent.v1.ConnectProcessResponse.start:type_name -> hostagent.v1.ExecStreamStart
|
||||
24, // 20: hostagent.v1.ConnectProcessResponse.data:type_name -> hostagent.v1.ExecStreamData
|
||||
25, // 21: hostagent.v1.ConnectProcessResponse.end:type_name -> hostagent.v1.ExecStreamEnd
|
||||
0, // 22: hostagent.v1.HostAgentService.CreateSandbox:input_type -> hostagent.v1.CreateSandboxRequest
|
||||
2, // 23: hostagent.v1.HostAgentService.DestroySandbox:input_type -> hostagent.v1.DestroySandboxRequest
|
||||
4, // 24: hostagent.v1.HostAgentService.PauseSandbox:input_type -> hostagent.v1.PauseSandboxRequest
|
||||
6, // 25: hostagent.v1.HostAgentService.ResumeSandbox:input_type -> hostagent.v1.ResumeSandboxRequest
|
||||
12, // 26: hostagent.v1.HostAgentService.Exec:input_type -> hostagent.v1.ExecRequest
|
||||
14, // 27: hostagent.v1.HostAgentService.ListSandboxes:input_type -> hostagent.v1.ListSandboxesRequest
|
||||
17, // 28: hostagent.v1.HostAgentService.WriteFile:input_type -> hostagent.v1.WriteFileRequest
|
||||
19, // 29: hostagent.v1.HostAgentService.ReadFile:input_type -> hostagent.v1.ReadFileRequest
|
||||
31, // 30: hostagent.v1.HostAgentService.ListDir:input_type -> hostagent.v1.ListDirRequest
|
||||
34, // 31: hostagent.v1.HostAgentService.MakeDir:input_type -> hostagent.v1.MakeDirRequest
|
||||
36, // 32: hostagent.v1.HostAgentService.RemovePath:input_type -> hostagent.v1.RemovePathRequest
|
||||
8, // 33: hostagent.v1.HostAgentService.CreateSnapshot:input_type -> hostagent.v1.CreateSnapshotRequest
|
||||
10, // 34: hostagent.v1.HostAgentService.DeleteSnapshot:input_type -> hostagent.v1.DeleteSnapshotRequest
|
||||
21, // 35: hostagent.v1.HostAgentService.ExecStream:input_type -> hostagent.v1.ExecStreamRequest
|
||||
26, // 36: hostagent.v1.HostAgentService.WriteFileStream:input_type -> hostagent.v1.WriteFileStreamRequest
|
||||
29, // 37: hostagent.v1.HostAgentService.ReadFileStream:input_type -> hostagent.v1.ReadFileStreamRequest
|
||||
38, // 38: hostagent.v1.HostAgentService.PingSandbox:input_type -> hostagent.v1.PingSandboxRequest
|
||||
40, // 39: hostagent.v1.HostAgentService.Terminate:input_type -> hostagent.v1.TerminateRequest
|
||||
43, // 40: hostagent.v1.HostAgentService.GetSandboxMetrics:input_type -> hostagent.v1.GetSandboxMetricsRequest
|
||||
45, // 41: hostagent.v1.HostAgentService.FlushSandboxMetrics:input_type -> hostagent.v1.FlushSandboxMetricsRequest
|
||||
47, // 42: hostagent.v1.HostAgentService.FlattenRootfs:input_type -> hostagent.v1.FlattenRootfsRequest
|
||||
49, // 43: hostagent.v1.HostAgentService.PtyAttach:input_type -> hostagent.v1.PtyAttachRequest
|
||||
54, // 44: hostagent.v1.HostAgentService.PtySendInput:input_type -> hostagent.v1.PtySendInputRequest
|
||||
56, // 45: hostagent.v1.HostAgentService.PtyResize:input_type -> hostagent.v1.PtyResizeRequest
|
||||
58, // 46: hostagent.v1.HostAgentService.PtyKill:input_type -> hostagent.v1.PtyKillRequest
|
||||
60, // 47: hostagent.v1.HostAgentService.StartBackground:input_type -> hostagent.v1.StartBackgroundRequest
|
||||
62, // 48: hostagent.v1.HostAgentService.ListProcesses:input_type -> hostagent.v1.ListProcessesRequest
|
||||
65, // 49: hostagent.v1.HostAgentService.KillProcess:input_type -> hostagent.v1.KillProcessRequest
|
||||
67, // 50: hostagent.v1.HostAgentService.ConnectProcess:input_type -> hostagent.v1.ConnectProcessRequest
|
||||
1, // 51: hostagent.v1.HostAgentService.CreateSandbox:output_type -> hostagent.v1.CreateSandboxResponse
|
||||
3, // 52: hostagent.v1.HostAgentService.DestroySandbox:output_type -> hostagent.v1.DestroySandboxResponse
|
||||
5, // 53: hostagent.v1.HostAgentService.PauseSandbox:output_type -> hostagent.v1.PauseSandboxResponse
|
||||
7, // 54: hostagent.v1.HostAgentService.ResumeSandbox:output_type -> hostagent.v1.ResumeSandboxResponse
|
||||
13, // 55: hostagent.v1.HostAgentService.Exec:output_type -> hostagent.v1.ExecResponse
|
||||
15, // 56: hostagent.v1.HostAgentService.ListSandboxes:output_type -> hostagent.v1.ListSandboxesResponse
|
||||
18, // 57: hostagent.v1.HostAgentService.WriteFile:output_type -> hostagent.v1.WriteFileResponse
|
||||
20, // 58: hostagent.v1.HostAgentService.ReadFile:output_type -> hostagent.v1.ReadFileResponse
|
||||
32, // 59: hostagent.v1.HostAgentService.ListDir:output_type -> hostagent.v1.ListDirResponse
|
||||
35, // 60: hostagent.v1.HostAgentService.MakeDir:output_type -> hostagent.v1.MakeDirResponse
|
||||
37, // 61: hostagent.v1.HostAgentService.RemovePath:output_type -> hostagent.v1.RemovePathResponse
|
||||
9, // 62: hostagent.v1.HostAgentService.CreateSnapshot:output_type -> hostagent.v1.CreateSnapshotResponse
|
||||
11, // 63: hostagent.v1.HostAgentService.DeleteSnapshot:output_type -> hostagent.v1.DeleteSnapshotResponse
|
||||
22, // 64: hostagent.v1.HostAgentService.ExecStream:output_type -> hostagent.v1.ExecStreamResponse
|
||||
28, // 65: hostagent.v1.HostAgentService.WriteFileStream:output_type -> hostagent.v1.WriteFileStreamResponse
|
||||
30, // 66: hostagent.v1.HostAgentService.ReadFileStream:output_type -> hostagent.v1.ReadFileStreamResponse
|
||||
39, // 67: hostagent.v1.HostAgentService.PingSandbox:output_type -> hostagent.v1.PingSandboxResponse
|
||||
41, // 68: hostagent.v1.HostAgentService.Terminate:output_type -> hostagent.v1.TerminateResponse
|
||||
44, // 69: hostagent.v1.HostAgentService.GetSandboxMetrics:output_type -> hostagent.v1.GetSandboxMetricsResponse
|
||||
46, // 70: hostagent.v1.HostAgentService.FlushSandboxMetrics:output_type -> hostagent.v1.FlushSandboxMetricsResponse
|
||||
48, // 71: hostagent.v1.HostAgentService.FlattenRootfs:output_type -> hostagent.v1.FlattenRootfsResponse
|
||||
50, // 72: hostagent.v1.HostAgentService.PtyAttach:output_type -> hostagent.v1.PtyAttachResponse
|
||||
55, // 73: hostagent.v1.HostAgentService.PtySendInput:output_type -> hostagent.v1.PtySendInputResponse
|
||||
57, // 74: hostagent.v1.HostAgentService.PtyResize:output_type -> hostagent.v1.PtyResizeResponse
|
||||
59, // 75: hostagent.v1.HostAgentService.PtyKill:output_type -> hostagent.v1.PtyKillResponse
|
||||
61, // 76: hostagent.v1.HostAgentService.StartBackground:output_type -> hostagent.v1.StartBackgroundResponse
|
||||
64, // 77: hostagent.v1.HostAgentService.ListProcesses:output_type -> hostagent.v1.ListProcessesResponse
|
||||
66, // 78: hostagent.v1.HostAgentService.KillProcess:output_type -> hostagent.v1.KillProcessResponse
|
||||
68, // 79: hostagent.v1.HostAgentService.ConnectProcess:output_type -> hostagent.v1.ConnectProcessResponse
|
||||
51, // [51:80] is the sub-list for method output_type
|
||||
22, // [22:51] is the sub-list for method input_type
|
||||
22, // [22:22] is the sub-list for extension type_name
|
||||
22, // [22:22] is the sub-list for extension extendee
|
||||
0, // [0:22] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_hostagent_proto_init() }
|
||||
@ -3933,13 +4622,26 @@ func file_hostagent_proto_init() {
|
||||
(*PtyAttachResponse_Output)(nil),
|
||||
(*PtyAttachResponse_Exited)(nil),
|
||||
}
|
||||
file_hostagent_proto_msgTypes[65].OneofWrappers = []any{
|
||||
(*KillProcessRequest_Pid)(nil),
|
||||
(*KillProcessRequest_Tag)(nil),
|
||||
}
|
||||
file_hostagent_proto_msgTypes[67].OneofWrappers = []any{
|
||||
(*ConnectProcessRequest_Pid)(nil),
|
||||
(*ConnectProcessRequest_Tag)(nil),
|
||||
}
|
||||
file_hostagent_proto_msgTypes[68].OneofWrappers = []any{
|
||||
(*ConnectProcessResponse_Start)(nil),
|
||||
(*ConnectProcessResponse_Data)(nil),
|
||||
(*ConnectProcessResponse_End)(nil),
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_hostagent_proto_rawDesc), len(file_hostagent_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 63,
|
||||
NumMessages: 73,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
|
||||
@ -107,6 +107,18 @@ const (
|
||||
// HostAgentServicePtyKillProcedure is the fully-qualified name of the HostAgentService's PtyKill
|
||||
// RPC.
|
||||
HostAgentServicePtyKillProcedure = "/hostagent.v1.HostAgentService/PtyKill"
|
||||
// HostAgentServiceStartBackgroundProcedure is the fully-qualified name of the HostAgentService's
|
||||
// StartBackground RPC.
|
||||
HostAgentServiceStartBackgroundProcedure = "/hostagent.v1.HostAgentService/StartBackground"
|
||||
// HostAgentServiceListProcessesProcedure is the fully-qualified name of the HostAgentService's
|
||||
// ListProcesses RPC.
|
||||
HostAgentServiceListProcessesProcedure = "/hostagent.v1.HostAgentService/ListProcesses"
|
||||
// HostAgentServiceKillProcessProcedure is the fully-qualified name of the HostAgentService's
|
||||
// KillProcess RPC.
|
||||
HostAgentServiceKillProcessProcedure = "/hostagent.v1.HostAgentService/KillProcess"
|
||||
// HostAgentServiceConnectProcessProcedure is the fully-qualified name of the HostAgentService's
|
||||
// ConnectProcess RPC.
|
||||
HostAgentServiceConnectProcessProcedure = "/hostagent.v1.HostAgentService/ConnectProcess"
|
||||
)
|
||||
|
||||
// HostAgentServiceClient is a client for the hostagent.v1.HostAgentService service.
|
||||
@ -172,6 +184,15 @@ type HostAgentServiceClient interface {
|
||||
PtyResize(context.Context, *connect.Request[gen.PtyResizeRequest]) (*connect.Response[gen.PtyResizeResponse], error)
|
||||
// PtyKill sends a signal to a PTY process.
|
||||
PtyKill(context.Context, *connect.Request[gen.PtyKillRequest]) (*connect.Response[gen.PtyKillResponse], error)
|
||||
// StartBackground starts a process in the background and returns immediately
|
||||
// with the PID and tag. The process survives RPC disconnection.
|
||||
StartBackground(context.Context, *connect.Request[gen.StartBackgroundRequest]) (*connect.Response[gen.StartBackgroundResponse], error)
|
||||
// ListProcesses returns all running processes inside a sandbox.
|
||||
ListProcesses(context.Context, *connect.Request[gen.ListProcessesRequest]) (*connect.Response[gen.ListProcessesResponse], error)
|
||||
// KillProcess sends a signal to a process identified by PID or tag.
|
||||
KillProcess(context.Context, *connect.Request[gen.KillProcessRequest]) (*connect.Response[gen.KillProcessResponse], error)
|
||||
// ConnectProcess re-attaches to a running process and streams its output.
|
||||
ConnectProcess(context.Context, *connect.Request[gen.ConnectProcessRequest]) (*connect.ServerStreamForClient[gen.ConnectProcessResponse], error)
|
||||
}
|
||||
|
||||
// NewHostAgentServiceClient constructs a client for the hostagent.v1.HostAgentService service. By
|
||||
@ -335,6 +356,30 @@ func NewHostAgentServiceClient(httpClient connect.HTTPClient, baseURL string, op
|
||||
connect.WithSchema(hostAgentServiceMethods.ByName("PtyKill")),
|
||||
connect.WithClientOptions(opts...),
|
||||
),
|
||||
startBackground: connect.NewClient[gen.StartBackgroundRequest, gen.StartBackgroundResponse](
|
||||
httpClient,
|
||||
baseURL+HostAgentServiceStartBackgroundProcedure,
|
||||
connect.WithSchema(hostAgentServiceMethods.ByName("StartBackground")),
|
||||
connect.WithClientOptions(opts...),
|
||||
),
|
||||
listProcesses: connect.NewClient[gen.ListProcessesRequest, gen.ListProcessesResponse](
|
||||
httpClient,
|
||||
baseURL+HostAgentServiceListProcessesProcedure,
|
||||
connect.WithSchema(hostAgentServiceMethods.ByName("ListProcesses")),
|
||||
connect.WithClientOptions(opts...),
|
||||
),
|
||||
killProcess: connect.NewClient[gen.KillProcessRequest, gen.KillProcessResponse](
|
||||
httpClient,
|
||||
baseURL+HostAgentServiceKillProcessProcedure,
|
||||
connect.WithSchema(hostAgentServiceMethods.ByName("KillProcess")),
|
||||
connect.WithClientOptions(opts...),
|
||||
),
|
||||
connectProcess: connect.NewClient[gen.ConnectProcessRequest, gen.ConnectProcessResponse](
|
||||
httpClient,
|
||||
baseURL+HostAgentServiceConnectProcessProcedure,
|
||||
connect.WithSchema(hostAgentServiceMethods.ByName("ConnectProcess")),
|
||||
connect.WithClientOptions(opts...),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@ -365,6 +410,10 @@ type hostAgentServiceClient struct {
|
||||
ptySendInput *connect.Client[gen.PtySendInputRequest, gen.PtySendInputResponse]
|
||||
ptyResize *connect.Client[gen.PtyResizeRequest, gen.PtyResizeResponse]
|
||||
ptyKill *connect.Client[gen.PtyKillRequest, gen.PtyKillResponse]
|
||||
startBackground *connect.Client[gen.StartBackgroundRequest, gen.StartBackgroundResponse]
|
||||
listProcesses *connect.Client[gen.ListProcessesRequest, gen.ListProcessesResponse]
|
||||
killProcess *connect.Client[gen.KillProcessRequest, gen.KillProcessResponse]
|
||||
connectProcess *connect.Client[gen.ConnectProcessRequest, gen.ConnectProcessResponse]
|
||||
}
|
||||
|
||||
// CreateSandbox calls hostagent.v1.HostAgentService.CreateSandbox.
|
||||
@ -492,6 +541,26 @@ func (c *hostAgentServiceClient) PtyKill(ctx context.Context, req *connect.Reque
|
||||
return c.ptyKill.CallUnary(ctx, req)
|
||||
}
|
||||
|
||||
// StartBackground calls hostagent.v1.HostAgentService.StartBackground.
|
||||
func (c *hostAgentServiceClient) StartBackground(ctx context.Context, req *connect.Request[gen.StartBackgroundRequest]) (*connect.Response[gen.StartBackgroundResponse], error) {
|
||||
return c.startBackground.CallUnary(ctx, req)
|
||||
}
|
||||
|
||||
// ListProcesses calls hostagent.v1.HostAgentService.ListProcesses.
|
||||
func (c *hostAgentServiceClient) ListProcesses(ctx context.Context, req *connect.Request[gen.ListProcessesRequest]) (*connect.Response[gen.ListProcessesResponse], error) {
|
||||
return c.listProcesses.CallUnary(ctx, req)
|
||||
}
|
||||
|
||||
// KillProcess calls hostagent.v1.HostAgentService.KillProcess.
|
||||
func (c *hostAgentServiceClient) KillProcess(ctx context.Context, req *connect.Request[gen.KillProcessRequest]) (*connect.Response[gen.KillProcessResponse], error) {
|
||||
return c.killProcess.CallUnary(ctx, req)
|
||||
}
|
||||
|
||||
// ConnectProcess calls hostagent.v1.HostAgentService.ConnectProcess.
|
||||
func (c *hostAgentServiceClient) ConnectProcess(ctx context.Context, req *connect.Request[gen.ConnectProcessRequest]) (*connect.ServerStreamForClient[gen.ConnectProcessResponse], error) {
|
||||
return c.connectProcess.CallServerStream(ctx, req)
|
||||
}
|
||||
|
||||
// HostAgentServiceHandler is an implementation of the hostagent.v1.HostAgentService service.
|
||||
type HostAgentServiceHandler interface {
|
||||
// CreateSandbox boots a new microVM with the given configuration.
|
||||
@ -555,6 +624,15 @@ type HostAgentServiceHandler interface {
|
||||
PtyResize(context.Context, *connect.Request[gen.PtyResizeRequest]) (*connect.Response[gen.PtyResizeResponse], error)
|
||||
// PtyKill sends a signal to a PTY process.
|
||||
PtyKill(context.Context, *connect.Request[gen.PtyKillRequest]) (*connect.Response[gen.PtyKillResponse], error)
|
||||
// StartBackground starts a process in the background and returns immediately
|
||||
// with the PID and tag. The process survives RPC disconnection.
|
||||
StartBackground(context.Context, *connect.Request[gen.StartBackgroundRequest]) (*connect.Response[gen.StartBackgroundResponse], error)
|
||||
// ListProcesses returns all running processes inside a sandbox.
|
||||
ListProcesses(context.Context, *connect.Request[gen.ListProcessesRequest]) (*connect.Response[gen.ListProcessesResponse], error)
|
||||
// KillProcess sends a signal to a process identified by PID or tag.
|
||||
KillProcess(context.Context, *connect.Request[gen.KillProcessRequest]) (*connect.Response[gen.KillProcessResponse], error)
|
||||
// ConnectProcess re-attaches to a running process and streams its output.
|
||||
ConnectProcess(context.Context, *connect.Request[gen.ConnectProcessRequest], *connect.ServerStream[gen.ConnectProcessResponse]) error
|
||||
}
|
||||
|
||||
// NewHostAgentServiceHandler builds an HTTP handler from the service implementation. It returns the
|
||||
@ -714,6 +792,30 @@ func NewHostAgentServiceHandler(svc HostAgentServiceHandler, opts ...connect.Han
|
||||
connect.WithSchema(hostAgentServiceMethods.ByName("PtyKill")),
|
||||
connect.WithHandlerOptions(opts...),
|
||||
)
|
||||
hostAgentServiceStartBackgroundHandler := connect.NewUnaryHandler(
|
||||
HostAgentServiceStartBackgroundProcedure,
|
||||
svc.StartBackground,
|
||||
connect.WithSchema(hostAgentServiceMethods.ByName("StartBackground")),
|
||||
connect.WithHandlerOptions(opts...),
|
||||
)
|
||||
hostAgentServiceListProcessesHandler := connect.NewUnaryHandler(
|
||||
HostAgentServiceListProcessesProcedure,
|
||||
svc.ListProcesses,
|
||||
connect.WithSchema(hostAgentServiceMethods.ByName("ListProcesses")),
|
||||
connect.WithHandlerOptions(opts...),
|
||||
)
|
||||
hostAgentServiceKillProcessHandler := connect.NewUnaryHandler(
|
||||
HostAgentServiceKillProcessProcedure,
|
||||
svc.KillProcess,
|
||||
connect.WithSchema(hostAgentServiceMethods.ByName("KillProcess")),
|
||||
connect.WithHandlerOptions(opts...),
|
||||
)
|
||||
hostAgentServiceConnectProcessHandler := connect.NewServerStreamHandler(
|
||||
HostAgentServiceConnectProcessProcedure,
|
||||
svc.ConnectProcess,
|
||||
connect.WithSchema(hostAgentServiceMethods.ByName("ConnectProcess")),
|
||||
connect.WithHandlerOptions(opts...),
|
||||
)
|
||||
return "/hostagent.v1.HostAgentService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case HostAgentServiceCreateSandboxProcedure:
|
||||
@ -766,6 +868,14 @@ func NewHostAgentServiceHandler(svc HostAgentServiceHandler, opts ...connect.Han
|
||||
hostAgentServicePtyResizeHandler.ServeHTTP(w, r)
|
||||
case HostAgentServicePtyKillProcedure:
|
||||
hostAgentServicePtyKillHandler.ServeHTTP(w, r)
|
||||
case HostAgentServiceStartBackgroundProcedure:
|
||||
hostAgentServiceStartBackgroundHandler.ServeHTTP(w, r)
|
||||
case HostAgentServiceListProcessesProcedure:
|
||||
hostAgentServiceListProcessesHandler.ServeHTTP(w, r)
|
||||
case HostAgentServiceKillProcessProcedure:
|
||||
hostAgentServiceKillProcessHandler.ServeHTTP(w, r)
|
||||
case HostAgentServiceConnectProcessProcedure:
|
||||
hostAgentServiceConnectProcessHandler.ServeHTTP(w, r)
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
@ -874,3 +984,19 @@ func (UnimplementedHostAgentServiceHandler) PtyResize(context.Context, *connect.
|
||||
func (UnimplementedHostAgentServiceHandler) PtyKill(context.Context, *connect.Request[gen.PtyKillRequest]) (*connect.Response[gen.PtyKillResponse], error) {
|
||||
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("hostagent.v1.HostAgentService.PtyKill is not implemented"))
|
||||
}
|
||||
|
||||
func (UnimplementedHostAgentServiceHandler) StartBackground(context.Context, *connect.Request[gen.StartBackgroundRequest]) (*connect.Response[gen.StartBackgroundResponse], error) {
|
||||
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("hostagent.v1.HostAgentService.StartBackground is not implemented"))
|
||||
}
|
||||
|
||||
func (UnimplementedHostAgentServiceHandler) ListProcesses(context.Context, *connect.Request[gen.ListProcessesRequest]) (*connect.Response[gen.ListProcessesResponse], error) {
|
||||
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("hostagent.v1.HostAgentService.ListProcesses is not implemented"))
|
||||
}
|
||||
|
||||
func (UnimplementedHostAgentServiceHandler) KillProcess(context.Context, *connect.Request[gen.KillProcessRequest]) (*connect.Response[gen.KillProcessResponse], error) {
|
||||
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("hostagent.v1.HostAgentService.KillProcess is not implemented"))
|
||||
}
|
||||
|
||||
func (UnimplementedHostAgentServiceHandler) ConnectProcess(context.Context, *connect.Request[gen.ConnectProcessRequest], *connect.ServerStream[gen.ConnectProcessResponse]) error {
|
||||
return connect.NewError(connect.CodeUnimplemented, errors.New("hostagent.v1.HostAgentService.ConnectProcess is not implemented"))
|
||||
}
|
||||
|
||||
@ -91,6 +91,19 @@ service HostAgentService {
|
||||
// PtyKill sends a signal to a PTY process.
|
||||
rpc PtyKill(PtyKillRequest) returns (PtyKillResponse);
|
||||
|
||||
// StartBackground starts a process in the background and returns immediately
|
||||
// with the PID and tag. The process survives RPC disconnection.
|
||||
rpc StartBackground(StartBackgroundRequest) returns (StartBackgroundResponse);
|
||||
|
||||
// ListProcesses returns all running processes inside a sandbox.
|
||||
rpc ListProcesses(ListProcessesRequest) returns (ListProcessesResponse);
|
||||
|
||||
// KillProcess sends a signal to a process identified by PID or tag.
|
||||
rpc KillProcess(KillProcessRequest) returns (KillProcessResponse);
|
||||
|
||||
// ConnectProcess re-attaches to a running process and streams its output.
|
||||
rpc ConnectProcess(ConnectProcessRequest) returns (stream ConnectProcessResponse);
|
||||
|
||||
}
|
||||
|
||||
message CreateSandboxRequest {
|
||||
@ -476,3 +489,64 @@ message PtyKillRequest {
|
||||
}
|
||||
|
||||
message PtyKillResponse {}
|
||||
|
||||
// ── Background Processes ───────────────────────────────────────────
|
||||
|
||||
message StartBackgroundRequest {
|
||||
string sandbox_id = 1;
|
||||
string cmd = 2;
|
||||
repeated string args = 3;
|
||||
// User-chosen tag for the process. If empty, the host agent generates one.
|
||||
string tag = 4;
|
||||
map<string, string> envs = 5;
|
||||
string cwd = 6;
|
||||
}
|
||||
|
||||
message StartBackgroundResponse {
|
||||
uint32 pid = 1;
|
||||
string tag = 2;
|
||||
}
|
||||
|
||||
message ListProcessesRequest {
|
||||
string sandbox_id = 1;
|
||||
}
|
||||
|
||||
message ProcessEntry {
|
||||
uint32 pid = 1;
|
||||
string tag = 2;
|
||||
string cmd = 3;
|
||||
repeated string args = 4;
|
||||
}
|
||||
|
||||
message ListProcessesResponse {
|
||||
repeated ProcessEntry processes = 1;
|
||||
}
|
||||
|
||||
message KillProcessRequest {
|
||||
string sandbox_id = 1;
|
||||
oneof selector {
|
||||
uint32 pid = 2;
|
||||
string tag = 3;
|
||||
}
|
||||
// Signal to send: "SIGTERM" or "SIGKILL" (default: "SIGKILL").
|
||||
string signal = 4;
|
||||
}
|
||||
|
||||
message KillProcessResponse {}
|
||||
|
||||
message ConnectProcessRequest {
|
||||
string sandbox_id = 1;
|
||||
oneof selector {
|
||||
uint32 pid = 2;
|
||||
string tag = 3;
|
||||
}
|
||||
}
|
||||
|
||||
// Reuses ExecStream event types for symmetry.
|
||||
message ConnectProcessResponse {
|
||||
oneof event {
|
||||
ExecStreamStart start = 1;
|
||||
ExecStreamData data = 2;
|
||||
ExecStreamEnd end = 3;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user