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": { |     "container": { | ||||||
|       "hostname": "localhost", |       "hostname": "localhost", | ||||||
|       "immediate_termination": true, |       "wait_delay": -1, | ||||||
|       "seccomp_flags": 1, |       "seccomp_flags": 1, | ||||||
|       "seccomp_presets": 1, |       "seccomp_presets": 1, | ||||||
|       "seccomp_compat": true, |       "seccomp_compat": true, | ||||||
| @ -384,7 +384,7 @@ App | |||||||
|   ], |   ], | ||||||
|   "container": { |   "container": { | ||||||
|     "hostname": "localhost", |     "hostname": "localhost", | ||||||
|     "immediate_termination": true, |     "wait_delay": -1, | ||||||
|     "seccomp_flags": 1, |     "seccomp_flags": 1, | ||||||
|     "seccomp_presets": 1, |     "seccomp_presets": 1, | ||||||
|     "seccomp_compat": true, |     "seccomp_compat": true, | ||||||
| @ -566,7 +566,7 @@ func Test_printPs(t *testing.T) { | |||||||
|       ], |       ], | ||||||
|       "container": { |       "container": { | ||||||
|         "hostname": "localhost", |         "hostname": "localhost", | ||||||
|         "immediate_termination": true, |         "wait_delay": -1, | ||||||
|         "seccomp_flags": 1, |         "seccomp_flags": 1, | ||||||
|         "seccomp_presets": 1, |         "seccomp_presets": 1, | ||||||
|         "seccomp_compat": true, |         "seccomp_compat": true, | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| package hst | package hst | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"time" | ||||||
|  | 
 | ||||||
| 	"hakurei.app/container/seccomp" | 	"hakurei.app/container/seccomp" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @ -10,8 +12,10 @@ type ( | |||||||
| 		// container hostname | 		// container hostname | ||||||
| 		Hostname string `json:"hostname,omitempty"` | 		Hostname string `json:"hostname,omitempty"` | ||||||
| 
 | 
 | ||||||
| 		// do not interrupt and wait for initial process during termination | 		// duration to wait for after interrupting a container's initial process in nanoseconds; | ||||||
| 		ImmediateTermination bool `json:"immediate_termination,omitempty"` | 		// a negative value causes the container to be terminated immediately on cancellation | ||||||
|  | 		WaitDelay time.Duration `json:"wait_delay,omitempty"` | ||||||
|  | 
 | ||||||
| 		// extra seccomp flags | 		// extra seccomp flags | ||||||
| 		SeccompFlags seccomp.ExportFlag `json:"seccomp_flags"` | 		SeccompFlags seccomp.ExportFlag `json:"seccomp_flags"` | ||||||
| 		// extra seccomp presets | 		// extra seccomp presets | ||||||
|  | |||||||
| @ -62,7 +62,7 @@ func Template() *Config { | |||||||
| 			Userns:         true, | 			Userns:         true, | ||||||
| 			Net:            true, | 			Net:            true, | ||||||
| 			Device:         true, | 			Device:         true, | ||||||
| 			ImmediateTermination: true, | 			WaitDelay:      -1, | ||||||
| 			SeccompFlags:   seccomp.AllowMultiarch, | 			SeccompFlags:   seccomp.AllowMultiarch, | ||||||
| 			SeccompPresets: seccomp.PresetExt, | 			SeccompPresets: seccomp.PresetExt, | ||||||
| 			SeccompCompat:  true, | 			SeccompCompat:  true, | ||||||
|  | |||||||
| @ -80,7 +80,7 @@ func TestTemplate(t *testing.T) { | |||||||
| 	], | 	], | ||||||
| 	"container": { | 	"container": { | ||||||
| 		"hostname": "localhost", | 		"hostname": "localhost", | ||||||
| 		"immediate_termination": true, | 		"wait_delay": -1, | ||||||
| 		"seccomp_flags": 1, | 		"seccomp_flags": 1, | ||||||
| 		"seccomp_presets": 1, | 		"seccomp_presets": 1, | ||||||
| 		"seccomp_compat": true, | 		"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; | 		// the container is canceled when shim is requested to exit or receives an interrupt or termination signal; | ||||||
| 		// this behaviour is implemented in the shim | 		// 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 | 	// this prevents blocking forever on an early failure | ||||||
| 	waitErr, setupErr := make(chan error, 1), make(chan error, 1) | 	waitErr, setupErr := make(chan error, 1), make(chan error, 1) | ||||||
| 	go func() { waitErr <- cmd.Wait(); cancel() }() | 	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 { | 	select { | ||||||
| 	case err := <-setupErr: | 	case err := <-setupErr: | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ import ( | |||||||
| 	"strings" | 	"strings" | ||||||
| 	"sync/atomic" | 	"sync/atomic" | ||||||
| 	"syscall" | 	"syscall" | ||||||
|  | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"hakurei.app/container" | 	"hakurei.app/container" | ||||||
| 	"hakurei.app/hst" | 	"hakurei.app/hst" | ||||||
| @ -79,6 +80,7 @@ type outcome struct { | |||||||
| 	sys  *system.I | 	sys  *system.I | ||||||
| 	ctx  context.Context | 	ctx  context.Context | ||||||
| 
 | 
 | ||||||
|  | 	waitDelay time.Duration | ||||||
| 	container *container.Params | 	container *container.Params | ||||||
| 	env       map[string]string | 	env       map[string]string | ||||||
| 	sync      *os.File | 	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 uid, gid int | ||||||
| 		var err error | 		var err error | ||||||
| 		seal.container, seal.env, err = newContainer(config.Container, sys, &uid, &gid) | 		seal.container, seal.env, err = newContainer(config.Container, sys, &uid, &gid) | ||||||
|  | 		seal.waitDelay = config.Container.WaitDelay | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return hlog.WrapErrSuffix(err, | 			return hlog.WrapErrSuffix(err, | ||||||
| 				"cannot initialise container configuration:") | 				"cannot initialise container configuration:") | ||||||
|  | |||||||
| @ -28,6 +28,10 @@ type shimParams struct { | |||||||
| 	// monitor pid, checked against ppid in signal handler | 	// monitor pid, checked against ppid in signal handler | ||||||
| 	Monitor int | 	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 | 	// finalised container params | ||||||
| 	Container *container.Params | 	Container *container.Params | ||||||
| 	// path to outer home directory | 	// path to outer home directory | ||||||
| @ -43,9 +47,8 @@ const ( | |||||||
| 	// ShimExitOrphan is returned when the shim is orphaned before monitor delivers a signal. | 	// ShimExitOrphan is returned when the shim is orphaned before monitor delivers a signal. | ||||||
| 	ShimExitOrphan = 3 | 	ShimExitOrphan = 3 | ||||||
| 
 | 
 | ||||||
| 	// ShimWaitDelay is the duration to wait after interrupting a container's initial process | 	DefaultShimWaitDelay = 5 * time.Second | ||||||
| 	// before the container is fully killed off. | 	MaxShimWaitDelay     = 30 * time.Second | ||||||
| 	ShimWaitDelay = 5 * time.Second |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // ShimMain is the main function of the shim process and runs as the unconstrained target user. | // 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 := container.New(ctx, name) | ||||||
| 	z.Params = *params.Container | 	z.Params = *params.Container | ||||||
| 	z.Stdin, z.Stdout, z.Stderr = os.Stdin, os.Stdout, os.Stderr | 	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 { | 	if err := z.Start(); err != nil { | ||||||
| 		hlog.PrintBaseError(err, "cannot start container:") | 		hlog.PrintBaseError(err, "cannot start container:") | ||||||
|  | |||||||
| @ -128,7 +128,7 @@ in | |||||||
| 
 | 
 | ||||||
|                     container = { |                     container = { | ||||||
|                       inherit (app) |                       inherit (app) | ||||||
|                         immediate_termination |                         wait_delay | ||||||
|                         devel |                         devel | ||||||
|                         userns |                         userns | ||||||
|                         net |                         net | ||||||
|  | |||||||
							
								
								
									
										12
									
								
								options.nix
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								options.nix
									
									
									
									
									
								
							| @ -76,6 +76,7 @@ in | |||||||
|         type = |         type = | ||||||
|           let |           let | ||||||
|             inherit (types) |             inherit (types) | ||||||
|  |               int | ||||||
|               ints |               ints | ||||||
|               str |               str | ||||||
|               bool |               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"; |               devel = mkEnableOption "debugging-related kernel interfaces"; | ||||||
|               userns = mkEnableOption "user namespace creation"; |               userns = mkEnableOption "user namespace creation"; | ||||||
|               tty = mkEnableOption "access to the controlling terminal"; |               tty = mkEnableOption "access to the controlling terminal"; | ||||||
|  | |||||||
| @ -132,7 +132,7 @@ | |||||||
|         identity = 1; |         identity = 1; | ||||||
|         shareUid = true; |         shareUid = true; | ||||||
|         verbose = true; |         verbose = true; | ||||||
|         immediate_termination = true; |         wait_delay = -1; | ||||||
|         share = pkgs.foot; |         share = pkgs.foot; | ||||||
|         packages = [ ]; |         packages = [ ]; | ||||||
|         command = "foot"; |         command = "foot"; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user