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
|
||||||
|
@ -57,18 +57,18 @@ func Template() *Config {
|
|||||||
Groups: []string{"video", "dialout", "plugdev"},
|
Groups: []string{"video", "dialout", "plugdev"},
|
||||||
|
|
||||||
Container: &ContainerConfig{
|
Container: &ContainerConfig{
|
||||||
Hostname: "localhost",
|
Hostname: "localhost",
|
||||||
Devel: true,
|
Devel: true,
|
||||||
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,
|
||||||
Tty: true,
|
Tty: true,
|
||||||
Multiarch: true,
|
Multiarch: true,
|
||||||
MapRealUID: true,
|
MapRealUID: true,
|
||||||
// example API credentials pulled from Google Chrome
|
// example API credentials pulled from Google Chrome
|
||||||
// DO NOT USE THESE IN A REAL BROWSER
|
// DO NOT USE THESE IN A REAL BROWSER
|
||||||
Env: map[string]string{
|
Env: map[string]string{
|
||||||
|
@ -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