forked from security/hakurei
internal/pkg: automatic overlay mount on work
This directly submits the upperdir to cache. It is primarily used in bootstrapping where tools are limited and should not be used unless there is a very good reason to. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
@@ -411,6 +411,36 @@ func TestFlatten(t *testing.T) {
|
|||||||
{Mode: fs.ModeDir | 0700, Path: "work"},
|
{Mode: fs.ModeDir | 0700, Path: "work"},
|
||||||
}, pkg.MustDecode("_r1IBeMWCkLwQ9Im9w0tV9_CWIOfQlXkkP2CogPHLmZp_AB6W3_8HVZqDV00dNAm")},
|
}, 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{
|
{"sample file short", fstest.MapFS{
|
||||||
".": {Mode: fs.ModeDir | 0700},
|
".": {Mode: fs.ModeDir | 0700},
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ import (
|
|||||||
"hakurei.app/message"
|
"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
|
// ExecContainerPath is an [Artifact] and the [check.Absolute] pathname to make
|
||||||
// it available under in the container.
|
// it available under in the container.
|
||||||
type ExecContainerPath struct {
|
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.
|
// 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 /work and /tmp respectively. If one or more paths target [fhs.AbsTmp], the
|
// on [AbsWork] and [fhs.AbsTmp] respectively. If one or more paths target
|
||||||
// final entry is set up as a writable overlay mount on /tmp backed by the host
|
// [fhs.AbsTmp], the final entry is set up as a writable overlay mount on /tmp
|
||||||
// side temporary directory.
|
// 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
|
// 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
|
// 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()
|
cures = runtime.NumCPU()
|
||||||
}
|
}
|
||||||
|
|
||||||
overlayTempIndex := -1
|
overlayTempIndex, overlayWorkIndex := -1, -1
|
||||||
paths := make([][2]*check.Absolute, len(a.paths))
|
paths := make([][2]*check.Absolute, len(a.paths))
|
||||||
for i, p := range a.paths {
|
for i, p := range a.paths {
|
||||||
if p.P == nil || p.A == nil {
|
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) {
|
if p.P.Is(fhs.AbsTmp) {
|
||||||
overlayTempIndex = i
|
overlayTempIndex = i
|
||||||
|
} else if p.P.Is(AbsWork) {
|
||||||
|
overlayWorkIndex = i
|
||||||
}
|
}
|
||||||
paths[i][1] = p.P
|
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])
|
z.OverlayEphemeral(fhs.AbsRoot, paths[0][0])
|
||||||
paths = paths[1:]
|
paths = paths[1:]
|
||||||
overlayTempIndex--
|
overlayTempIndex--
|
||||||
|
overlayWorkIndex--
|
||||||
}
|
}
|
||||||
|
|
||||||
|
temp, work := c.GetTempDir(), c.GetWorkDir()
|
||||||
for i, b := range paths {
|
for i, b := range paths {
|
||||||
if i == overlayTempIndex {
|
if i == overlayTempIndex {
|
||||||
temp := c.GetTempDir()
|
|
||||||
tempUpper := temp.Append("upper")
|
tempUpper := temp.Append("upper")
|
||||||
if err = os.MkdirAll(tempUpper.String(), 0700); err != nil {
|
if err = os.MkdirAll(tempUpper.String(), 0700); err != nil {
|
||||||
return
|
return
|
||||||
@@ -301,14 +312,31 @@ func (a *execArtifact) cure(c *CureContext, hostNet bool) (err error) {
|
|||||||
)
|
)
|
||||||
continue
|
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)
|
z.Bind(b[0], b[1], 0)
|
||||||
}
|
}
|
||||||
work := c.GetWorkDir()
|
if overlayWorkIndex < 0 {
|
||||||
z.Bind(
|
z.Bind(
|
||||||
work,
|
work,
|
||||||
fhs.AbsRoot.Append("work"),
|
AbsWork,
|
||||||
std.BindWritable|std.BindEnsure,
|
std.BindWritable|std.BindEnsure,
|
||||||
)
|
)
|
||||||
|
}
|
||||||
if overlayTempIndex < 0 {
|
if overlayTempIndex < 0 {
|
||||||
z.Bind(
|
z.Bind(
|
||||||
c.GetTempDir(),
|
c.GetTempDir(),
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ func TestExec(t *testing.T) {
|
|||||||
msg,
|
msg,
|
||||||
0,
|
0,
|
||||||
nil,
|
nil,
|
||||||
check.MustAbs("/work"),
|
pkg.AbsWork,
|
||||||
[]string{"HAKUREI_TEST=1"},
|
[]string{"HAKUREI_TEST=1"},
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
check.MustAbs("/opt/bin/testtool"),
|
||||||
[]string{"testtool"},
|
[]string{"testtool"},
|
||||||
@@ -71,7 +71,7 @@ func TestExec(t *testing.T) {
|
|||||||
msg,
|
msg,
|
||||||
0,
|
0,
|
||||||
nil,
|
nil,
|
||||||
check.MustAbs("/work"),
|
pkg.AbsWork,
|
||||||
[]string{"HAKUREI_TEST=1"},
|
[]string{"HAKUREI_TEST=1"},
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
check.MustAbs("/opt/bin/testtool"),
|
||||||
[]string{"testtool"},
|
[]string{"testtool"},
|
||||||
@@ -90,7 +90,7 @@ func TestExec(t *testing.T) {
|
|||||||
msg,
|
msg,
|
||||||
0,
|
0,
|
||||||
nil,
|
nil,
|
||||||
check.MustAbs("/work"),
|
pkg.AbsWork,
|
||||||
[]string{"HAKUREI_TEST=1"},
|
[]string{"HAKUREI_TEST=1"},
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
check.MustAbs("/opt/bin/testtool"),
|
||||||
[]string{"testtool"},
|
[]string{"testtool"},
|
||||||
@@ -106,7 +106,7 @@ func TestExec(t *testing.T) {
|
|||||||
msg,
|
msg,
|
||||||
0,
|
0,
|
||||||
nil,
|
nil,
|
||||||
check.MustAbs("/work"),
|
pkg.AbsWork,
|
||||||
nil,
|
nil,
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
check.MustAbs("/opt/bin/testtool"),
|
||||||
[]string{"testtool"},
|
[]string{"testtool"},
|
||||||
@@ -134,7 +134,7 @@ func TestExec(t *testing.T) {
|
|||||||
msg,
|
msg,
|
||||||
0,
|
0,
|
||||||
&wantChecksum,
|
&wantChecksum,
|
||||||
check.MustAbs("/work"),
|
pkg.AbsWork,
|
||||||
[]string{"HAKUREI_TEST=1"},
|
[]string{"HAKUREI_TEST=1"},
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
check.MustAbs("/opt/bin/testtool"),
|
||||||
[]string{"testtool", "net"},
|
[]string{"testtool", "net"},
|
||||||
@@ -172,7 +172,7 @@ func TestExec(t *testing.T) {
|
|||||||
msg,
|
msg,
|
||||||
0,
|
0,
|
||||||
nil,
|
nil,
|
||||||
check.MustAbs("/work"),
|
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"),
|
||||||
[]string{"testtool"},
|
[]string{"testtool"},
|
||||||
@@ -204,7 +204,7 @@ func TestExec(t *testing.T) {
|
|||||||
msg,
|
msg,
|
||||||
0,
|
0,
|
||||||
nil,
|
nil,
|
||||||
check.MustAbs("/work"),
|
pkg.AbsWork,
|
||||||
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
|
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
|
||||||
check.MustAbs("/tmp/bin/testtool"),
|
check.MustAbs("/tmp/bin/testtool"),
|
||||||
[]string{"testtool"},
|
[]string{"testtool"},
|
||||||
@@ -232,6 +232,48 @@ func TestExec(t *testing.T) {
|
|||||||
|
|
||||||
testtoolDestroy(t, base, c)
|
testtoolDestroy(t, base, c)
|
||||||
}, pkg.MustDecode("_r1IBeMWCkLwQ9Im9w0tV9_CWIOfQlXkkP2CogPHLmZp_AB6W3_8HVZqDV00dNAm")},
|
}, 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")},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
29
internal/pkg/testdata/main.go
vendored
29
internal/pkg/testdata/main.go
vendored
@@ -40,18 +40,25 @@ func main() {
|
|||||||
log.Fatalf("Environ: %q, want %q", os.Environ(), wantEnv)
|
log.Fatalf("Environ: %q, want %q", os.Environ(), wantEnv)
|
||||||
}
|
}
|
||||||
|
|
||||||
var overlayTmp bool
|
var overlayTmp, overlayWork bool
|
||||||
const (
|
const (
|
||||||
wantExec = "/opt/bin/testtool"
|
wantExec = "/opt/bin/testtool"
|
||||||
wantExecOverlay = "/tmp/bin/testtool"
|
wantExecTmp = "/tmp/bin/testtool"
|
||||||
|
wantExecWork = "/work/bin/testtool"
|
||||||
)
|
)
|
||||||
if got, err := os.Executable(); err != nil {
|
if got, err := os.Executable(); err != nil {
|
||||||
log.Fatalf("Executable: error = %v", err)
|
log.Fatalf("Executable: error = %v", err)
|
||||||
} else if got != wantExec {
|
} 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)
|
log.Fatalf("Executable: %q, want %q", got, wantExec)
|
||||||
}
|
}
|
||||||
overlayTmp = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wantHostname := "cure"
|
wantHostname := "cure"
|
||||||
@@ -153,8 +160,16 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
next()
|
next()
|
||||||
if path.Base(m.Root) != ident || m.Target != "/work" {
|
if overlayWork {
|
||||||
log.Fatal("unexpected work mount entry")
|
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 {
|
if !overlayTmp {
|
||||||
|
|||||||
Reference in New Issue
Block a user