An instance is a directory under instances/<id>/ (config.json, state.json, stdout, stderr, run/, volumes/) written by package instance, the service behind the verbs. run -d and start fork this binary as a supervisor (werkdock supervise ID) that records the pids and the exit code; stop, kill, wait, logs, ps, rm, inspect read the files. exec is a second bwrap over the same instance tree. The command is pid 1 of its sandbox (bwrap --as-pid-1) so stop's SIGTERM reaches it, as in docker; /run and the anonymous volumes are instance directories, kept across stop/start and shared with exec. Version 0.5.0. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: mhoennig <michael@hoennig.de> Reviewed-on: #4
77 lines
2.4 KiB
Go
77 lines
2.4 KiB
Go
// Package engine executes sandboxed commands. The CLI verbs are thin
|
|
// frontends over this package, so a later daemon can expose the same
|
|
// logic without duplicating it (RFC 0002).
|
|
package engine
|
|
|
|
import "os"
|
|
|
|
// MountMode distinguishes the mount kinds a RunSpec can carry.
|
|
type MountMode int
|
|
|
|
const (
|
|
// MountBind is a read-write bind mount.
|
|
MountBind MountMode = iota
|
|
// MountRoBind is a read-only bind mount.
|
|
MountRoBind
|
|
// MountTmpfs is an empty tmpfs at Dest; Source is unused.
|
|
MountTmpfs
|
|
)
|
|
|
|
// Mount is one mount, applied in order; later mounts shadow earlier
|
|
// ones at their own path, exactly as bwrap layers them — the order of
|
|
// -v and --tmpfs flags is therefore significant and preserved.
|
|
type Mount struct {
|
|
Mode MountMode
|
|
Source string
|
|
Dest string
|
|
}
|
|
|
|
// EnvVar is one environment variable; order is preserved.
|
|
type EnvVar struct {
|
|
Key string
|
|
Value string
|
|
}
|
|
|
|
// RunSpec describes one sandboxed command, independent of the engine
|
|
// that executes it.
|
|
type RunSpec struct {
|
|
// RootFS is the absolute path to the unpacked image rootfs,
|
|
// bound read-only at /.
|
|
RootFS string
|
|
Mounts []Mount
|
|
Env []EnvVar
|
|
Workdir string
|
|
Command []string
|
|
// UID and GID are what the calling user appears as inside the
|
|
// sandbox — the single mapping an unprivileged user namespace has.
|
|
// Zero, the default, is root as before (RFC 0005).
|
|
UID, GID int
|
|
// Home is HOME inside the sandbox; empty means /root, which is a
|
|
// tmpfs and therefore writable whoever the uid is.
|
|
Home string
|
|
}
|
|
|
|
// Process is a started sandbox: the command runs as pid 1 of its own
|
|
// pid namespace, and ChildPID is that process as the host sees it —
|
|
// the address a stop signal goes to (RFC 0005).
|
|
type Process interface {
|
|
// ChildPID is the host pid of the sandboxed command.
|
|
ChildPID() int
|
|
// Signal delivers sig to the sandboxed command. Like docker's
|
|
// pid 1, the command only receives signals it handles, except
|
|
// SIGKILL.
|
|
Signal(sig os.Signal) error
|
|
// Wait blocks until the command has exited and returns its code.
|
|
Wait() (int, error)
|
|
}
|
|
|
|
// Engine runs a RunSpec and reports the command's exit code.
|
|
// bwrap is the first engine; native namespaces may become a second
|
|
// (RFC 0001).
|
|
type Engine interface {
|
|
Run(spec RunSpec) (int, error)
|
|
// Start launches spec and returns without waiting; the instance
|
|
// supervisor uses it to record the pid and to stop on request.
|
|
Start(spec RunSpec) (Process, error)
|
|
}
|