Skip to content

Commit b8d8345

Browse files
committed
feat: Add process-control gRPC service for docker top
Implements ListProcesses RPC that reads /proc directly to avoid race condition where /bin/ps appears in its own output. Changes: - Add ListProcesses RPC to process.proto - Implement namespace filtering to show only container processes - Fix vsock listener to use github.com/mdlayher/vsock library - Add service startup in vminitd Application.swift - Filter processes by PID namespace (exclude root namespace) The service runs in the VM's root namespace and filters out all processes in that namespace (vminitd, services, kernel threads), returning only container processes since we have 1 container per VM.
1 parent 2951cc0 commit b8d8345

File tree

10 files changed

+538
-62
lines changed

10 files changed

+538
-62
lines changed

vminitd/Sources/vminitd/Application.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,29 @@ struct Application {
169169
log.warning("arca-overlayfs-service binary not found at \(overlayFSServicePath), OverlayFS mounting will not be available")
170170
}
171171

172+
// Start arca-process-service in background for process control
173+
// This service listens on vsock port 51822 (accessible from host via container.dialVsock())
174+
let processServicePath = "/sbin/arca-process-service"
175+
let processServiceExists = FileManager.default.fileExists(atPath: processServicePath)
176+
log.info("arca-process-service binary exists: \(processServiceExists) at \(processServicePath)")
177+
178+
if processServiceExists {
179+
log.info("starting arca-process-service...")
180+
var processService = Command(processServicePath)
181+
// Leave stdin/stdout/stderr as nil for detached background service
182+
processService.stdin = nil
183+
processService.stdout = nil
184+
processService.stderr = .standardError // Log errors to vminitd stderr
185+
do {
186+
try processService.start()
187+
log.info("arca-process-service started successfully on vsock port 51822")
188+
} catch {
189+
log.error("failed to start arca-process-service: \(error)")
190+
}
191+
} else {
192+
log.warning("arca-process-service binary not found at \(processServicePath), process listing via gRPC will not be available")
193+
}
194+
172195
// Auto-detect and mount OverlayFS if layer block devices are present
173196
// This is NOT hardcoded - it only runs if vdb/vdc/vdd/etc exist (indicating OverlayFS layers)
174197
if FileManager.default.fileExists(atPath: "/dev/vdb") {
9.44 MB
Binary file not shown.

vminitd/extensions/process-control/build.sh

100644100755
File mode changed.

vminitd/extensions/process-control/cmd/arca-process-service/main.go

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,36 @@ package main
33
import (
44
"fmt"
55
"log"
6-
"net"
76
"os"
7+
"strconv"
88

9+
"github.com/mdlayher/vsock"
910
"google.golang.org/grpc"
1011
pb "github.com/apple/containerization/vminitd/extensions/process-control/proto"
1112
"github.com/apple/containerization/vminitd/extensions/process-control"
1213
)
1314

15+
const (
16+
PROCESS_SERVICE_PORT = 51822 // vsock port for Process Control API
17+
)
18+
1419
func main() {
1520
// Get vsock port from environment (default: 51822)
16-
port := os.Getenv("PROCESS_SERVICE_PORT")
17-
if port == "" {
18-
port = "51822"
21+
portStr := os.Getenv("PROCESS_SERVICE_PORT")
22+
port := PROCESS_SERVICE_PORT
23+
if portStr != "" {
24+
if p, err := strconv.Atoi(portStr); err == nil {
25+
port = p
26+
}
1927
}
2028

21-
// Listen on vsock
22-
addr := fmt.Sprintf("vsock://:%%d/%%s", port)
23-
lis, err := net.Listen("vsock", addr)
29+
// Listen on vsock using mdlayher/vsock library (required for vsock support)
30+
lis, err := vsock.Listen(uint32(port), nil)
2431
if err != nil {
25-
log.Fatalf("Failed to listen on vsock port %s: %v", port, err)
32+
log.Fatalf("Failed to listen on vsock port %d: %v", port, err)
2633
}
2734

28-
log.Printf("Process service listening on vsock port %s", port)
35+
log.Printf("Process service listening on vsock port %d", port)
2936

3037
// Create gRPC server
3138
grpcServer := grpc.NewServer()

vminitd/extensions/process-control/go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ module github.com/apple/containerization/vminitd/extensions/process-control
33
go 1.24.0
44

55
require (
6-
github.com/mdlayher/vsock v1.2.1
76
google.golang.org/grpc v1.76.0
87
google.golang.org/protobuf v1.36.10
98
)
109

1110
require (
12-
github.com/mdlayher/socket v0.5.1 // indirect
11+
github.com/mdlayher/socket v0.4.1 // indirect
12+
github.com/mdlayher/vsock v1.2.1 // indirect
1313
golang.org/x/net v0.46.0 // indirect
1414
golang.org/x/sync v0.17.0 // indirect
1515
golang.org/x/sys v0.37.0 // indirect
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
2+
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
3+
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
4+
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
5+
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
6+
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
7+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
8+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
9+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
10+
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
11+
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
12+
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
13+
github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ=
14+
github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE=
15+
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
16+
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
17+
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
18+
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
19+
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
20+
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
21+
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
22+
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
23+
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
24+
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
25+
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
26+
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
27+
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
28+
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
29+
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
30+
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
31+
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
32+
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
33+
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
34+
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
35+
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
36+
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
37+
google.golang.org/genproto/googleapis/rpc v0.0.0-20251020155222-88f65dc88635 h1:3uycTxukehWrxH4HtPRtn1PDABTU331ViDjyqrUbaog=
38+
google.golang.org/genproto/googleapis/rpc v0.0.0-20251020155222-88f65dc88635/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
39+
google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
40+
google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c=
41+
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
42+
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=

0 commit comments

Comments
 (0)