github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/pkg/hooks/exec/exec.go (about) 1 // Package exec provides utilities for executing Open Container Initiative runtime hooks. 2 package exec 3 4 import ( 5 "bytes" 6 "context" 7 "fmt" 8 "io" 9 osexec "os/exec" 10 "time" 11 12 rspec "github.com/opencontainers/runtime-spec/specs-go" 13 "github.com/pkg/errors" 14 "github.com/sirupsen/logrus" 15 ) 16 17 // DefaultPostKillTimeout is the recommended default post-kill timeout. 18 const DefaultPostKillTimeout = time.Duration(10) * time.Second 19 20 // Run executes the hook and waits for it to complete or for the 21 // context or hook-specified timeout to expire. 22 func Run(ctx context.Context, hook *rspec.Hook, state []byte, stdout io.Writer, stderr io.Writer, postKillTimeout time.Duration) (hookErr, err error) { 23 cmd := osexec.Cmd{ 24 Path: hook.Path, 25 Args: hook.Args, 26 Env: hook.Env, 27 Stdin: bytes.NewReader(state), 28 Stdout: stdout, 29 Stderr: stderr, 30 } 31 if cmd.Env == nil { 32 cmd.Env = []string{} 33 } 34 35 if hook.Timeout != nil { 36 var cancel context.CancelFunc 37 ctx, cancel = context.WithTimeout(ctx, time.Duration(*hook.Timeout)*time.Second) 38 defer cancel() 39 } 40 41 err = cmd.Start() 42 if err != nil { 43 return err, err 44 } 45 exit := make(chan error, 1) 46 go func() { 47 err := cmd.Wait() 48 if err != nil { 49 err = errors.Wrapf(err, "executing %v", cmd.Args) 50 } 51 exit <- err 52 }() 53 54 select { 55 case err = <-exit: 56 return err, err 57 case <-ctx.Done(): 58 if err := cmd.Process.Kill(); err != nil { 59 logrus.Errorf("Failed to kill pid %v", cmd.Process) 60 } 61 timer := time.NewTimer(postKillTimeout) 62 defer timer.Stop() 63 select { 64 case <-timer.C: 65 err = fmt.Errorf("failed to reap process within %s of the kill signal", postKillTimeout) 66 case err = <-exit: 67 } 68 return err, ctx.Err() 69 } 70 }