aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'internal/pkg')
-rw-r--r--internal/pkg/exec.go35
-rw-r--r--internal/pkg/exec_test.go16
2 files changed, 37 insertions, 14 deletions
diff --git a/internal/pkg/exec.go b/internal/pkg/exec.go
index db0cf9f0..2ded00e9 100644
--- a/internal/pkg/exec.go
+++ b/internal/pkg/exec.go
@@ -42,6 +42,13 @@ func MustPath(pathname string, writable bool, a ...Artifact) ExecPath {
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
// part of another [Artifact] in a [container] to produce its output.
//
@@ -59,6 +66,11 @@ type execArtifact struct {
path *check.Absolute
// Passed through to [container.Params].
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
@@ -88,10 +100,9 @@ func (a *execNetArtifact) Cure(f *FContext) error {
return a.cure(f, true)
}
-// NewExec returns a new [Artifact] bounded by ctx, it cures all [Artifact]
-// in paths at the specified maximum concurrent cures limit. Specified paths are
-// bind mounted read-only in the specified order in the resulting container.
-// A private instance of /proc and /dev is made available to the container.
+// NewExec returns a new [Artifact] that executes the program path in a
+// container with specified paths bind mounted read-only in order. A private
+// instance of /proc and /dev is made available to the container.
//
// The working and temporary directories are both created and mounted writable
// 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]
// 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(
checksum *Checksum,
+ timeout time.Duration,
dir *check.Absolute,
env []string,
@@ -113,7 +130,13 @@ func NewExec(
paths ...ExecPath,
) 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 {
return &a
}
@@ -197,7 +220,7 @@ func (a *execArtifact) cure(f *FContext, hostNet bool) (err error) {
artifactCount += len(p.A)
}
- ctx, cancel := context.WithCancel(f.Unwrap())
+ ctx, cancel := context.WithTimeout(f.Unwrap(), a.timeout)
defer cancel()
z := container.New(ctx, f.GetMessage())
diff --git a/internal/pkg/exec_test.go b/internal/pkg/exec_test.go
index 22e0e2f0..b422da39 100644
--- a/internal/pkg/exec_test.go
+++ b/internal/pkg/exec_test.go
@@ -38,7 +38,7 @@ func TestExec(t *testing.T) {
cureMany(t, c, []cureStep{
{"container", pkg.NewExec(
- nil,
+ nil, 0,
pkg.AbsWork,
[]string{"HAKUREI_TEST=1"},
check.MustAbs("/opt/bin/testtool"),
@@ -61,7 +61,7 @@ func TestExec(t *testing.T) {
), ignorePathname, wantChecksumOffline, nil},
{"error passthrough", pkg.NewExec(
- nil,
+ nil, 0,
pkg.AbsWork,
[]string{"HAKUREI_TEST=1"},
check.MustAbs("/opt/bin/testtool"),
@@ -77,7 +77,7 @@ func TestExec(t *testing.T) {
), nil, pkg.Checksum{}, errors.Join(stub.UniqueError(0xcafe))},
{"invalid paths", pkg.NewExec(
- nil,
+ nil, 0,
pkg.AbsWork,
[]string{"HAKUREI_TEST=1"},
check.MustAbs("/opt/bin/testtool"),
@@ -90,7 +90,7 @@ func TestExec(t *testing.T) {
// check init failure passthrough
var exitError *exec.ExitError
if _, _, err := c.Cure(pkg.NewExec(
- nil,
+ nil, 0,
pkg.AbsWork,
nil,
check.MustAbs("/opt/bin/testtool"),
@@ -112,7 +112,7 @@ func TestExec(t *testing.T) {
)
cureMany(t, c, []cureStep{
{"container", pkg.NewExec(
- &wantChecksum,
+ &wantChecksum, 0,
pkg.AbsWork,
[]string{"HAKUREI_TEST=1"},
check.MustAbs("/opt/bin/testtool"),
@@ -144,7 +144,7 @@ func TestExec(t *testing.T) {
cureMany(t, c, []cureStep{
{"container", pkg.NewExec(
- nil,
+ nil, 0,
pkg.AbsWork,
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
check.MustAbs("/opt/bin/testtool"),
@@ -170,7 +170,7 @@ func TestExec(t *testing.T) {
cureMany(t, c, []cureStep{
{"container", pkg.NewExec(
- nil,
+ nil, 0,
pkg.AbsWork,
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
check.MustAbs("/work/bin/testtool"),
@@ -201,7 +201,7 @@ func TestExec(t *testing.T) {
cureMany(t, c, []cureStep{
{"container", pkg.NewExec(
- nil,
+ nil, 0,
pkg.AbsWork,
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
check.MustAbs("/opt/bin/testtool"),