aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--internal/pkg/dir_test.go30
-rw-r--r--internal/pkg/exec.go50
-rw-r--r--internal/pkg/exec_test.go56
-rw-r--r--internal/pkg/testdata/main.go29
4 files changed, 140 insertions, 25 deletions
diff --git a/internal/pkg/dir_test.go b/internal/pkg/dir_test.go
index 87683fbb..798d0d03 100644
--- a/internal/pkg/dir_test.go
+++ b/internal/pkg/dir_test.go
@@ -411,6 +411,36 @@ func TestFlatten(t *testing.T) {
{Mode: fs.ModeDir | 0700, Path: "work"},
}, pkg.MustDecode("_r1IBeMWCkLwQ9Im9w0tV9_CWIOfQlXkkP2CogPHLmZp_AB6W3_8HVZqDV00dNAm")},
+ {"sample exec container overlay work", fstest.MapFS{
+ ".": {Mode: fs.ModeDir | 0700},
+
+ "checksum": {Mode: fs.ModeDir | 0700},
+ "checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9": {Mode: fs.ModeDir | 0500},
+ "checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9/check": {Mode: 0400, Data: []byte{0}},
+ "checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500},
+
+ "identifier": {Mode: fs.ModeDir | 0700},
+ "identifier/VMCurZKCA_MV80zb-ZBWVytfl3rhYOKJeo2u9l-OuaytQ_w_r4EsqgJ2nfO93x5_": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9")},
+ "identifier/nfeISfLeFDr1k-g3hpE1oZ440kTqDdfF8TDpoLdbTPqaMMIl95oiqcvqjRkMjubA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
+
+ "temp": {Mode: fs.ModeDir | 0700},
+ "work": {Mode: fs.ModeDir | 0700},
+ }, []pkg.FlatEntry{
+ {Mode: fs.ModeDir | 0700, Path: "."},
+
+ {Mode: fs.ModeDir | 0700, Path: "checksum"},
+ {Mode: fs.ModeDir | 0500, Path: "checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9"},
+ {Mode: 0400, Path: "checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9/check", Data: []byte{0}},
+ {Mode: fs.ModeDir | 0500, Path: "checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU"},
+
+ {Mode: fs.ModeDir | 0700, Path: "identifier"},
+ {Mode: fs.ModeSymlink | 0777, Path: "identifier/VMCurZKCA_MV80zb-ZBWVytfl3rhYOKJeo2u9l-OuaytQ_w_r4EsqgJ2nfO93x5_", Data: []byte("../checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9")},
+ {Mode: fs.ModeSymlink | 0777, Path: "identifier/nfeISfLeFDr1k-g3hpE1oZ440kTqDdfF8TDpoLdbTPqaMMIl95oiqcvqjRkMjubA", Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
+
+ {Mode: fs.ModeDir | 0700, Path: "temp"},
+ {Mode: fs.ModeDir | 0700, Path: "work"},
+ }, pkg.MustDecode("-DrfvuB9gUAT-Tgw6V1KjFyosYGMGKJW7KMZFF1Ew8jZ9LJ82FtXf0wTgM3fO0oD")},
+
{"sample file short", fstest.MapFS{
".": {Mode: fs.ModeDir | 0700},
diff --git a/internal/pkg/exec.go b/internal/pkg/exec.go
index 6e050b15..8d736b5b 100644
--- a/internal/pkg/exec.go
+++ b/internal/pkg/exec.go
@@ -16,6 +16,9 @@ import (
"hakurei.app/message"
)
+// AbsWork is the container pathname [CureContext.GetWorkDir] is mounted on.
+var AbsWork = fhs.AbsRoot.Append("work/")
+
// ExecContainerPath is an [Artifact] and the [check.Absolute] pathname to make
// it available under in the container.
type ExecContainerPath struct {
@@ -90,9 +93,14 @@ func (a *execNetArtifact) Cure(c *CureContext) error {
// 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 /work and /tmp respectively. If one or more paths target [fhs.AbsTmp], the
-// final entry is set up as a writable overlay mount on /tmp backed by the host
-// side temporary directory.
+// on [AbsWork] and [fhs.AbsTmp] respectively. If one or more paths target
+// [fhs.AbsTmp], the final entry is set up as a writable overlay mount on /tmp
+// backed by the host side temporary directory. If one or more paths target
+// [AbsWork], the final entry is set up as a writable overlay mount on /work for
+// which the upperdir is the host side work directory. In this configuration,
+// the program must avoid causing whiteout files to be created, cure fails if
+// upperdir ends up with anything other than directory, regular or symlink
+// entries.
//
// If the first path targets [fhs.AbsRoot], it is made writable via an overlay
// mount with writes going to an ephemeral tmpfs bound to the lifetime of the
@@ -186,7 +194,7 @@ func (a *execArtifact) cure(c *CureContext, hostNet bool) (err error) {
cures = runtime.NumCPU()
}
- overlayTempIndex := -1
+ overlayTempIndex, overlayWorkIndex := -1, -1
paths := make([][2]*check.Absolute, len(a.paths))
for i, p := range a.paths {
if p.P == nil || p.A == nil {
@@ -194,6 +202,8 @@ func (a *execArtifact) cure(c *CureContext, hostNet bool) (err error) {
}
if p.P.Is(fhs.AbsTmp) {
overlayTempIndex = i
+ } else if p.P.Is(AbsWork) {
+ overlayWorkIndex = i
}
paths[i][1] = p.P
}
@@ -280,11 +290,12 @@ func (a *execArtifact) cure(c *CureContext, hostNet bool) (err error) {
z.OverlayEphemeral(fhs.AbsRoot, paths[0][0])
paths = paths[1:]
overlayTempIndex--
+ overlayWorkIndex--
}
+ temp, work := c.GetTempDir(), c.GetWorkDir()
for i, b := range paths {
if i == overlayTempIndex {
- temp := c.GetTempDir()
tempUpper := temp.Append("upper")
if err = os.MkdirAll(tempUpper.String(), 0700); err != nil {
return
@@ -301,14 +312,31 @@ func (a *execArtifact) cure(c *CureContext, hostNet bool) (err error) {
)
continue
}
+ if i == overlayWorkIndex {
+ if err = os.MkdirAll(work.String(), 0700); err != nil {
+ return
+ }
+ tempWork := temp.Append(".work")
+ if err = os.MkdirAll(tempWork.String(), 0700); err != nil {
+ return
+ }
+ z.Overlay(
+ AbsWork,
+ work,
+ tempWork,
+ b[0],
+ )
+ continue
+ }
z.Bind(b[0], b[1], 0)
}
- work := c.GetWorkDir()
- z.Bind(
- work,
- fhs.AbsRoot.Append("work"),
- std.BindWritable|std.BindEnsure,
- )
+ if overlayWorkIndex < 0 {
+ z.Bind(
+ work,
+ AbsWork,
+ std.BindWritable|std.BindEnsure,
+ )
+ }
if overlayTempIndex < 0 {
z.Bind(
c.GetTempDir(),
diff --git a/internal/pkg/exec_test.go b/internal/pkg/exec_test.go
index d1b88766..680f0ce1 100644
--- a/internal/pkg/exec_test.go
+++ b/internal/pkg/exec_test.go
@@ -45,7 +45,7 @@ func TestExec(t *testing.T) {
msg,
0,
nil,
- check.MustAbs("/work"),
+ pkg.AbsWork,
[]string{"HAKUREI_TEST=1"},
check.MustAbs("/opt/bin/testtool"),
[]string{"testtool"},
@@ -71,7 +71,7 @@ func TestExec(t *testing.T) {
msg,
0,
nil,
- check.MustAbs("/work"),
+ pkg.AbsWork,
[]string{"HAKUREI_TEST=1"},
check.MustAbs("/opt/bin/testtool"),
[]string{"testtool"},
@@ -90,7 +90,7 @@ func TestExec(t *testing.T) {
msg,
0,
nil,
- check.MustAbs("/work"),
+ pkg.AbsWork,
[]string{"HAKUREI_TEST=1"},
check.MustAbs("/opt/bin/testtool"),
[]string{"testtool"},
@@ -106,7 +106,7 @@ func TestExec(t *testing.T) {
msg,
0,
nil,
- check.MustAbs("/work"),
+ pkg.AbsWork,
nil,
check.MustAbs("/opt/bin/testtool"),
[]string{"testtool"},
@@ -134,7 +134,7 @@ func TestExec(t *testing.T) {
msg,
0,
&wantChecksum,
- check.MustAbs("/work"),
+ pkg.AbsWork,
[]string{"HAKUREI_TEST=1"},
check.MustAbs("/opt/bin/testtool"),
[]string{"testtool", "net"},
@@ -172,7 +172,7 @@ func TestExec(t *testing.T) {
msg,
0,
nil,
- check.MustAbs("/work"),
+ pkg.AbsWork,
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
check.MustAbs("/opt/bin/testtool"),
[]string{"testtool"},
@@ -204,7 +204,7 @@ func TestExec(t *testing.T) {
msg,
0,
nil,
- check.MustAbs("/work"),
+ pkg.AbsWork,
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
check.MustAbs("/tmp/bin/testtool"),
[]string{"testtool"},
@@ -232,6 +232,48 @@ func TestExec(t *testing.T) {
testtoolDestroy(t, base, c)
}, pkg.MustDecode("_r1IBeMWCkLwQ9Im9w0tV9_CWIOfQlXkkP2CogPHLmZp_AB6W3_8HVZqDV00dNAm")},
+
+ {"overlay work", nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
+ c.SetStrict(true)
+ testtool, testtoolDestroy := newTesttool()
+
+ msg := message.New(log.New(os.Stderr, "container: ", 0))
+ msg.SwapVerbose(testing.Verbose())
+
+ cureMany(t, c, []cureStep{
+ {"container", pkg.NewExec(
+ t.Context(),
+ msg,
+ 0,
+ nil,
+ pkg.AbsWork,
+ []string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
+ check.MustAbs("/work/bin/testtool"),
+ []string{"testtool"},
+
+ pkg.MustPath("/", stubArtifact{
+ kind: pkg.KindTar,
+ params: []byte("empty directory"),
+ cure: func(c *pkg.CureContext) error {
+ return os.MkdirAll(c.GetWorkDir().String(), 0700)
+ },
+ }),
+ pkg.MustPath("/work/", stubArtifact{
+ kind: pkg.KindTar,
+ params: []byte("empty directory"),
+ cure: func(c *pkg.CureContext) error {
+ return os.MkdirAll(c.GetWorkDir().String(), 0700)
+ },
+ }),
+ pkg.ExecContainerPath{
+ P: pkg.AbsWork,
+ A: testtool,
+ },
+ ), ignorePathname, wantChecksumOffline, nil},
+ })
+
+ testtoolDestroy(t, base, c)
+ }, pkg.MustDecode("-DrfvuB9gUAT-Tgw6V1KjFyosYGMGKJW7KMZFF1Ew8jZ9LJ82FtXf0wTgM3fO0oD")},
})
}
diff --git a/internal/pkg/testdata/main.go b/internal/pkg/testdata/main.go
index 6a884a3a..b3ce494c 100644
--- a/internal/pkg/testdata/main.go
+++ b/internal/pkg/testdata/main.go
@@ -40,18 +40,25 @@ func main() {
log.Fatalf("Environ: %q, want %q", os.Environ(), wantEnv)
}
- var overlayTmp bool
+ var overlayTmp, overlayWork bool
const (
- wantExec = "/opt/bin/testtool"
- wantExecOverlay = "/tmp/bin/testtool"
+ wantExec = "/opt/bin/testtool"
+ wantExecTmp = "/tmp/bin/testtool"
+ wantExecWork = "/work/bin/testtool"
)
if got, err := os.Executable(); err != nil {
log.Fatalf("Executable: error = %v", err)
} else if got != wantExec {
- if got != wantExecOverlay {
+ switch got {
+ case wantExecTmp:
+ overlayTmp = true
+
+ case wantExecWork:
+ overlayWork = true
+
+ default:
log.Fatalf("Executable: %q, want %q", got, wantExec)
}
- overlayTmp = true
}
wantHostname := "cure"
@@ -153,8 +160,16 @@ func main() {
}
next()
- if path.Base(m.Root) != ident || m.Target != "/work" {
- log.Fatal("unexpected work mount entry")
+ if overlayWork {
+ ident = "VMCurZKCA_MV80zb-ZBWVytfl3rhYOKJeo2u9l-OuaytQ_w_r4EsqgJ2nfO93x5_"
+ if m.Root != "/" || m.Target != "/work" ||
+ m.Source != "overlay" || m.FsType != "overlay" {
+ log.Fatal("unexpected work mount entry")
+ }
+ } else {
+ if path.Base(m.Root) != ident || m.Target != "/work" {
+ log.Fatal("unexpected work mount entry")
+ }
}
if !overlayTmp {