internal/outcome/process: relocate start and serve
All checks were successful
Test / Create distribution (push) Successful in 34s
Test / Sandbox (push) Successful in 2m14s
Test / Hakurei (push) Successful in 3m11s
Test / Hpkg (push) Successful in 4m2s
Test / Sandbox (race detector) (push) Successful in 4m5s
Test / Flake checks (push) Successful in 1m30s
Test / Hakurei (race detector) (push) Successful in 4m57s
All checks were successful
Test / Create distribution (push) Successful in 34s
Test / Sandbox (push) Successful in 2m14s
Test / Hakurei (push) Successful in 3m11s
Test / Hpkg (push) Successful in 4m2s
Test / Sandbox (race detector) (push) Successful in 4m5s
Test / Flake checks (push) Successful in 1m30s
Test / Hakurei (race detector) (push) Successful in 4m57s
This is useful for reordering these operations for further cleanup. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
651cdf9ccb
commit
d3d3417125
@ -12,6 +12,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hakurei.app/container"
|
"hakurei.app/container"
|
||||||
|
"hakurei.app/container/check"
|
||||||
"hakurei.app/container/fhs"
|
"hakurei.app/container/fhs"
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
"hakurei.app/internal"
|
"hakurei.app/internal"
|
||||||
@ -32,16 +33,12 @@ type mainState struct {
|
|||||||
// done is whether beforeExit has been called already.
|
// done is whether beforeExit has been called already.
|
||||||
done bool
|
done bool
|
||||||
|
|
||||||
// Time is the exact point in time where the process was created.
|
// Populated on successful hsu startup.
|
||||||
// Location must be set to UTC.
|
cmd *exec.Cmd
|
||||||
//
|
// Cancels cmd, must be populated before cmd is populated.
|
||||||
// Time is nil if no process was ever created.
|
cancel context.CancelFunc
|
||||||
Time *time.Time
|
|
||||||
|
|
||||||
store store.Compat
|
store store.Compat
|
||||||
cancel context.CancelFunc
|
|
||||||
cmd *exec.Cmd
|
|
||||||
cmdWait chan error
|
|
||||||
|
|
||||||
k *outcome
|
k *outcome
|
||||||
message.Msg
|
message.Msg
|
||||||
@ -81,14 +78,9 @@ func (ms mainState) beforeExit(isFault bool) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// this also handles wait for a non-fault termination
|
// this also handles wait for a non-fault termination
|
||||||
if ms.cmd != nil && ms.cmdWait != nil {
|
if ms.cmd != nil {
|
||||||
waitDone := make(chan struct{})
|
|
||||||
|
|
||||||
// this ties waitDone to ctx with the additional compensated timeout duration
|
|
||||||
go func() { <-ms.k.ctx.Done(); time.Sleep(ms.k.state.Shim.WaitDelay + shimWaitTimeout); close(waitDone) }()
|
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case err := <-ms.cmdWait:
|
case err := <-func() chan error { w := make(chan error, 1); go func() { w <- ms.cmd.Wait(); ms.cancel() }(); return w }():
|
||||||
wstatus, ok := ms.cmd.ProcessState.Sys().(syscall.WaitStatus)
|
wstatus, ok := ms.cmd.ProcessState.Sys().(syscall.WaitStatus)
|
||||||
if ok {
|
if ok {
|
||||||
if v := wstatus.ExitStatus(); v != 0 {
|
if v := wstatus.ExitStatus(); v != 0 {
|
||||||
@ -119,7 +111,12 @@ func (ms mainState) beforeExit(isFault bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case <-waitDone:
|
case <-func() chan struct{} {
|
||||||
|
w := make(chan struct{})
|
||||||
|
// this ties waitDone to ctx with the additional compensated timeout duration
|
||||||
|
go func() { <-ms.k.ctx.Done(); time.Sleep(ms.k.state.Shim.WaitDelay + shimWaitTimeout); close(w) }()
|
||||||
|
return w
|
||||||
|
}():
|
||||||
ms.Resume()
|
ms.Resume()
|
||||||
// this is only reachable when shim did not exit within shimWaitTimeout, after its WaitDelay has elapsed.
|
// this is only reachable when shim did not exit within shimWaitTimeout, after its WaitDelay has elapsed.
|
||||||
// This is different from the container failing to terminate within its timeout period, as that is enforced
|
// This is different from the container failing to terminate within its timeout period, as that is enforced
|
||||||
@ -226,52 +223,23 @@ func (k *outcome) main(msg message.Msg) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
ms.cancel = cancel
|
ms.cancel = cancel
|
||||||
|
|
||||||
ms.cmd = exec.CommandContext(ctx, hsuPath.String())
|
// shim starts and blocks on setup payload before container is started
|
||||||
ms.cmd.Stdin, ms.cmd.Stdout, ms.cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
var (
|
||||||
ms.cmd.Dir = fhs.Root // container init enters final working directory
|
startTime time.Time
|
||||||
// shim runs in the same session as monitor; see shim.go for behaviour
|
shimPipe *os.File
|
||||||
ms.cmd.Cancel = func() error { return ms.cmd.Process.Signal(syscall.SIGCONT) }
|
)
|
||||||
|
if cmd, f, err := k.start(ctx, msg, hsuPath, &startTime); err != nil {
|
||||||
var shimPipe *os.File
|
ms.fatal("cannot start shim:", err)
|
||||||
if fd, w, err := container.Setup(&ms.cmd.ExtraFiles); err != nil {
|
|
||||||
ms.fatal("cannot create shim setup pipe:", err)
|
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
} else {
|
} else {
|
||||||
shimPipe = w
|
ms.cmd, shimPipe = cmd, f
|
||||||
ms.cmd.Env = []string{
|
|
||||||
// passed through to shim by hsu
|
|
||||||
shimEnv + "=" + strconv.Itoa(fd),
|
|
||||||
// interpreted by hsu
|
|
||||||
"HAKUREI_IDENTITY=" + k.state.identity.String(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(k.supp) > 0 {
|
// this starts the container, system setup must complete before this point
|
||||||
msg.Verbosef("attaching supplementary group ids %s", k.supp)
|
if err := serveShim(msg, shimPipe, k.state); err != nil {
|
||||||
// interpreted by hsu
|
ms.fatal("cannot serve shim payload:", err)
|
||||||
ms.cmd.Env = append(ms.cmd.Env, "HAKUREI_GROUPS="+strings.Join(k.supp, " "))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.Verbosef("setuid helper at %s", hsuPath)
|
|
||||||
msg.Suspend()
|
|
||||||
if err := ms.cmd.Start(); err != nil {
|
|
||||||
ms.fatal("cannot start setuid wrapper:", err)
|
|
||||||
}
|
|
||||||
startTime := time.Now().UTC()
|
|
||||||
ms.cmdWait = make(chan error, 1)
|
|
||||||
// this ties context back to the life of the process
|
|
||||||
go func() { ms.cmdWait <- ms.cmd.Wait(); cancel() }()
|
|
||||||
ms.Time = &startTime
|
|
||||||
|
|
||||||
if err := shimPipe.SetDeadline(time.Now().Add(shimSetupTimeout)); err != nil {
|
|
||||||
msg.Verbose(err.Error())
|
|
||||||
}
|
|
||||||
if err := gob.NewEncoder(shimPipe).Encode(k.state); err != nil {
|
|
||||||
msg.Resume()
|
|
||||||
ms.fatal("cannot transmit shim config:", err)
|
|
||||||
}
|
|
||||||
_ = shimPipe.Close()
|
|
||||||
|
|
||||||
// shim accepted setup payload, create process state
|
// shim accepted setup payload, create process state
|
||||||
if ok, err := ms.store.Do(k.state.identity.unwrap(), func(c store.Cursor) {
|
if ok, err := ms.store.Do(k.state.identity.unwrap(), func(c store.Cursor) {
|
||||||
if err := c.Save(&hst.State{
|
if err := c.Save(&hst.State{
|
||||||
@ -279,7 +247,7 @@ func (k *outcome) main(msg message.Msg) {
|
|||||||
PID: os.Getpid(),
|
PID: os.Getpid(),
|
||||||
ShimPID: ms.cmd.Process.Pid,
|
ShimPID: ms.cmd.Process.Pid,
|
||||||
Config: k.config,
|
Config: k.config,
|
||||||
Time: *ms.Time,
|
Time: startTime,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
ms.fatal("cannot save state entry:", err)
|
ms.fatal("cannot save state entry:", err)
|
||||||
}
|
}
|
||||||
@ -299,6 +267,63 @@ func (k *outcome) main(msg message.Msg) {
|
|||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// start starts the shim via cmd/hsu.
|
||||||
|
//
|
||||||
|
// If successful, a [time.Time] value for [hst.State] is stored in the value pointed to by startTime.
|
||||||
|
// The resulting [exec.Cmd] and write end of the shim setup pipe is returned.
|
||||||
|
func (k *outcome) start(ctx context.Context, msg message.Msg,
|
||||||
|
hsuPath *check.Absolute,
|
||||||
|
startTime *time.Time,
|
||||||
|
) (*exec.Cmd, *os.File, error) {
|
||||||
|
cmd := exec.CommandContext(ctx, hsuPath.String())
|
||||||
|
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||||
|
cmd.Dir = fhs.Root // container init enters final working directory
|
||||||
|
// shim runs in the same session as monitor; see shim.go for behaviour
|
||||||
|
cmd.Cancel = func() error { return cmd.Process.Signal(syscall.SIGCONT) }
|
||||||
|
|
||||||
|
var shimPipe *os.File
|
||||||
|
if fd, w, err := container.Setup(&cmd.ExtraFiles); err != nil {
|
||||||
|
return cmd, nil, &hst.AppError{Step: "create shim setup pipe", Err: err}
|
||||||
|
} else {
|
||||||
|
shimPipe = w
|
||||||
|
cmd.Env = []string{
|
||||||
|
// passed through to shim by hsu
|
||||||
|
shimEnv + "=" + strconv.Itoa(fd),
|
||||||
|
// interpreted by hsu
|
||||||
|
"HAKUREI_IDENTITY=" + k.state.identity.String(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(k.supp) > 0 {
|
||||||
|
msg.Verbosef("attaching supplementary group ids %s", k.supp)
|
||||||
|
// interpreted by hsu
|
||||||
|
cmd.Env = append(cmd.Env, "HAKUREI_GROUPS="+strings.Join(k.supp, " "))
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Verbosef("setuid helper at %s", hsuPath)
|
||||||
|
msg.Suspend()
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
msg.Resume()
|
||||||
|
return cmd, shimPipe, &hst.AppError{Step: "start setuid wrapper", Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
*startTime = time.Now().UTC()
|
||||||
|
return cmd, shimPipe, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// serveShim serves outcomeState through the shim setup pipe.
|
||||||
|
func serveShim(msg message.Msg, shimPipe *os.File, state *outcomeState) error {
|
||||||
|
if err := shimPipe.SetDeadline(time.Now().Add(shimSetupTimeout)); err != nil {
|
||||||
|
msg.Verbose(err.Error())
|
||||||
|
}
|
||||||
|
if err := gob.NewEncoder(shimPipe).Encode(state); err != nil {
|
||||||
|
msg.Resume()
|
||||||
|
return &hst.AppError{Step: "transmit shim config", Err: err}
|
||||||
|
}
|
||||||
|
_ = shimPipe.Close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// printMessageError prints the error message according to [message.GetMessage],
|
// printMessageError prints the error message according to [message.GetMessage],
|
||||||
// or fallback prepended to err if an error message is not available.
|
// or fallback prepended to err if an error message is not available.
|
||||||
func printMessageError(println func(v ...any), fallback string, err error) {
|
func printMessageError(println func(v ...any), fallback string, err error) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user