internal/pkg: isolate container params
All checks were successful
Test / Create distribution (push) Successful in 1m2s
Test / Sandbox (push) Successful in 2m43s
Test / Hakurei (push) Successful in 3m44s
Test / ShareFS (push) Successful in 3m47s
Test / Sandbox (race detector) (push) Successful in 5m12s
Test / Hakurei (race detector) (push) Successful in 6m11s
Test / Flake checks (push) Successful in 1m20s
All checks were successful
Test / Create distribution (push) Successful in 1m2s
Test / Sandbox (push) Successful in 2m43s
Test / Hakurei (push) Successful in 3m44s
Test / ShareFS (push) Successful in 3m47s
Test / Sandbox (race detector) (push) Successful in 5m12s
Test / Hakurei (race detector) (push) Successful in 6m11s
Test / Flake checks (push) Successful in 1m20s
This enables exporting container params for interactive troubleshooting within the cure container. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
@@ -40,14 +40,17 @@ type ExecPath struct {
|
|||||||
W bool
|
W bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSchedIdle is whether to set [std.SCHED_IDLE] scheduling priority.
|
// SetSchedIdle is whether to set [ext.SCHED_IDLE] scheduling priority.
|
||||||
var SetSchedIdle bool
|
var SetSchedIdle bool
|
||||||
|
|
||||||
|
// GetArtifactFunc is the function signature of [FContext.GetArtifact].
|
||||||
|
type GetArtifactFunc func(Artifact) (*check.Absolute, unique.Handle[Checksum])
|
||||||
|
|
||||||
// PromoteLayers returns artifacts with identical-by-content layers promoted to
|
// PromoteLayers returns artifacts with identical-by-content layers promoted to
|
||||||
// the highest priority instance, as if mounted via [ExecPath].
|
// the highest priority instance, as if mounted via [ExecPath].
|
||||||
func PromoteLayers(
|
func PromoteLayers(
|
||||||
artifacts []Artifact,
|
artifacts []Artifact,
|
||||||
getArtifact func(Artifact) (*check.Absolute, unique.Handle[Checksum]),
|
getArtifact GetArtifactFunc,
|
||||||
report func(i int, d Artifact),
|
report func(i int, d Artifact),
|
||||||
) []*check.Absolute {
|
) []*check.Absolute {
|
||||||
layers := make([]*check.Absolute, 0, len(artifacts))
|
layers := make([]*check.Absolute, 0, len(artifacts))
|
||||||
@@ -67,14 +70,14 @@ func PromoteLayers(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// layers returns pathnames collected from A deduplicated via [PromoteLayers].
|
// layers returns pathnames collected from A deduplicated via [PromoteLayers].
|
||||||
func (p *ExecPath) layers(f *FContext) []*check.Absolute {
|
func (p *ExecPath) layers(
|
||||||
msg := f.GetMessage()
|
msg message.Msg,
|
||||||
return PromoteLayers(p.A, f.GetArtifact, func(i int, d Artifact) {
|
getArtifact GetArtifactFunc,
|
||||||
|
ident func(a Artifact) unique.Handle[ID],
|
||||||
|
) []*check.Absolute {
|
||||||
|
return PromoteLayers(p.A, getArtifact, func(i int, d Artifact) {
|
||||||
if msg.IsVerbose() {
|
if msg.IsVerbose() {
|
||||||
msg.Verbosef(
|
msg.Verbosef("promoted layer %d as %s", i, reportName(d, ident(d)))
|
||||||
"promoted layer %d as %s",
|
|
||||||
i, reportName(d, f.cache.Ident(d)),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -382,17 +385,30 @@ func scanVerbose(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrInvalidPaths is returned for an [Artifact] of [KindExec] or
|
||||||
|
// [KindExecNet] specified with invalid paths.
|
||||||
|
ErrInvalidPaths = errors.New("invalid mount point")
|
||||||
|
)
|
||||||
|
|
||||||
// SeccompPresets is the [seccomp] presets used by exec artifacts.
|
// SeccompPresets is the [seccomp] presets used by exec artifacts.
|
||||||
const SeccompPresets = std.PresetStrict &
|
const SeccompPresets = std.PresetStrict &
|
||||||
^(std.PresetDenyNS | std.PresetDenyDevel)
|
^(std.PresetDenyNS | std.PresetDenyDevel)
|
||||||
|
|
||||||
// cure is like Cure but allows optional host net namespace. This is used for
|
// makeContainer sets up the specified temp and work directories and returns the
|
||||||
// the [KnownChecksum] variant where networking is allowed.
|
// corresponding [container.Container] that would have run for cure.
|
||||||
func (a *execArtifact) cure(f *FContext, hostNet bool) (err error) {
|
func (a *execArtifact) makeContainer(
|
||||||
|
ctx context.Context,
|
||||||
|
msg message.Msg,
|
||||||
|
hostNet bool,
|
||||||
|
temp, work *check.Absolute,
|
||||||
|
getArtifact GetArtifactFunc,
|
||||||
|
ident func(a Artifact) unique.Handle[ID],
|
||||||
|
) (z *container.Container, err error) {
|
||||||
overlayWorkIndex := -1
|
overlayWorkIndex := -1
|
||||||
for i, p := range a.paths {
|
for i, p := range a.paths {
|
||||||
if p.P == nil || len(p.A) == 0 {
|
if p.P == nil || len(p.A) == 0 {
|
||||||
return os.ErrInvalid
|
return nil, ErrInvalidPaths
|
||||||
}
|
}
|
||||||
if p.P.Is(AbsWork) {
|
if p.P.Is(AbsWork) {
|
||||||
overlayWorkIndex = i
|
overlayWorkIndex = i
|
||||||
@@ -404,10 +420,7 @@ func (a *execArtifact) cure(f *FContext, hostNet bool) (err error) {
|
|||||||
artifactCount += len(p.A)
|
artifactCount += len(p.A)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(f.Unwrap(), a.timeout)
|
z = container.New(ctx, msg)
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
z := container.New(ctx, f.GetMessage())
|
|
||||||
z.WaitDelay = execWaitDelay
|
z.WaitDelay = execWaitDelay
|
||||||
z.SeccompPresets = SeccompPresets
|
z.SeccompPresets = SeccompPresets
|
||||||
z.SeccompFlags |= seccomp.AllowMultiarch
|
z.SeccompFlags |= seccomp.AllowMultiarch
|
||||||
@@ -421,12 +434,85 @@ func (a *execArtifact) cure(f *FContext, hostNet bool) (err error) {
|
|||||||
}
|
}
|
||||||
z.Uid, z.Gid = (1<<10)-1, (1<<10)-1
|
z.Uid, z.Gid = (1<<10)-1, (1<<10)-1
|
||||||
|
|
||||||
|
z.Dir, z.Env, z.Path, z.Args = a.dir, a.env, a.path, a.args
|
||||||
|
z.Grow(len(a.paths) + 4)
|
||||||
|
|
||||||
|
for i, b := range a.paths {
|
||||||
|
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.layers(msg, getArtifact, ident)...,
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.paths[i].W {
|
||||||
|
tempUpper, tempWork := temp.Append(
|
||||||
|
".upper", strconv.Itoa(i),
|
||||||
|
), temp.Append(
|
||||||
|
".work", strconv.Itoa(i),
|
||||||
|
)
|
||||||
|
if err = os.MkdirAll(tempUpper.String(), 0700); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = os.MkdirAll(tempWork.String(), 0700); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
z.Overlay(b.P, tempUpper, tempWork, b.layers(msg, getArtifact, ident)...)
|
||||||
|
} else if len(b.A) == 1 {
|
||||||
|
pathname, _ := getArtifact(b.A[0])
|
||||||
|
z.Bind(pathname, b.P, 0)
|
||||||
|
} else {
|
||||||
|
z.OverlayReadonly(b.P, b.layers(msg, getArtifact, ident)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if overlayWorkIndex < 0 {
|
||||||
|
z.Bind(
|
||||||
|
work,
|
||||||
|
AbsWork,
|
||||||
|
std.BindWritable|std.BindEnsure,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
z.Bind(
|
||||||
|
temp,
|
||||||
|
fhs.AbsTmp,
|
||||||
|
std.BindWritable|std.BindEnsure,
|
||||||
|
)
|
||||||
|
z.Proc(fhs.AbsProc).Dev(fhs.AbsDev, true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// cure is like Cure but allows optional host net namespace.
|
||||||
|
func (a *execArtifact) cure(f *FContext, hostNet bool) (err error) {
|
||||||
|
ctx, cancel := context.WithTimeout(f.Unwrap(), a.timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
msg := f.GetMessage()
|
||||||
|
var z *container.Container
|
||||||
|
if z, err = a.makeContainer(
|
||||||
|
ctx, msg, hostNet,
|
||||||
|
f.GetTempDir(), f.GetWorkDir(),
|
||||||
|
f.GetArtifact,
|
||||||
|
f.cache.Ident,
|
||||||
|
); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var status io.Writer
|
var status io.Writer
|
||||||
if status, err = f.GetStatusWriter(); err != nil {
|
if status, err = f.GetStatusWriter(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if msg := f.GetMessage(); msg.IsVerbose() {
|
if msg.IsVerbose() {
|
||||||
var stdout, stderr io.ReadCloser
|
var stdout, stderr io.ReadCloser
|
||||||
if stdout, err = z.StdoutPipe(); err != nil {
|
if stdout, err = z.StdoutPipe(); err != nil {
|
||||||
return
|
return
|
||||||
@@ -464,62 +550,6 @@ func (a *execArtifact) cure(f *FContext, hostNet bool) (err error) {
|
|||||||
z.Stdout, z.Stderr = status, status
|
z.Stdout, z.Stderr = status, status
|
||||||
}
|
}
|
||||||
|
|
||||||
z.Dir, z.Env, z.Path, z.Args = a.dir, a.env, a.path, a.args
|
|
||||||
z.Grow(len(a.paths) + 4)
|
|
||||||
|
|
||||||
temp, work := f.GetTempDir(), f.GetWorkDir()
|
|
||||||
for i, b := range a.paths {
|
|
||||||
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.layers(f)...,
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if a.paths[i].W {
|
|
||||||
tempUpper, tempWork := temp.Append(
|
|
||||||
".upper", strconv.Itoa(i),
|
|
||||||
), temp.Append(
|
|
||||||
".work", strconv.Itoa(i),
|
|
||||||
)
|
|
||||||
if err = os.MkdirAll(tempUpper.String(), 0700); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err = os.MkdirAll(tempWork.String(), 0700); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
z.Overlay(b.P, tempUpper, tempWork, b.layers(f)...)
|
|
||||||
} else if len(b.A) == 1 {
|
|
||||||
pathname, _ := f.GetArtifact(b.A[0])
|
|
||||||
z.Bind(pathname, b.P, 0)
|
|
||||||
} else {
|
|
||||||
z.OverlayReadonly(b.P, b.layers(f)...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if overlayWorkIndex < 0 {
|
|
||||||
z.Bind(
|
|
||||||
work,
|
|
||||||
AbsWork,
|
|
||||||
std.BindWritable|std.BindEnsure,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
z.Bind(
|
|
||||||
f.GetTempDir(),
|
|
||||||
fhs.AbsTmp,
|
|
||||||
std.BindWritable|std.BindEnsure,
|
|
||||||
)
|
|
||||||
z.Proc(fhs.AbsProc).Dev(fhs.AbsDev, true)
|
|
||||||
|
|
||||||
if err = z.Start(); err != nil {
|
if err = z.Start(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -532,7 +562,7 @@ func (a *execArtifact) cure(f *FContext, hostNet bool) (err error) {
|
|||||||
|
|
||||||
// do not allow empty directories to succeed
|
// do not allow empty directories to succeed
|
||||||
for {
|
for {
|
||||||
err = syscall.Rmdir(work.String())
|
err = syscall.Rmdir(f.GetWorkDir().String())
|
||||||
if err != syscall.EINTR {
|
if err != syscall.EINTR {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ func TestExec(t *testing.T) {
|
|||||||
[]string{"testtool"},
|
[]string{"testtool"},
|
||||||
|
|
||||||
pkg.ExecPath{},
|
pkg.ExecPath{},
|
||||||
), nil, pkg.Checksum{}, os.ErrInvalid},
|
), nil, pkg.Checksum{}, pkg.ErrInvalidPaths},
|
||||||
})
|
})
|
||||||
|
|
||||||
// check init failure passthrough
|
// check init failure passthrough
|
||||||
|
|||||||
Reference in New Issue
Block a user