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