1a69fcfd04
- Updated the installation script to clarify that production wrappers do not include fixed test secrets, improving user guidance for local testing. - Modified the jiggablend-manager and jiggablend-runner scripts to remove fixed test configurations, emphasizing the use of local test credentials via `make init-test`. - Enhanced error handling in the runner script to ensure that an API key is provided, improving security and user feedback. - Added new flags and options for the runner, including sandboxing capabilities and GPU ray tracing control, enhancing flexibility for users. - Improved README documentation to reflect changes in usage and configuration, ensuring users have clear instructions for setup and execution.
129 lines
3.5 KiB
Go
129 lines
3.5 KiB
Go
// Package sandbox wraps Blender (and similar) invocations in optional isolation.
|
|
//
|
|
// Backends:
|
|
// - none: run on the host (current behavior)
|
|
// - podman: rootless podman container; Blender tarball is bind-mounted (not baked into an image)
|
|
//
|
|
// GPU access is provided by passing host device nodes and common userspace lib roots
|
|
// discovered at wrap time (NVIDIA / AMD ROCm / Intel DRM), not by shipping per-version
|
|
// Blender container images.
|
|
package sandbox
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
)
|
|
|
|
// Backend names accepted by New and CLI flags.
|
|
const (
|
|
BackendNone = "none"
|
|
BackendPodman = "podman"
|
|
)
|
|
|
|
// Options configures sandbox construction.
|
|
type Options struct {
|
|
// Backend is none|podman (default none).
|
|
Backend string
|
|
// AllowNetwork keeps network in the sandbox (default false for podman).
|
|
AllowNetwork bool
|
|
// PodmanImage is used only for backend=podman. The image is a thin OS root;
|
|
// Blender comes from a host bind of the versioned tarball tree.
|
|
// Default: registry.fedoraproject.org/fedora-minimal:41
|
|
PodmanImage string
|
|
}
|
|
|
|
// Spec describes a Blender process to run under the sandbox.
|
|
type Spec struct {
|
|
// BlenderBinary is an absolute path to the blender executable.
|
|
BlenderBinary string
|
|
// Args are arguments after the binary (not including argv0).
|
|
Args []string
|
|
// WorkDir is the process working directory (job workspace); bind-mounted RW.
|
|
WorkDir string
|
|
// HomeDir is Blender HOME (usually WorkDir/home); bind-mounted RW.
|
|
HomeDir string
|
|
// Env is the full environment for the process (HOME, LD_LIBRARY_PATH, etc.).
|
|
Env []string
|
|
|
|
// GPU hints from host detection (used to select device/lib binds).
|
|
HasAMD bool
|
|
HasNVIDIA bool
|
|
HasIntel bool
|
|
// ForceCPU skips GPU device binds when true.
|
|
ForceCPU bool
|
|
// AllowNetwork overrides Options.AllowNetwork when non-nil... kept simple: use Options only.
|
|
}
|
|
|
|
// Wrapper turns a Spec into an *exec.Cmd ready to Start.
|
|
type Wrapper interface {
|
|
// Name returns the backend name.
|
|
Name() string
|
|
// Available reports whether required host tools exist.
|
|
Available() error
|
|
// Wrap builds the command. Callers own Start/Wait/pipes.
|
|
Wrap(spec Spec) (*exec.Cmd, error)
|
|
}
|
|
|
|
// New returns a sandbox Wrapper for the given options.
|
|
func New(opts Options) (Wrapper, error) {
|
|
backend := strings.ToLower(strings.TrimSpace(opts.Backend))
|
|
if backend == "" {
|
|
backend = BackendPodman
|
|
}
|
|
switch backend {
|
|
case BackendNone:
|
|
return &noneWrapper{}, nil
|
|
case BackendPodman:
|
|
img := opts.PodmanImage
|
|
if img == "" {
|
|
img = defaultPodmanImage
|
|
}
|
|
w := &podmanWrapper{allowNetwork: opts.AllowNetwork, image: img}
|
|
return w, nil
|
|
default:
|
|
return nil, fmt.Errorf("unknown sandbox backend %q (want none or podman)", opts.Backend)
|
|
}
|
|
}
|
|
|
|
// NormalizeBackend validates and returns a canonical backend name.
|
|
func NormalizeBackend(s string) (string, error) {
|
|
b := strings.ToLower(strings.TrimSpace(s))
|
|
if b == "" {
|
|
return BackendPodman, nil
|
|
}
|
|
switch b {
|
|
case BackendNone, BackendPodman:
|
|
return b, nil
|
|
default:
|
|
return "", fmt.Errorf("unknown sandbox backend %q (want none or podman)", s)
|
|
}
|
|
}
|
|
|
|
// LookPath is os/exec.LookPath, overridable in tests.
|
|
var LookPath = exec.LookPath
|
|
|
|
// pathExists reports whether path exists.
|
|
func pathExists(p string) bool {
|
|
_, err := os.Stat(p)
|
|
return err == nil
|
|
}
|
|
|
|
// mustAbs returns an absolute path or the original on error.
|
|
func mustAbs(p string) string {
|
|
if p == "" {
|
|
return p
|
|
}
|
|
abs, err := absPath(p)
|
|
if err != nil {
|
|
return p
|
|
}
|
|
return abs
|
|
}
|
|
|
|
// absPath is filepath.Abs, isolated for tests.
|
|
var absPath = func(p string) (string, error) {
|
|
return execAbs(p)
|
|
}
|