github.com/wmuizelaar/kpt@v0.0.0-20221018115725-bd564717b2ed/internal/fnruntime/exec.go (about) 1 // Copyright 2021 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package fnruntime 16 17 import ( 18 "bytes" 19 "context" 20 goerrors "errors" 21 "fmt" 22 "io" 23 "os/exec" 24 "time" 25 26 "github.com/GoogleContainerTools/kpt/internal/printer" 27 fnresult "github.com/GoogleContainerTools/kpt/pkg/api/fnresult/v1" 28 ) 29 30 type ExecFn struct { 31 // Path is the os specific path to the executable 32 // file. It can be relative or absolute. 33 Path string 34 // Args are the arguments to the executable 35 Args []string 36 37 Env map[string]string 38 // Container function will be killed after this timeour. 39 // The default value is 5 minutes. 40 Timeout time.Duration 41 // FnResult is used to store the information about the result from 42 // the function. 43 FnResult *fnresult.Result 44 } 45 46 // Run runs the executable file which reads the input from r and 47 // writes the output to w. 48 func (f *ExecFn) Run(r io.Reader, w io.Writer) error { 49 // setup exec run timeout 50 timeout := defaultLongTimeout 51 if f.Timeout != 0 { 52 timeout = f.Timeout 53 } 54 ctx, cancel := context.WithTimeout(context.Background(), timeout) 55 defer cancel() 56 57 cmd := exec.CommandContext(ctx, f.Path, f.Args...) 58 59 errSink := bytes.Buffer{} 60 cmd.Stdin = r 61 cmd.Stdout = w 62 cmd.Stderr = &errSink 63 64 for k, v := range f.Env { 65 cmd.Env = append(cmd.Env, fmt.Sprintf("%v=%v", k, v)) 66 } 67 68 if err := cmd.Run(); err != nil { 69 var exitErr *exec.ExitError 70 if goerrors.As(err, &exitErr) { 71 return &ExecError{ 72 OriginalErr: exitErr, 73 ExitCode: exitErr.ExitCode(), 74 Stderr: errSink.String(), 75 TruncateOutput: printer.TruncateOutput, 76 } 77 } 78 return fmt.Errorf("unexpected function error: %w", err) 79 } 80 81 if errSink.Len() > 0 { 82 f.FnResult.Stderr = errSink.String() 83 } 84 85 return nil 86 }