github.com/apptainer/singularity@v3.1.1+incompatible/internal/pkg/util/exec/hook.go (about) 1 // Copyright (c) 2018, Sylabs Inc. All rights reserved. 2 // This software is licensed under a 3-clause BSD license. Please consult the 3 // LICENSE.md file distributed with the sources of this project regarding your 4 // rights to use or distribute this software. 5 6 package exec 7 8 import ( 9 "bytes" 10 "context" 11 "encoding/json" 12 "fmt" 13 "os/exec" 14 "time" 15 16 "github.com/opencontainers/runtime-spec/specs-go" 17 ) 18 19 // Hook execute an OCI hook command and pass state over stdin. 20 func Hook(hook *specs.Hook, state *specs.State) error { 21 var ctx context.Context 22 var cancel context.CancelFunc 23 var timeout time.Duration 24 var cmd *exec.Cmd 25 26 if hook.Timeout != nil { 27 timeout = time.Duration(*hook.Timeout) * 1000 * time.Millisecond 28 } 29 30 if timeout != 0 { 31 ctx, cancel = context.WithTimeout(context.Background(), timeout) 32 defer cancel() 33 } 34 35 if ctx != nil { 36 cmd = exec.CommandContext(ctx, hook.Path) 37 } else { 38 cmd = exec.Command(hook.Path) 39 } 40 41 data, err := json.Marshal(state) 42 if err != nil { 43 return fmt.Errorf("failed to marshal state data: %s", err) 44 } 45 46 cmd.Stdin = bytes.NewReader(data) 47 cmd.Env = hook.Env 48 cmd.Args = hook.Args 49 50 err = cmd.Start() 51 if err != nil { 52 return fmt.Errorf("failed to execute hook %s: %s", hook.Path, err) 53 } 54 55 err = cmd.Wait() 56 if err != nil { 57 return fmt.Errorf("hook execution failed: %s", err) 58 } 59 60 if ctx != nil && ctx.Err() == context.DeadlineExceeded { 61 return fmt.Errorf("hook time out") 62 } 63 64 return err 65 }