internal/pkg: exec with specific timeout
All checks were successful
Test / Create distribution (push) Successful in 47s
Test / Sandbox (push) Successful in 2m58s
Test / ShareFS (push) Successful in 5m1s
Test / Sandbox (race detector) (push) Successful in 5m24s
Test / Hpkg (push) Successful in 5m29s
Test / Hakurei (push) Successful in 5m49s
Test / Hakurei (race detector) (push) Successful in 7m37s
Test / Flake checks (push) Successful in 1m47s
All checks were successful
Test / Create distribution (push) Successful in 47s
Test / Sandbox (push) Successful in 2m58s
Test / ShareFS (push) Successful in 5m1s
Test / Sandbox (race detector) (push) Successful in 5m24s
Test / Hpkg (push) Successful in 5m29s
Test / Hakurei (push) Successful in 5m49s
Test / Hakurei (race detector) (push) Successful in 7m37s
Test / Flake checks (push) Successful in 1m47s
This change also updates the documentation of NewExec. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
@@ -42,6 +42,13 @@ func MustPath(pathname string, writable bool, a ...Artifact) ExecPath {
|
|||||||
return ExecPath{check.MustAbs(pathname), a, writable}
|
return ExecPath{check.MustAbs(pathname), a, writable}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ExecTimeoutDefault replaces out of range [NewExec] timeout values.
|
||||||
|
ExecTimeoutDefault = 15 * time.Minute
|
||||||
|
// ExecTimeoutMax is the arbitrary upper bound of [NewExec] timeout.
|
||||||
|
ExecTimeoutMax = 48 * time.Hour
|
||||||
|
)
|
||||||
|
|
||||||
// An execArtifact is an [Artifact] that produces output by running a program
|
// An execArtifact is an [Artifact] that produces output by running a program
|
||||||
// part of another [Artifact] in a [container] to produce its output.
|
// part of another [Artifact] in a [container] to produce its output.
|
||||||
//
|
//
|
||||||
@@ -59,6 +66,11 @@ type execArtifact struct {
|
|||||||
path *check.Absolute
|
path *check.Absolute
|
||||||
// Passed through to [container.Params].
|
// Passed through to [container.Params].
|
||||||
args []string
|
args []string
|
||||||
|
|
||||||
|
// Duration the initial process is allowed to run. The zero value is
|
||||||
|
// equivalent to execTimeoutDefault. This value is never encoded in Params
|
||||||
|
// because it cannot affect outcome.
|
||||||
|
timeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// execNetArtifact is like execArtifact but implements [KnownChecksum] and has
|
// execNetArtifact is like execArtifact but implements [KnownChecksum] and has
|
||||||
@@ -88,10 +100,9 @@ func (a *execNetArtifact) Cure(f *FContext) error {
|
|||||||
return a.cure(f, true)
|
return a.cure(f, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewExec returns a new [Artifact] bounded by ctx, it cures all [Artifact]
|
// NewExec returns a new [Artifact] that executes the program path in a
|
||||||
// in paths at the specified maximum concurrent cures limit. Specified paths are
|
// container with specified paths bind mounted read-only in order. A private
|
||||||
// bind mounted read-only in the specified order in the resulting container.
|
// instance of /proc and /dev is made available to the container.
|
||||||
// A private instance of /proc and /dev is made available to the container.
|
|
||||||
//
|
//
|
||||||
// The working and temporary directories are both created and mounted writable
|
// The working and temporary directories are both created and mounted writable
|
||||||
// on [AbsWork] and [fhs.AbsTmp] respectively. If one or more paths target
|
// on [AbsWork] and [fhs.AbsTmp] respectively. If one or more paths target
|
||||||
@@ -103,8 +114,14 @@ func (a *execNetArtifact) Cure(f *FContext) error {
|
|||||||
//
|
//
|
||||||
// If checksum is non-nil, the resulting [Artifact] implements [KnownChecksum]
|
// If checksum is non-nil, the resulting [Artifact] implements [KnownChecksum]
|
||||||
// and its container runs in the host net namespace.
|
// and its container runs in the host net namespace.
|
||||||
|
//
|
||||||
|
// The container is allowed to run for the specified duration before the initial
|
||||||
|
// process and all processes originating from it is terminated. A zero or
|
||||||
|
// negative timeout value is equivalent tp [ExecTimeoutDefault], a timeout value
|
||||||
|
// greater than [ExecTimeoutMax] is equivalent to [ExecTimeoutMax].
|
||||||
func NewExec(
|
func NewExec(
|
||||||
checksum *Checksum,
|
checksum *Checksum,
|
||||||
|
timeout time.Duration,
|
||||||
|
|
||||||
dir *check.Absolute,
|
dir *check.Absolute,
|
||||||
env []string,
|
env []string,
|
||||||
@@ -113,7 +130,13 @@ func NewExec(
|
|||||||
|
|
||||||
paths ...ExecPath,
|
paths ...ExecPath,
|
||||||
) Artifact {
|
) Artifact {
|
||||||
a := execArtifact{paths, dir, env, path, args}
|
if timeout <= 0 {
|
||||||
|
timeout = ExecTimeoutDefault
|
||||||
|
}
|
||||||
|
if timeout > ExecTimeoutMax {
|
||||||
|
timeout = ExecTimeoutMax
|
||||||
|
}
|
||||||
|
a := execArtifact{paths, dir, env, path, args, timeout}
|
||||||
if checksum == nil {
|
if checksum == nil {
|
||||||
return &a
|
return &a
|
||||||
}
|
}
|
||||||
@@ -197,7 +220,7 @@ func (a *execArtifact) cure(f *FContext, hostNet bool) (err error) {
|
|||||||
artifactCount += len(p.A)
|
artifactCount += len(p.A)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(f.Unwrap())
|
ctx, cancel := context.WithTimeout(f.Unwrap(), a.timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
z := container.New(ctx, f.GetMessage())
|
z := container.New(ctx, f.GetMessage())
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ func TestExec(t *testing.T) {
|
|||||||
|
|
||||||
cureMany(t, c, []cureStep{
|
cureMany(t, c, []cureStep{
|
||||||
{"container", pkg.NewExec(
|
{"container", pkg.NewExec(
|
||||||
nil,
|
nil, 0,
|
||||||
pkg.AbsWork,
|
pkg.AbsWork,
|
||||||
[]string{"HAKUREI_TEST=1"},
|
[]string{"HAKUREI_TEST=1"},
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
check.MustAbs("/opt/bin/testtool"),
|
||||||
@@ -61,7 +61,7 @@ func TestExec(t *testing.T) {
|
|||||||
), ignorePathname, wantChecksumOffline, nil},
|
), ignorePathname, wantChecksumOffline, nil},
|
||||||
|
|
||||||
{"error passthrough", pkg.NewExec(
|
{"error passthrough", pkg.NewExec(
|
||||||
nil,
|
nil, 0,
|
||||||
pkg.AbsWork,
|
pkg.AbsWork,
|
||||||
[]string{"HAKUREI_TEST=1"},
|
[]string{"HAKUREI_TEST=1"},
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
check.MustAbs("/opt/bin/testtool"),
|
||||||
@@ -77,7 +77,7 @@ func TestExec(t *testing.T) {
|
|||||||
), nil, pkg.Checksum{}, errors.Join(stub.UniqueError(0xcafe))},
|
), nil, pkg.Checksum{}, errors.Join(stub.UniqueError(0xcafe))},
|
||||||
|
|
||||||
{"invalid paths", pkg.NewExec(
|
{"invalid paths", pkg.NewExec(
|
||||||
nil,
|
nil, 0,
|
||||||
pkg.AbsWork,
|
pkg.AbsWork,
|
||||||
[]string{"HAKUREI_TEST=1"},
|
[]string{"HAKUREI_TEST=1"},
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
check.MustAbs("/opt/bin/testtool"),
|
||||||
@@ -90,7 +90,7 @@ func TestExec(t *testing.T) {
|
|||||||
// check init failure passthrough
|
// check init failure passthrough
|
||||||
var exitError *exec.ExitError
|
var exitError *exec.ExitError
|
||||||
if _, _, err := c.Cure(pkg.NewExec(
|
if _, _, err := c.Cure(pkg.NewExec(
|
||||||
nil,
|
nil, 0,
|
||||||
pkg.AbsWork,
|
pkg.AbsWork,
|
||||||
nil,
|
nil,
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
check.MustAbs("/opt/bin/testtool"),
|
||||||
@@ -112,7 +112,7 @@ func TestExec(t *testing.T) {
|
|||||||
)
|
)
|
||||||
cureMany(t, c, []cureStep{
|
cureMany(t, c, []cureStep{
|
||||||
{"container", pkg.NewExec(
|
{"container", pkg.NewExec(
|
||||||
&wantChecksum,
|
&wantChecksum, 0,
|
||||||
pkg.AbsWork,
|
pkg.AbsWork,
|
||||||
[]string{"HAKUREI_TEST=1"},
|
[]string{"HAKUREI_TEST=1"},
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
check.MustAbs("/opt/bin/testtool"),
|
||||||
@@ -144,7 +144,7 @@ func TestExec(t *testing.T) {
|
|||||||
|
|
||||||
cureMany(t, c, []cureStep{
|
cureMany(t, c, []cureStep{
|
||||||
{"container", pkg.NewExec(
|
{"container", pkg.NewExec(
|
||||||
nil,
|
nil, 0,
|
||||||
pkg.AbsWork,
|
pkg.AbsWork,
|
||||||
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
|
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
check.MustAbs("/opt/bin/testtool"),
|
||||||
@@ -170,7 +170,7 @@ func TestExec(t *testing.T) {
|
|||||||
|
|
||||||
cureMany(t, c, []cureStep{
|
cureMany(t, c, []cureStep{
|
||||||
{"container", pkg.NewExec(
|
{"container", pkg.NewExec(
|
||||||
nil,
|
nil, 0,
|
||||||
pkg.AbsWork,
|
pkg.AbsWork,
|
||||||
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
|
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
|
||||||
check.MustAbs("/work/bin/testtool"),
|
check.MustAbs("/work/bin/testtool"),
|
||||||
@@ -201,7 +201,7 @@ func TestExec(t *testing.T) {
|
|||||||
|
|
||||||
cureMany(t, c, []cureStep{
|
cureMany(t, c, []cureStep{
|
||||||
{"container", pkg.NewExec(
|
{"container", pkg.NewExec(
|
||||||
nil,
|
nil, 0,
|
||||||
pkg.AbsWork,
|
pkg.AbsWork,
|
||||||
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
|
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
check.MustAbs("/opt/bin/testtool"),
|
||||||
|
|||||||
Reference in New Issue
Block a user