Skip to content

Commit bdd9670

Browse files
authored
Add support for isolate v2 (#112)
* fix: change isolate daemon command in scripts/start_container.sh * feat: Remove isolate in docker/Dockerfile * chore: update go-sqlite3 to fix musl build mattn/go-sqlite3#1164 * feat: Dockerfile for gcc-only * feat: accept arbitrary command for isolate daemon * feat(isolate): print logs real-time and add Stop() * chore: update golangci-lint to make tests passable
1 parent 0a83cee commit bdd9670

File tree

11 files changed

+113
-62
lines changed

11 files changed

+113
-62
lines changed

cmd/kjudge/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ func main() {
5656

5757
log.Println("Starting kjudge. Press Ctrl+C to stop")
5858

59+
go sandbox.Start()
5960
go queue.Start()
6061
go startServer(server)
6162

docker/Dockerfile

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Stage -1: Update apt-get
1+
# Stage 0: Update apt-get
22
FROM ubuntu:jammy AS base-ubuntu
33

44
# Mount apt's cache folders to cache install but maintain
@@ -10,19 +10,6 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
1010
--mount=type=cache,target=/var/lib/apt,sharing=locked \
1111
apt-get update && apt-get upgrade -y
1212

13-
# Stage 0: Compile isolate
14-
FROM base-ubuntu AS isolate
15-
16-
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
17-
--mount=type=cache,target=/var/lib/apt,sharing=locked \
18-
apt-get update && apt-get install -y libcap-dev gcc git make
19-
20-
WORKDIR /isolate
21-
22-
RUN git clone --branch v1.10.1 --single-branch https://github.com/ioi/isolate.git .
23-
24-
RUN make isolate
25-
2613
# Stage 1: Generate front-end
2714
FROM node:18-alpine AS frontend
2815

@@ -51,7 +38,7 @@ RUN scripts/install_tools.sh
5138
RUN go generate && go build -tags production -o kjudge cmd/kjudge/main.go
5239

5340
# Stage 3: Create awesome output image
54-
FROM base-ubuntu
41+
FROM ghcr.io/minhnhatnoe/isolate:v2.1.5
5542

5643
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
5744
--mount=type=cache,target=/var/lib/apt,sharing=locked \
@@ -60,11 +47,6 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
6047
python3.10 python2.7 rustc golang libcap-dev \
6148
openssl
6249

63-
COPY --from=isolate /isolate/ /isolate
64-
65-
WORKDIR /isolate
66-
RUN make install
67-
6850
COPY --from=backend /kjudge/kjudge /usr/local/bin
6951
COPY --from=backend /kjudge/scripts /scripts
7052

docker/gcc-only.dockerfile

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,3 @@
1-
# Stage 0: Compile isolate
2-
FROM alpine:3 AS isolate
3-
4-
RUN apk add --no-cache libcap gcc make git g++ libcap-dev
5-
6-
WORKDIR /isolate
7-
8-
RUN git clone --branch v1.10.1 --single-branch https://github.com/ioi/isolate.git .
9-
10-
RUN make isolate
11-
121
# Stage 1: Generate front-end
132
FROM node:18-alpine AS frontend
143

@@ -40,15 +29,10 @@ RUN sh scripts/install_tools.sh
4029
RUN go generate && go build -tags production -o kjudge cmd/kjudge/main.go
4130

4231
# Stage 3: Create awesome output image
43-
FROM alpine:3
32+
FROM ghcr.io/minhnhatnoe/isolate:v2.1.5-alpine
4433

4534
RUN apk add --no-cache libcap make g++ openssl bash
4635

47-
COPY --from=isolate /isolate/ /isolate
48-
49-
WORKDIR /isolate
50-
RUN make install
51-
5236
COPY --from=backend /kjudge/kjudge /usr/local/bin
5337
COPY --from=backend /kjudge/scripts /scripts
5438

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ require (
1010
github.com/labstack/echo-contrib v0.9.0
1111
github.com/labstack/echo/v4 v4.9.0
1212
github.com/mattn/go-colorable v0.1.12 // indirect
13-
github.com/mattn/go-sqlite3 v1.14.0
13+
github.com/mattn/go-sqlite3 v1.14.19
1414
github.com/pkg/errors v0.9.1
1515
golang.org/x/crypto v0.14.0
1616
golang.org/x/net v0.17.0 // indirect

go.sum

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
22
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
33
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
4-
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
54
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
65
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
7-
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
86
github.com/appleboy/gofight/v2 v2.1.2/go.mod h1:frW+U1QZEdDgixycTj4CygQ48yLTUhplt43+Wczp3rw=
97
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
108
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -62,8 +60,8 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
6260
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
6361
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
6462
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
65-
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
66-
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
63+
github.com/mattn/go-sqlite3 v1.14.19 h1:fhGleo2h1p8tVChob4I9HpmVFIAkKGpiukdrgQbWfGI=
64+
github.com/mattn/go-sqlite3 v1.14.19/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
6765
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
6866
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
6967
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -116,16 +114,13 @@ golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf
116114
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
117115
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
118116
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
119-
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
120117
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
121118
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
122119
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
123120
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
124121
golang.org/x/net v0.0.0-20190607181551-461777fb6f67/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
125122
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
126123
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
127-
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
128-
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
129124
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
130125
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
131126
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
@@ -146,7 +141,6 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
146141
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
147142
golang.org/x/sys v0.0.0-20190609082536-301114b31cce/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
148143
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
149-
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
150144
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
151145
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
152146
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

scripts/install_tools.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ do
88
done
99

1010
# Install golangci-lint
11-
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b "$(go env GOPATH)"/bin v1.52.2
11+
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b "$(go env GOPATH)"/bin v1.58.0

scripts/start_container.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ case ${HTTPS} in
4444
esac
4545

4646
if [ "${useHTTPS}" = true ]; then
47-
kjudge -port 443 -file /data/kjudge.db -https /certs "$@"
47+
KJUDGE_ISOLATE_DAEMON="start_isolate" kjudge -port 443 -file /data/kjudge.db -https /certs "$@"
4848
else
49-
kjudge -port 80 -file /data/kjudge.db "$@"
50-
fi
49+
KJUDGE_ISOLATE_DAEMON="start_isolate" kjudge -port 80 -file /data/kjudge.db "$@"
50+
fi

worker/sandbox.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@ func NewSandbox(name string, options ...sandbox.Option) (sandbox.Runner, error)
1212
switch name {
1313
case "raw":
1414
return raw.New(setting), nil
15+
case "isolate_v1":
16+
return isolate.New(1, setting), nil
1517
case "isolate":
16-
return isolate.New(setting), nil
18+
fallthrough
19+
case "isolate_v2":
20+
return isolate.New(2, setting), nil
1721
default:
1822
return nil, errors.Errorf("Sandbox %s doesn't exists or not yet implemented.", name)
1923
}

worker/sandbox/isolate/sandbox.go

Lines changed: 89 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@
66
package isolate
77

88
import (
9+
"bufio"
910
"bytes"
1011
"fmt"
12+
"io"
13+
"log"
1114
"os"
1215
"os/exec"
1316
"path/filepath"
@@ -19,40 +22,115 @@ import (
1922
)
2023

2124
var (
22-
// The isolate command. Can be overridden with KJUDGE_ISOLATE environment variable.
23-
isolateCommand = "isolate"
25+
// The isolate command. Can be overridden with KJUDGE_ISOLATE_V1 environment variable.
26+
isolateCommandV1 = "isolate"
27+
isolateCommandV2 = "isolate"
28+
isolateDaemonCommand = "systemctl status isolate.service"
2429
)
2530

2631
func init() {
32+
if v, ok := os.LookupEnv("KJUDGE_ISOLATE_V1"); ok {
33+
isolateCommandV1 = v
34+
}
2735
if v, ok := os.LookupEnv("KJUDGE_ISOLATE"); ok {
28-
isolateCommand = v
36+
isolateCommandV2 = v
37+
}
38+
if v, ok := os.LookupEnv("KJUDGE_ISOLATE_DAEMON"); ok {
39+
isolateDaemonCommand = v
2940
}
3041
}
3142

3243
// Runner implements worker.Runner.
3344
type Runner struct {
45+
version int // 1 or 2
46+
cmd *exec.Cmd
3447
settings sandbox.Settings
3548
private struct{} // Makes the sandbox not simply constructible
3649
}
3750

3851
var _ sandbox.Runner = (*Runner)(nil)
3952

53+
func (s *Runner) isolateCommand() string {
54+
if s.version == 1 {
55+
return isolateCommandV1
56+
} else if s.version == 2 {
57+
return isolateCommandV2
58+
} else {
59+
log.Panicf("Invalid isolate version: %d", s.version)
60+
return ""
61+
}
62+
}
63+
4064
// Panics on not having "isolate" accessible.
41-
func mustHaveIsolate() {
42-
output, err := exec.Command(isolateCommand, "--version").CombinedOutput()
65+
func (s *Runner) mustHaveIsolate() {
66+
output, err := exec.Command(s.isolateCommand(), "--version").CombinedOutput()
4367
if err != nil {
4468
panic(errors.Wrap(err, "trying to run isolate"))
4569
}
4670
if !strings.Contains(string(output), "The process isolator") {
47-
panic("Wrong isolate command found. Override the KJUDGE_ISOLATE environment variable to set a different path.")
71+
panic("Wrong isolate command found. Override the KJUDGE_ISOLATE_V1/KJUDGE_ISOLATE environment variable to set a different path.")
4872
}
4973
}
5074

5175
// New returns a new sandbox.
5276
// Panics if isolate is not installed.
53-
func New(settings sandbox.Settings) *Runner {
54-
mustHaveIsolate()
55-
return &Runner{settings: settings, private: struct{}{}}
77+
func New(version int, settings sandbox.Settings) *Runner {
78+
runner := &Runner{version: version, cmd: nil, settings: settings, private: struct{}{}}
79+
runner.mustHaveIsolate()
80+
return runner
81+
}
82+
83+
func (s *Runner) Start() {
84+
if s.version == 1 {
85+
return
86+
} else if s.version != 2 {
87+
log.Panicf("Invalid isolate version: %v", s.version)
88+
}
89+
90+
s.cmd = exec.Command("/bin/sh", "-c", isolateDaemonCommand)
91+
92+
stdout, err := s.cmd.StdoutPipe()
93+
if err != nil {
94+
log.Panic(errors.Wrap(err, "getting stdout pipe"))
95+
}
96+
97+
stderr, err := s.cmd.StderrPipe()
98+
if err != nil {
99+
log.Panic(errors.Wrap(err, "getting stderr pipe"))
100+
}
101+
102+
multi := io.MultiReader(stdout, stderr)
103+
reader := bufio.NewScanner(multi)
104+
105+
if err := s.cmd.Start(); err != nil {
106+
log.Panic(errors.Wrap(err, "starting isolate daemon"))
107+
}
108+
109+
for reader.Scan() {
110+
log.Printf("[isolate v2 daemon]: %s", reader.Text())
111+
}
112+
113+
if err := reader.Err(); err != nil {
114+
log.Panic(errors.Wrapf(err, "isolate daemon dead. Is daemon installed and, if installed as a systemd unit, started?"))
115+
}
116+
117+
if err := s.cmd.Wait(); err != nil {
118+
log.Panic(errors.Wrap(err, "waiting for isolate daemon"))
119+
}
120+
}
121+
122+
func (s *Runner) Stop() error {
123+
if s.cmd != nil {
124+
if err := s.cmd.Process.Kill(); err != nil {
125+
return errors.Wrap(err, "killing isolate daemon")
126+
}
127+
128+
if err := s.cmd.Process.Release(); err != nil {
129+
return errors.Wrap(err, "releasing isolate daemon")
130+
}
131+
}
132+
133+
return nil
56134
}
57135

58136
func (s *Runner) Settings() *sandbox.Settings {
@@ -63,7 +141,7 @@ func (s *Runner) Settings() *sandbox.Settings {
63141
func (s *Runner) Run(input *sandbox.Input) (*sandbox.Output, error) {
64142
// Init the sandbox
65143
defer s.cleanup()
66-
dirBytes, err := exec.Command(isolateCommand, "--init", "--cg").Output()
144+
dirBytes, err := exec.Command(s.isolateCommand(), "--init", "--cg").Output()
67145
if err != nil {
68146
return nil, errors.WithStack(err)
69147
}
@@ -153,5 +231,5 @@ func buildCmd(dir, metaFile string, input *sandbox.Input) *exec.Cmd {
153231
}
154232

155233
func (s *Runner) cleanup() {
156-
_ = exec.Command(isolateCommand, "--cleanup", "--cg").Run()
234+
_ = exec.Command(s.isolateCommand(), "--cleanup", "--cg").Run()
157235
}

worker/sandbox/raw/sandbox.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ func New(settings sandbox.Settings) *Runner {
3535
return &Runner{settings: settings}
3636
}
3737

38+
func (s *Runner) Start() {}
39+
40+
func (s *Runner) Stop() error {
41+
return nil
42+
}
43+
3844
func (s *Runner) Settings() *sandbox.Settings {
3945
return &s.settings
4046
}

0 commit comments

Comments
 (0)