Documentation
¶
Overview ¶
Package executor runs a runner's command somewhere (ADR-007). Contained executors (docker) are required for unattended lanes; process is for interactive steps and shadow mode only. Every run gets its own worktree, run folder and tool caches.
Index ¶
- Constants
- Variables
- func ResolveUser(spec string, lookup func(name string) (uint32, error)) (uint32, error)
- type Docker
- func (d Docker) Args(j Job, name, network string) ([]string, error)
- func (Docker) Contained() bool
- func (Docker) Name() string
- func (Docker) Paths(Job) (string, string)
- func (d Docker) ProxyArgs(j Job, name string) []string
- func (d Docker) Run(ctx context.Context, j Job) (Output, error)
- func (d Docker) RunUID(ctx context.Context, j Job) (uint32, bool, error)
- func (Docker) SpoolVolume() bool
- type Executor
- type Inline
- type Job
- type Output
- type Process
- type RunUser
- type SpoolVolumes
Constants ¶
const ( WorkDir = "/work" RunDir = "/run/ynf" SpoolDir = spool.ContainerPath )
Container paths: what a contained command sees.
Variables ¶
var ErrEgress = errors.New("this lane allows egress, which needs the egress proxy: a linux ynf binary (make build, or YNF_LINUX_BINARY)")
ErrEgress means the lane allows hosts but the egress proxy cannot be started. A containment control that cannot be applied is an error, never a warning (ADR-007).
Functions ¶
Types ¶
type Docker ¶
type Docker struct {
Bin string
ProxyBinary string // a static linux ynf, run as the egress proxy
ProxyImage string // the image the proxy runs in; default alpine:3.20
}
Docker runs the command in a container: no network at all when the lane allows no hosts, and otherwise an internal network whose only way out is ynf's allow-list proxy (ADR-007).
func (Docker) Args ¶
Args builds the job's docker command line for a container name and network; it is separate from Run so it can be tested.
func (Docker) RunUID ¶
RunUID implements RunUser: a run that keeps its image's own user writes as the user the image names, found in the image's configuration, and in the image's /etc/passwd when it names the user rather than numbering it. Any other docker run is ynf's own user (--user).
func (Docker) SpoolVolume ¶
SpoolVolume implements SpoolVolumes. Docker Desktop for Mac cannot bind-mount a host folder that is a mount of its own: the daemon fails with "error while creating mount source path ... file exists", so a run there keeps a plain folder and the quota watcher. A docker daemon on Linux binds one like any folder.
type Executor ¶
type Executor interface {
Name() string
// Contained reports whether the executor confines the run (ADR-007).
Contained() bool
// Paths returns the worktree and run folder as the command sees them.
Paths(j Job) (worktree, runDir string)
Run(ctx context.Context, j Job) (Output, error)
}
Executor runs jobs.
type Inline ¶
type Inline struct {
// User is the user runs run as; default ynh, the user an agent image is built for.
User string
// Chown changes a path's owner; nil is os.Lchown. For tests.
Chown func(path string, uid, gid int) error
// Credential sets the user a command runs as; nil runs it as that user. For tests.
Credential func(c *exec.Cmd, uid, gid uint32)
}
Inline runs the runner as a process inside the container ynf itself runs in: the factory image, as a job (ADR-007, ADR-009). The job runner provides the containment (the network policy, the dropped capabilities); ynf keeps its credentials from the run by running it as another user.
ynf runs as root in the container with only SETUID, SETGID and CHOWN. Before a run it hands the run's folders to the run user; it starts the run as that user with only the run's own environment; afterwards it takes the folders back. The run cannot read ynf's environment or memory (another user, no SYS_PTRACE) or its token.
func (Inline) Contained ¶
Contained implements Executor: the operator declared the containment (ADR-007).
type Job ¶
type Job struct {
Argv []string
Env map[string]string
Worktree string // host path, real (no symlinks)
RunDir string // host path for the run's files and caches
Image string
Egress []string
Timeout time.Duration
// ImageUser keeps the image's own user and home: an agent image built by ynh keeps its
// harness and vendor configuration under its user's home.
ImageUser bool
// Secrets reach the run by name only: docker reads each value from its own environment, so a
// secret never appears in a command line or a process listing.
Secrets map[string]string
Share []string
// Spool is the run's own spool folder on the host, when it has one (ynr ADR-004): the run
// writes its telemetry there, as YNR_SPOOL. A docker run has this folder mounted at SpoolDir,
// and nothing else of the spool; the inline executor hands it to the run user.
Spool string
// NoOTLP starts the run without the operator's OTEL_EXPORTER_OTLP_*: the collector is on, and
// ynr serve ships to the operator's endpoint instead.
NoOTLP bool
}
Job is one run.
type Output ¶
type Output struct {
Exit int
Stdout []byte
Stderr []byte
Denied []string // hosts the egress proxy refused
}
Output is how the command ended.
type Process ¶
type Process struct{}
Process runs the command directly on the host. It is not contained, so ynf only allows it for interactive steps and shadow mode (ADR-007).
type RunUser ¶
type RunUser interface {
// RunUID returns the user the run writes as and whether it is another than ynf's own, the
// owner of the run's spool folder. An error means it could not be found out.
RunUID(ctx context.Context, j Job) (uid uint32, other bool, err error)
}
RunUser is implemented by an executor whose run can write as a user other than ynf's own, so the run's spool manifest can name that user (ynr ADR-003). The answer comes from the image's own configuration or the executor's own setting, which the run cannot reach or change.
type SpoolVolumes ¶
type SpoolVolumes interface {
SpoolVolume() bool
}
SpoolVolumes is implemented by an executor that may not be able to use a run's spool folder when it is a volume of its own, in which case the folder stays a plain one.