mirror of
https://github.com/criyle/go-judge.git
synced 2025-09-26 22:39:12 +08:00
split ffi from executor server
This commit is contained in:
parent
84dc8cfe29
commit
411d74a087
13
.github/workflows/build.yml
vendored
13
.github/workflows/build.yml
vendored
@ -23,8 +23,13 @@ jobs:
|
||||
GOARCH: ${{ matrix.GOARCH }}
|
||||
run: |
|
||||
go build -o executorserver ./cmd/executorserver
|
||||
- name: Build shared objects
|
||||
env:
|
||||
GOOS: linux
|
||||
GOARCH: ${{ matrix.GOARCH }}
|
||||
run: |
|
||||
go build -o cinit ./cmd/cinit
|
||||
go build -buildmode=c-shared -o executorserver.so ./cmd/executorserver
|
||||
go build -buildmode=c-shared -o executorserver.so ./cmd/ffi
|
||||
- name: Upload executorserver
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
@ -54,7 +59,7 @@ jobs:
|
||||
- name: Build on Windows
|
||||
run: |
|
||||
go build -o executorserver.exe ./cmd/executorserver
|
||||
go build -buildmode=c-shared -o executorserver.dll ./cmd/executorserver
|
||||
go build -buildmode=c-shared -o executorserver.dll ./cmd/ffi
|
||||
- name: Upload executorserver.exe on Windows
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
@ -66,7 +71,7 @@ jobs:
|
||||
name: ExecutorServer.dll
|
||||
path: executorserver.dll
|
||||
build-macos:
|
||||
name: Build
|
||||
name: Build macOS
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Set up Go 1.14
|
||||
@ -79,7 +84,7 @@ jobs:
|
||||
- name: Build on MacOS
|
||||
run: |
|
||||
go build -o executorserver ./cmd/executorserver
|
||||
go build -buildmode=c-shared -o executorserver.dylib ./cmd/executorserver
|
||||
go build -buildmode=c-shared -o executorserver.dylib ./cmd/ffi
|
||||
- name: Upload executorserver
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
|
@ -13,7 +13,7 @@ COPY ./ /go/judge
|
||||
|
||||
RUN go build -o executorserver ./cmd/executorserver && \
|
||||
go build -o cinit ./cmd/cinit && \
|
||||
go build -buildmode=c-shared -o executor_server.so ./cmd/executorserver/
|
||||
go build -buildmode=c-shared -o executor_server.so ./cmd/ffi/
|
||||
|
||||
FROM alpine:latest
|
||||
|
||||
|
@ -8,7 +8,9 @@ RUN go mod download
|
||||
|
||||
COPY ./ /go/judge
|
||||
|
||||
RUN go build -o executorserver ./cmd/executorserver
|
||||
RUN go build -o executorserver ./cmd/executorserver \
|
||||
go build -o cinit ./cmd/cinit && \
|
||||
go build -buildmode=c-shared -o executor_server.so ./cmd/ffi/
|
||||
|
||||
FROM debian:latest
|
||||
|
||||
|
@ -48,7 +48,7 @@ Build container init `cinit`:
|
||||
|
||||
Build `executor_server.so`:
|
||||
|
||||
`go build -buildmode=c-shared -o executor_server.so ./cmd/executorserver/`
|
||||
`go build -buildmode=c-shared -o executor_server.so ./cmd/ffi/`
|
||||
|
||||
For example, in JavaScript, run with `ffi-napi` (seems node 14 is not supported yet):
|
||||
|
||||
@ -96,7 +96,7 @@ const result = JSON.parse(executor_server.Exec(JSON.stringify({
|
||||
})));
|
||||
console.log(result);
|
||||
|
||||
// Async
|
||||
// Async
|
||||
executor_server.Exec.async(JSON.stringify({
|
||||
"cmd": [{
|
||||
"args": ["/bin/cat", "test.txt"],
|
||||
@ -201,7 +201,7 @@ Build `executorserver` by:
|
||||
|
||||
Build `executor_server.dll`: (need to install `gcc` as well)
|
||||
|
||||
`go build -buildmode=c-shared -o executor_server.so ./cmd/executorserver/`
|
||||
`go build -buildmode=c-shared -o executor_server.so ./cmd/ffi/`
|
||||
|
||||
Run: `./executorserver`
|
||||
|
||||
@ -219,7 +219,7 @@ Build `executorserver` by:
|
||||
|
||||
Build `executor_server.dylib`: (need to install `XCode`)
|
||||
|
||||
`go build -buildmode=c-shared -o executor_server.dylib ./cmd/executorserver/`
|
||||
`go build -buildmode=c-shared -o executor_server.dylib ./cmd/ffi/`
|
||||
|
||||
Run: `./executorserver`
|
||||
|
||||
|
@ -7,7 +7,9 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/criyle/go-judge/env"
|
||||
"github.com/criyle/go-judge/filestore"
|
||||
"github.com/criyle/go-judge/pkg/pool"
|
||||
"github.com/criyle/go-judge/worker"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
@ -46,7 +48,11 @@ func main() {
|
||||
}
|
||||
|
||||
fs := newFilsStore(*dir)
|
||||
envPool := newEnvPool()
|
||||
b, err := env.NewBuilder(*cinitPath, *mountConf, *tmpFsParam, *netShare, printLog)
|
||||
if err != nil {
|
||||
log.Fatalln("create environment builder failed", err)
|
||||
}
|
||||
envPool := pool.NewPool(b)
|
||||
work = worker.New(fs, envPool, *parallism, *dir)
|
||||
work.Start()
|
||||
printLog("Starting worker with parallism", *parallism)
|
||||
|
@ -1,23 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/criyle/go-judge/pkg/envexec"
|
||||
"github.com/criyle/go-judge/pkg/macsandbox"
|
||||
"github.com/criyle/go-judge/pkg/pool"
|
||||
)
|
||||
|
||||
var defaultRead = []string{
|
||||
"/",
|
||||
}
|
||||
|
||||
var defaultWrite = []string{
|
||||
"/tmp",
|
||||
"/dev/null",
|
||||
"/var/tmp",
|
||||
}
|
||||
|
||||
func newEnvPool() envexec.EnvironmentPool {
|
||||
b := macsandbox.NewBuilder("", defaultRead, defaultWrite, *netShare)
|
||||
printLog("created mac sandbox at", "")
|
||||
return pool.NewPool(b)
|
||||
}
|
@ -1,80 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
|
||||
"github.com/criyle/go-judge/pkg/envexec"
|
||||
"github.com/criyle/go-judge/pkg/pool"
|
||||
"github.com/criyle/go-sandbox/container"
|
||||
"github.com/criyle/go-sandbox/pkg/cgroup"
|
||||
"github.com/criyle/go-sandbox/pkg/forkexec"
|
||||
)
|
||||
|
||||
func init() {
|
||||
container.Init()
|
||||
}
|
||||
|
||||
func newEnvPool() envexec.EnvironmentPool {
|
||||
root, err := ioutil.TempDir("", "executorserver")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
printLog("Created tmp dir for container root at:", root)
|
||||
|
||||
mb, err := parseMountConfig(*mountConf)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
printLog("Use the default container mount")
|
||||
mb = getDefaultMount()
|
||||
}
|
||||
m, err := mb.Build(true)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
printLog("Created container mount at:", mb)
|
||||
|
||||
unshareFlags := uintptr(forkexec.UnshareFlags)
|
||||
if *netShare {
|
||||
unshareFlags ^= syscall.CLONE_NEWNET
|
||||
}
|
||||
|
||||
b := &container.Builder{
|
||||
Root: root,
|
||||
Mounts: m,
|
||||
CredGenerator: newCredGen(),
|
||||
Stderr: true,
|
||||
CloneFlags: unshareFlags,
|
||||
ExecFile: *cinitPath,
|
||||
}
|
||||
cgb, err := cgroup.NewBuilder("executorserver").WithCPUAcct().WithMemory().WithPids().FilterByEnv()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
printLog("Created cgroup builder with:", cgb)
|
||||
|
||||
cgroupPool := pool.NewFakeCgroupPool(cgb)
|
||||
builder := pool.NewEnvBuilder(b, cgroupPool)
|
||||
return pool.NewPool(builder)
|
||||
}
|
||||
|
||||
type credGen struct {
|
||||
cur uint32
|
||||
}
|
||||
|
||||
func newCredGen() *credGen {
|
||||
return &credGen{cur: 10000}
|
||||
}
|
||||
|
||||
func (c *credGen) Get() syscall.Credential {
|
||||
n := atomic.AddUint32(&c.cur, 1)
|
||||
return syscall.Credential{
|
||||
Uid: n,
|
||||
Gid: n,
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +0,0 @@
|
||||
// +build !windows,!linux,!darwin
|
||||
|
||||
package main
|
||||
|
||||
import "github.com/criyle/go-judge/pkg/envexec"
|
||||
|
||||
func newEnvPool() envexec.EnvironmentPool {
|
||||
return nil
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/criyle/go-judge/pkg/envexec"
|
||||
"github.com/criyle/go-judge/pkg/pool"
|
||||
"github.com/criyle/go-judge/pkg/winc"
|
||||
)
|
||||
|
||||
func newEnvPool() envexec.EnvironmentPool {
|
||||
b, err := winc.NewBuilder("")
|
||||
if err != nil {
|
||||
log.Fatalln("init container", err)
|
||||
}
|
||||
printLog("created winc builder")
|
||||
return pool.NewPool(b)
|
||||
}
|
@ -5,8 +5,12 @@ import "C"
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/criyle/go-judge/env"
|
||||
"github.com/criyle/go-judge/filestore"
|
||||
"github.com/criyle/go-judge/pkg/pool"
|
||||
"github.com/criyle/go-judge/worker"
|
||||
)
|
||||
|
||||
@ -19,7 +23,21 @@ type initParameter struct {
|
||||
MountConf string `json:"mountConf"`
|
||||
}
|
||||
|
||||
var fs filestore.FileStore
|
||||
var (
|
||||
fs filestore.FileStore
|
||||
work *worker.Worker
|
||||
)
|
||||
|
||||
func newFilsStore(dir string) filestore.FileStore {
|
||||
var fs filestore.FileStore
|
||||
if dir == "" {
|
||||
fs = filestore.NewFileMemoryStore()
|
||||
} else {
|
||||
os.MkdirAll(dir, 0755)
|
||||
fs = filestore.NewFileLocalStore(dir)
|
||||
}
|
||||
return fs
|
||||
}
|
||||
|
||||
// Init initialize the sandbox environment
|
||||
//export Init
|
||||
@ -33,23 +51,24 @@ func Init(i *C.char) C.int {
|
||||
if ip.Parallism == 0 {
|
||||
ip.Parallism = 4
|
||||
}
|
||||
parallism = &ip.Parallism
|
||||
|
||||
if ip.TmpFsParam == "" {
|
||||
ip.TmpFsParam = "size=16m,nr_inodes=4k"
|
||||
}
|
||||
tmpFsParam = &ip.TmpFsParam
|
||||
|
||||
if ip.MountConf == "" {
|
||||
ip.MountConf = "mount.yaml"
|
||||
}
|
||||
|
||||
fs = newFilsStore(ip.Dir)
|
||||
cinitPath = &ip.CInitPath
|
||||
|
||||
printLog = func(v ...interface{}) {}
|
||||
envPool := newEnvPool()
|
||||
work = worker.New(fs, envPool, *parallism, *dir)
|
||||
printLog := func(v ...interface{}) {}
|
||||
b, err := env.NewBuilder(ip.CInitPath, ip.MountConf, ip.TmpFsParam, ip.NetShare, printLog)
|
||||
if err != nil {
|
||||
log.Fatalln("create environment builder failed", err)
|
||||
}
|
||||
envPool := pool.NewPool(b)
|
||||
work = worker.New(fs, envPool, ip.Parallism, ip.Dir)
|
||||
work.Start()
|
||||
|
||||
return 0
|
4
cmd/ffi/main.go
Normal file
4
cmd/ffi/main.go
Normal file
@ -0,0 +1,4 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
}
|
2
env/doc.go
vendored
Normal file
2
env/doc.go
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
// Package env provides a unified method to create environment for envexec
|
||||
package env
|
23
env/env_darwin.go
vendored
Normal file
23
env/env_darwin.go
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"github.com/criyle/go-judge/pkg/macsandbox"
|
||||
"github.com/criyle/go-judge/pkg/pool"
|
||||
)
|
||||
|
||||
var defaultRead = []string{
|
||||
"/",
|
||||
}
|
||||
|
||||
var defaultWrite = []string{
|
||||
"/tmp",
|
||||
"/dev/null",
|
||||
"/var/tmp",
|
||||
}
|
||||
|
||||
// NewBuilder build a environment builder
|
||||
func NewBuilder(cinitPath, mountConf, tmpFsConf string, netShare bool, printLog func(v ...interface{})) (pool.EnvBuilder, error) {
|
||||
b := macsandbox.NewBuilder("", defaultRead, defaultWrite, netShare)
|
||||
printLog("created mac sandbox at", "")
|
||||
return b, nil
|
||||
}
|
74
env/env_linux.go
vendored
Normal file
74
env/env_linux.go
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
|
||||
"github.com/criyle/go-judge/pkg/pool"
|
||||
"github.com/criyle/go-sandbox/container"
|
||||
"github.com/criyle/go-sandbox/pkg/cgroup"
|
||||
"github.com/criyle/go-sandbox/pkg/forkexec"
|
||||
)
|
||||
|
||||
// NewBuilder build a environment builder
|
||||
func NewBuilder(cinitPath, mountConf, tmpFsConf string, netShare bool, printLog func(v ...interface{})) (pool.EnvBuilder, error) {
|
||||
root, err := ioutil.TempDir("", "executorserver")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
printLog("Created tmp dir for container root at:", root)
|
||||
|
||||
mb, err := parseMountConfig(mountConf)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
printLog("Use the default container mount")
|
||||
mb = getDefaultMount(tmpFsConf)
|
||||
}
|
||||
m, err := mb.Build(true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
printLog("Created container mount at:", mb)
|
||||
|
||||
unshareFlags := uintptr(forkexec.UnshareFlags)
|
||||
if netShare {
|
||||
unshareFlags ^= syscall.CLONE_NEWNET
|
||||
}
|
||||
|
||||
b := &container.Builder{
|
||||
Root: root,
|
||||
Mounts: m,
|
||||
CredGenerator: newCredGen(),
|
||||
Stderr: true,
|
||||
CloneFlags: unshareFlags,
|
||||
ExecFile: cinitPath,
|
||||
}
|
||||
cgb, err := cgroup.NewBuilder("executorserver").WithCPUAcct().WithMemory().WithPids().FilterByEnv()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
printLog("Created cgroup builder with:", cgb)
|
||||
|
||||
cgroupPool := pool.NewFakeCgroupPool(cgb)
|
||||
return pool.NewEnvBuilder(b, cgroupPool), nil
|
||||
}
|
||||
|
||||
type credGen struct {
|
||||
cur uint32
|
||||
}
|
||||
|
||||
func newCredGen() *credGen {
|
||||
return &credGen{cur: 10000}
|
||||
}
|
||||
|
||||
func (c *credGen) Get() syscall.Credential {
|
||||
n := atomic.AddUint32(&c.cur, 1)
|
||||
return syscall.Credential{
|
||||
Uid: n,
|
||||
Gid: n,
|
||||
}
|
||||
}
|
14
env/env_others.go
vendored
Normal file
14
env/env_others.go
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
// +build !windows,!linux,!darwin
|
||||
|
||||
package env
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"runtime"
|
||||
|
||||
"github.com/criyle/go-judge/pkg/pool"
|
||||
)
|
||||
|
||||
func NewBuilder(cinitPath, mountConf, tmpFsConf string, netShare bool, printLog func(v ...interface{})) (pool.EnvBuilder, error) {
|
||||
return nil, errors.New("environment is not support on this platform" + runtime.GOOS)
|
||||
}
|
16
env/env_windows.go
vendored
Normal file
16
env/env_windows.go
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"github.com/criyle/go-judge/pkg/pool"
|
||||
"github.com/criyle/go-judge/pkg/winc"
|
||||
)
|
||||
|
||||
// NewBuilder build a environment builder
|
||||
func NewBuilder(cinitPath, mountConf, tmpFsConf string, netShare bool, printLog func(v ...interface{})) (pool.EnvBuilder, error) {
|
||||
b, err := winc.NewBuilder("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
printLog("created winc builder")
|
||||
return b, nil
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package env
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -55,7 +55,7 @@ func parseMountConfig(p string) (*mount.Builder, error) {
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func getDefaultMount() *mount.Builder {
|
||||
func getDefaultMount(tmpFsConf string) *mount.Builder {
|
||||
return mount.NewBuilder().
|
||||
// basic exec and lib
|
||||
WithBind("/bin", "bin", true).
|
||||
@ -78,7 +78,7 @@ func getDefaultMount() *mount.Builder {
|
||||
// javaScript wants /dev/urandom
|
||||
WithBind("/dev/urandom", "dev/urandom", true).
|
||||
// work dir
|
||||
WithTmpfs("w", *tmpFsParam).
|
||||
WithTmpfs("w", tmpFsConf).
|
||||
// tmp dir
|
||||
WithTmpfs("tmp", *tmpFsParam)
|
||||
WithTmpfs("tmp", tmpFsConf)
|
||||
}
|
Loading…
Reference in New Issue
Block a user