internal/pkg: automatic overlay mount on tmp
All checks were successful
Test / Create distribution (push) Successful in 52s
Test / Sandbox (push) Successful in 2m54s
Test / ShareFS (push) Successful in 4m46s
Test / Sandbox (race detector) (push) Successful in 5m20s
Test / Hakurei (push) Successful in 5m35s
Test / Hpkg (push) Successful in 5m34s
Test / Hakurei (race detector) (push) Successful in 7m37s
Test / Flake checks (push) Successful in 1m48s
All checks were successful
Test / Create distribution (push) Successful in 52s
Test / Sandbox (push) Successful in 2m54s
Test / ShareFS (push) Successful in 4m46s
Test / Sandbox (race detector) (push) Successful in 5m20s
Test / Hakurei (push) Successful in 5m35s
Test / Hpkg (push) Successful in 5m34s
Test / Hakurei (race detector) (push) Successful in 7m37s
Test / Flake checks (push) Successful in 1m48s
This sets up the last Artifact to target /tmp as a writable overlay mount backed by the host side temp directory. This is useful for an Artifact containing source code to be built for another Artifact for example. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
@@ -380,6 +380,36 @@ func TestFlatten(t *testing.T) {
|
||||
{Mode: fs.ModeDir | 0700, Path: "temp"},
|
||||
{Mode: fs.ModeDir | 0700, Path: "work"},
|
||||
}, pkg.MustDecode("gFT9kprYBqEJKifJIl2sHn_3TgULWVLTU4DrYAHiGcRmcdFRZ0YtjiROW820cAEc")},
|
||||
|
||||
{"sample exec container overlay temp", 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/3ELJ8l42g6XeIoLGR9LheVhMIwSIleD6VrhsliBuon5DAdBOwFSMqd7aiUI4fll7": {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/3ELJ8l42g6XeIoLGR9LheVhMIwSIleD6VrhsliBuon5DAdBOwFSMqd7aiUI4fll7", 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("_r1IBeMWCkLwQ9Im9w0tV9_CWIOfQlXkkP2CogPHLmZp_AB6W3_8HVZqDV00dNAm")},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
|
||||
@@ -89,7 +89,9 @@ 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.
|
||||
// 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.
|
||||
//
|
||||
// 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
|
||||
@@ -273,18 +275,46 @@ func (a *execArtifact) cure(c *CureContext, hostNet bool) (err error) {
|
||||
z.OverlayEphemeral(fhs.AbsRoot, paths[0][0])
|
||||
paths = paths[1:]
|
||||
}
|
||||
var overlayTemp *check.Absolute
|
||||
for _, b := range paths {
|
||||
if b[1].Is(fhs.AbsTmp) {
|
||||
if overlayTemp != nil {
|
||||
z.Bind(overlayTemp, fhs.AbsTmp, 0)
|
||||
}
|
||||
overlayTemp = b[0]
|
||||
continue
|
||||
}
|
||||
z.Bind(b[0], b[1], 0)
|
||||
}
|
||||
z.Bind(
|
||||
c.GetWorkDir(),
|
||||
fhs.AbsRoot.Append("work"),
|
||||
std.BindWritable|std.BindEnsure,
|
||||
).Bind(
|
||||
c.GetTempDir(),
|
||||
fhs.AbsTmp,
|
||||
std.BindWritable|std.BindEnsure,
|
||||
).Proc(fhs.AbsProc).Dev(fhs.AbsDev, true)
|
||||
)
|
||||
if overlayTemp == nil {
|
||||
z.Bind(
|
||||
c.GetTempDir(),
|
||||
fhs.AbsTmp,
|
||||
std.BindWritable|std.BindEnsure,
|
||||
)
|
||||
} else {
|
||||
temp := c.GetTempDir()
|
||||
tempUpper := temp.Append("upper")
|
||||
if err = os.MkdirAll(tempUpper.String(), 0700); err != nil {
|
||||
return
|
||||
}
|
||||
tempWork := temp.Append("work")
|
||||
if err = os.MkdirAll(tempWork.String(), 0700); err != nil {
|
||||
return
|
||||
}
|
||||
z.Overlay(
|
||||
fhs.AbsTmp,
|
||||
tempUpper,
|
||||
tempWork,
|
||||
overlayTemp,
|
||||
)
|
||||
}
|
||||
z.Proc(fhs.AbsProc).Dev(fhs.AbsDev, true)
|
||||
|
||||
if err = z.Start(); err != nil {
|
||||
return
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"hakurei.app/container/check"
|
||||
"hakurei.app/container/fhs"
|
||||
"hakurei.app/container/stub"
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/internal/pkg"
|
||||
@@ -189,6 +190,48 @@ func TestExec(t *testing.T) {
|
||||
|
||||
testtoolDestroy(t, base, c)
|
||||
}, pkg.MustDecode("gFT9kprYBqEJKifJIl2sHn_3TgULWVLTU4DrYAHiGcRmcdFRZ0YtjiROW820cAEc")},
|
||||
|
||||
{"overlay temp", 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,
|
||||
check.MustAbs("/work"),
|
||||
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
|
||||
check.MustAbs("/tmp/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("/tmp/", stubArtifact{
|
||||
kind: pkg.KindTar,
|
||||
params: []byte("empty directory"),
|
||||
cure: func(c *pkg.CureContext) error {
|
||||
return os.MkdirAll(c.GetWorkDir().String(), 0700)
|
||||
},
|
||||
}),
|
||||
pkg.ExecContainerPath{
|
||||
P: fhs.AbsTmp,
|
||||
A: testtool,
|
||||
},
|
||||
), ignorePathname, wantChecksumOffline, nil},
|
||||
})
|
||||
|
||||
testtoolDestroy(t, base, c)
|
||||
}, pkg.MustDecode("_r1IBeMWCkLwQ9Im9w0tV9_CWIOfQlXkkP2CogPHLmZp_AB6W3_8HVZqDV00dNAm")},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
36
internal/pkg/testdata/main.go
vendored
36
internal/pkg/testdata/main.go
vendored
@@ -39,11 +39,19 @@ func main() {
|
||||
if !slices.Equal(wantEnv, os.Environ()) {
|
||||
log.Fatalf("Environ: %q, want %q", os.Environ(), wantEnv)
|
||||
}
|
||||
const wantExec = "/opt/bin/testtool"
|
||||
|
||||
var overlayTmp bool
|
||||
const (
|
||||
wantExec = "/opt/bin/testtool"
|
||||
wantExecOverlay = "/tmp/bin/testtool"
|
||||
)
|
||||
if got, err := os.Executable(); err != nil {
|
||||
log.Fatalf("Executable: error = %v", err)
|
||||
} else if got != wantExec {
|
||||
log.Fatalf("Executable: %q, want %q", got, wantExec)
|
||||
if got != wantExecOverlay {
|
||||
log.Fatalf("Executable: %q, want %q", got, wantExec)
|
||||
}
|
||||
overlayTmp = true
|
||||
}
|
||||
|
||||
wantHostname := "cure"
|
||||
@@ -105,7 +113,6 @@ func main() {
|
||||
if path.Base(lowerdir) != checksumEmptyDir {
|
||||
log.Fatal("unexpected artifact checksum")
|
||||
}
|
||||
|
||||
} else {
|
||||
if hostNet {
|
||||
ident = "I3T53NtN6HPAyyodHtq2B0clcsoS1nPdvCEb-Zc5K-hoqFGL2od1mftHhwG7gX1S"
|
||||
@@ -126,7 +133,16 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
next() // testtool artifact
|
||||
if !overlayTmp {
|
||||
next() // testtool artifact
|
||||
} else {
|
||||
ident = "3ELJ8l42g6XeIoLGR9LheVhMIwSIleD6VrhsliBuon5DAdBOwFSMqd7aiUI4fll7"
|
||||
|
||||
next()
|
||||
if path.Base(m.Root) != checksumEmptyDir || m.Target != "/tmp" {
|
||||
log.Fatal("unexpected artifact checksum")
|
||||
}
|
||||
}
|
||||
|
||||
next()
|
||||
if path.Base(m.Root) != ident || m.Target != "/work" {
|
||||
@@ -134,8 +150,16 @@ func main() {
|
||||
}
|
||||
|
||||
next()
|
||||
if path.Base(m.Root) != ident || m.Target != "/tmp" {
|
||||
log.Fatal("unexpected temp mount entry")
|
||||
if !overlayTmp {
|
||||
if path.Base(m.Root) != ident || m.Target != "/tmp" {
|
||||
log.Fatal("unexpected temp mount entry")
|
||||
}
|
||||
} else {
|
||||
// testtool artifact
|
||||
if m.Root != "/" || m.Target != "/tmp" ||
|
||||
m.Source != "overlay" || m.FsType != "overlay" {
|
||||
log.Fatal("unexpected temp mount entry")
|
||||
}
|
||||
}
|
||||
|
||||
next()
|
||||
|
||||
Reference in New Issue
Block a user