hst: configurable wait delay
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				Test / Create distribution (push) Successful in 32s
				
			
		
			
				
	
				Test / Sandbox (push) Successful in 1m58s
				
			
		
			
				
	
				Test / Hakurei (push) Successful in 2m47s
				
			
		
			
				
	
				Test / Sandbox (race detector) (push) Successful in 3m56s
				
			
		
			
				
	
				Test / Planterette (push) Successful in 3m58s
				
			
		
			
				
	
				Test / Hakurei (race detector) (push) Successful in 4m31s
				
			
		
			
				
	
				Test / Flake checks (push) Successful in 1m17s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	Test / Create distribution (push) Successful in 32s
				
			Test / Sandbox (push) Successful in 1m58s
				
			Test / Hakurei (push) Successful in 2m47s
				
			Test / Sandbox (race detector) (push) Successful in 3m56s
				
			Test / Planterette (push) Successful in 3m58s
				
			Test / Hakurei (race detector) (push) Successful in 4m31s
				
			Test / Flake checks (push) Successful in 1m17s
				
			This is useful for programs that take a long time to clean up. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
		
							parent
							
								
									940ee00ffe
								
							
						
					
					
						commit
						f7bd28118c
					
				| @ -256,7 +256,7 @@ App | ||||
|     ], | ||||
|     "container": { | ||||
|       "hostname": "localhost", | ||||
|       "immediate_termination": true, | ||||
|       "wait_delay": -1, | ||||
|       "seccomp_flags": 1, | ||||
|       "seccomp_presets": 1, | ||||
|       "seccomp_compat": true, | ||||
| @ -384,7 +384,7 @@ App | ||||
|   ], | ||||
|   "container": { | ||||
|     "hostname": "localhost", | ||||
|     "immediate_termination": true, | ||||
|     "wait_delay": -1, | ||||
|     "seccomp_flags": 1, | ||||
|     "seccomp_presets": 1, | ||||
|     "seccomp_compat": true, | ||||
| @ -566,7 +566,7 @@ func Test_printPs(t *testing.T) { | ||||
|       ], | ||||
|       "container": { | ||||
|         "hostname": "localhost", | ||||
|         "immediate_termination": true, | ||||
|         "wait_delay": -1, | ||||
|         "seccomp_flags": 1, | ||||
|         "seccomp_presets": 1, | ||||
|         "seccomp_compat": true, | ||||
|  | ||||
| @ -1,6 +1,8 @@ | ||||
| package hst | ||||
| 
 | ||||
| import ( | ||||
| 	"time" | ||||
| 
 | ||||
| 	"hakurei.app/container/seccomp" | ||||
| ) | ||||
| 
 | ||||
| @ -10,8 +12,10 @@ type ( | ||||
| 		// container hostname | ||||
| 		Hostname string `json:"hostname,omitempty"` | ||||
| 
 | ||||
| 		// do not interrupt and wait for initial process during termination | ||||
| 		ImmediateTermination bool `json:"immediate_termination,omitempty"` | ||||
| 		// duration to wait for after interrupting a container's initial process in nanoseconds; | ||||
| 		// a negative value causes the container to be terminated immediately on cancellation | ||||
| 		WaitDelay time.Duration `json:"wait_delay,omitempty"` | ||||
| 
 | ||||
| 		// extra seccomp flags | ||||
| 		SeccompFlags seccomp.ExportFlag `json:"seccomp_flags"` | ||||
| 		// extra seccomp presets | ||||
|  | ||||
| @ -57,18 +57,18 @@ func Template() *Config { | ||||
| 		Groups:   []string{"video", "dialout", "plugdev"}, | ||||
| 
 | ||||
| 		Container: &ContainerConfig{ | ||||
| 			Hostname:             "localhost", | ||||
| 			Devel:                true, | ||||
| 			Userns:               true, | ||||
| 			Net:                  true, | ||||
| 			Device:               true, | ||||
| 			ImmediateTermination: true, | ||||
| 			SeccompFlags:         seccomp.AllowMultiarch, | ||||
| 			SeccompPresets:       seccomp.PresetExt, | ||||
| 			SeccompCompat:        true, | ||||
| 			Tty:                  true, | ||||
| 			Multiarch:            true, | ||||
| 			MapRealUID:           true, | ||||
| 			Hostname:       "localhost", | ||||
| 			Devel:          true, | ||||
| 			Userns:         true, | ||||
| 			Net:            true, | ||||
| 			Device:         true, | ||||
| 			WaitDelay:      -1, | ||||
| 			SeccompFlags:   seccomp.AllowMultiarch, | ||||
| 			SeccompPresets: seccomp.PresetExt, | ||||
| 			SeccompCompat:  true, | ||||
| 			Tty:            true, | ||||
| 			Multiarch:      true, | ||||
| 			MapRealUID:     true, | ||||
| 			// example API credentials pulled from Google Chrome | ||||
| 			// DO NOT USE THESE IN A REAL BROWSER | ||||
| 			Env: map[string]string{ | ||||
|  | ||||
| @ -80,7 +80,7 @@ func TestTemplate(t *testing.T) { | ||||
| 	], | ||||
| 	"container": { | ||||
| 		"hostname": "localhost", | ||||
| 		"immediate_termination": true, | ||||
| 		"wait_delay": -1, | ||||
| 		"seccomp_flags": 1, | ||||
| 		"seccomp_presets": 1, | ||||
| 		"seccomp_compat": true, | ||||
|  | ||||
| @ -35,7 +35,7 @@ func newContainer(s *hst.ContainerConfig, os sys.State, uid, gid *int) (*contain | ||||
| 
 | ||||
| 		// the container is canceled when shim is requested to exit or receives an interrupt or termination signal; | ||||
| 		// this behaviour is implemented in the shim | ||||
| 		ForwardCancel: !s.ImmediateTermination, | ||||
| 		ForwardCancel: s.WaitDelay >= 0, | ||||
| 	} | ||||
| 
 | ||||
| 	{ | ||||
|  | ||||
| @ -123,7 +123,15 @@ func (seal *outcome) Run(rs *RunState) error { | ||||
| 	// this prevents blocking forever on an early failure | ||||
| 	waitErr, setupErr := make(chan error, 1), make(chan error, 1) | ||||
| 	go func() { waitErr <- cmd.Wait(); cancel() }() | ||||
| 	go func() { setupErr <- e.Encode(&shimParams{os.Getpid(), seal.container, seal.user.data, hlog.Load()}) }() | ||||
| 	go func() { | ||||
| 		setupErr <- e.Encode(&shimParams{ | ||||
| 			os.Getpid(), | ||||
| 			seal.waitDelay, | ||||
| 			seal.container, | ||||
| 			seal.user.data, | ||||
| 			hlog.Load(), | ||||
| 		}) | ||||
| 	}() | ||||
| 
 | ||||
| 	select { | ||||
| 	case err := <-setupErr: | ||||
|  | ||||
| @ -15,6 +15,7 @@ import ( | ||||
| 	"strings" | ||||
| 	"sync/atomic" | ||||
| 	"syscall" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"hakurei.app/container" | ||||
| 	"hakurei.app/hst" | ||||
| @ -79,6 +80,7 @@ type outcome struct { | ||||
| 	sys  *system.I | ||||
| 	ctx  context.Context | ||||
| 
 | ||||
| 	waitDelay time.Duration | ||||
| 	container *container.Params | ||||
| 	env       map[string]string | ||||
| 	sync      *os.File | ||||
| @ -281,6 +283,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co | ||||
| 		var uid, gid int | ||||
| 		var err error | ||||
| 		seal.container, seal.env, err = newContainer(config.Container, sys, &uid, &gid) | ||||
| 		seal.waitDelay = config.Container.WaitDelay | ||||
| 		if err != nil { | ||||
| 			return hlog.WrapErrSuffix(err, | ||||
| 				"cannot initialise container configuration:") | ||||
|  | ||||
| @ -28,6 +28,10 @@ type shimParams struct { | ||||
| 	// monitor pid, checked against ppid in signal handler | ||||
| 	Monitor int | ||||
| 
 | ||||
| 	// duration to wait for after interrupting a container's initial process before the container is killed; | ||||
| 	// zero value defaults to [DefaultShimWaitDelay], values exceeding [MaxShimWaitDelay] becomes [MaxShimWaitDelay] | ||||
| 	WaitDelay time.Duration | ||||
| 
 | ||||
| 	// finalised container params | ||||
| 	Container *container.Params | ||||
| 	// path to outer home directory | ||||
| @ -43,9 +47,8 @@ const ( | ||||
| 	// ShimExitOrphan is returned when the shim is orphaned before monitor delivers a signal. | ||||
| 	ShimExitOrphan = 3 | ||||
| 
 | ||||
| 	// ShimWaitDelay is the duration to wait after interrupting a container's initial process | ||||
| 	// before the container is fully killed off. | ||||
| 	ShimWaitDelay = 5 * time.Second | ||||
| 	DefaultShimWaitDelay = 5 * time.Second | ||||
| 	MaxShimWaitDelay     = 30 * time.Second | ||||
| ) | ||||
| 
 | ||||
| // ShimMain is the main function of the shim process and runs as the unconstrained target user. | ||||
| @ -163,7 +166,14 @@ func ShimMain() { | ||||
| 	z := container.New(ctx, name) | ||||
| 	z.Params = *params.Container | ||||
| 	z.Stdin, z.Stdout, z.Stderr = os.Stdin, os.Stdout, os.Stderr | ||||
| 	z.WaitDelay = ShimWaitDelay | ||||
| 
 | ||||
| 	z.WaitDelay = params.WaitDelay | ||||
| 	if z.WaitDelay == 0 { | ||||
| 		z.WaitDelay = DefaultShimWaitDelay | ||||
| 	} | ||||
| 	if z.WaitDelay > MaxShimWaitDelay { | ||||
| 		z.WaitDelay = MaxShimWaitDelay | ||||
| 	} | ||||
| 
 | ||||
| 	if err := z.Start(); err != nil { | ||||
| 		hlog.PrintBaseError(err, "cannot start container:") | ||||
|  | ||||
| @ -128,7 +128,7 @@ in | ||||
| 
 | ||||
|                     container = { | ||||
|                       inherit (app) | ||||
|                         immediate_termination | ||||
|                         wait_delay | ||||
|                         devel | ||||
|                         userns | ||||
|                         net | ||||
|  | ||||
							
								
								
									
										12
									
								
								options.nix
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								options.nix
									
									
									
									
									
								
							| @ -76,6 +76,7 @@ in | ||||
|         type = | ||||
|           let | ||||
|             inherit (types) | ||||
|               int | ||||
|               ints | ||||
|               str | ||||
|               bool | ||||
| @ -195,7 +196,16 @@ in | ||||
|                 ''; | ||||
|               }; | ||||
| 
 | ||||
|               immediate_termination = mkEnableOption "immediate termination of the container on interrupt"; | ||||
|               wait_delay = mkOption { | ||||
|                 type = nullOr int; | ||||
|                 default = null; | ||||
|                 description = '' | ||||
|                   Duration to wait for after interrupting a container's initial process in nanoseconds. | ||||
|                   A negative value causes the container to be terminated immediately on cancellation. | ||||
|                   Setting this to null defaults to five seconds. | ||||
|                 ''; | ||||
|               }; | ||||
| 
 | ||||
|               devel = mkEnableOption "debugging-related kernel interfaces"; | ||||
|               userns = mkEnableOption "user namespace creation"; | ||||
|               tty = mkEnableOption "access to the controlling terminal"; | ||||
|  | ||||
| @ -132,7 +132,7 @@ | ||||
|         identity = 1; | ||||
|         shareUid = true; | ||||
|         verbose = true; | ||||
|         immediate_termination = true; | ||||
|         wait_delay = -1; | ||||
|         share = pkgs.foot; | ||||
|         packages = [ ]; | ||||
|         command = "foot"; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user