...

Source file src/helm.sh/helm/v3/pkg/postrender/exec.go

Documentation: helm.sh/helm/v3/pkg/postrender

     1  /*
     2  Copyright The Helm Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package postrender
    18  
    19  import (
    20  	"bytes"
    21  	"io"
    22  	"os/exec"
    23  	"path/filepath"
    24  
    25  	"github.com/pkg/errors"
    26  )
    27  
    28  type execRender struct {
    29  	binaryPath string
    30  	args       []string
    31  }
    32  
    33  // NewExec returns a PostRenderer implementation that calls the provided binary.
    34  // It returns an error if the binary cannot be found. If the path does not
    35  // contain any separators, it will search in $PATH, otherwise it will resolve
    36  // any relative paths to a fully qualified path
    37  func NewExec(binaryPath string, args ...string) (PostRenderer, error) {
    38  	fullPath, err := getFullPath(binaryPath)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  	return &execRender{fullPath, args}, nil
    43  }
    44  
    45  // Run the configured binary for the post render
    46  func (p *execRender) Run(renderedManifests *bytes.Buffer) (*bytes.Buffer, error) {
    47  	cmd := exec.Command(p.binaryPath, p.args...)
    48  	stdin, err := cmd.StdinPipe()
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  
    53  	var postRendered = &bytes.Buffer{}
    54  	var stderr = &bytes.Buffer{}
    55  	cmd.Stdout = postRendered
    56  	cmd.Stderr = stderr
    57  
    58  	go func() {
    59  		defer stdin.Close()
    60  		io.Copy(stdin, renderedManifests)
    61  	}()
    62  	err = cmd.Run()
    63  	if err != nil {
    64  		return nil, errors.Wrapf(err, "error while running command %s. error output:\n%s", p.binaryPath, stderr.String())
    65  	}
    66  
    67  	return postRendered, nil
    68  }
    69  
    70  // getFullPath returns the full filepath to the binary to execute. If the path
    71  // does not contain any separators, it will search in $PATH, otherwise it will
    72  // resolve any relative paths to a fully qualified path
    73  func getFullPath(binaryPath string) (string, error) {
    74  	// NOTE(thomastaylor312): I am leaving this code commented out here. During
    75  	// the implementation of post-render, it was brought up that if we are
    76  	// relying on plugins, we should actually use the plugin system so it can
    77  	// properly handle multiple OSs. This will be a feature add in the future,
    78  	// so I left this code for reference. It can be deleted or reused once the
    79  	// feature is implemented
    80  
    81  	// Manually check the plugin dir first
    82  	// if !strings.Contains(binaryPath, string(filepath.Separator)) {
    83  	// 	// First check the plugin dir
    84  	// 	pluginDir := helmpath.DataPath("plugins") // Default location
    85  	// 	// If location for plugins is explicitly set, check there
    86  	// 	if v, ok := os.LookupEnv("HELM_PLUGINS"); ok {
    87  	// 		pluginDir = v
    88  	// 	}
    89  	// 	// The plugins variable can actually contain multiple paths, so loop through those
    90  	// 	for _, p := range filepath.SplitList(pluginDir) {
    91  	// 		_, err := os.Stat(filepath.Join(p, binaryPath))
    92  	// 		if err != nil && !os.IsNotExist(err) {
    93  	// 			return "", err
    94  	// 		} else if err == nil {
    95  	// 			binaryPath = filepath.Join(p, binaryPath)
    96  	// 			break
    97  	// 		}
    98  	// 	}
    99  	// }
   100  
   101  	// Now check for the binary using the given path or check if it exists in
   102  	// the path and is executable
   103  	checkedPath, err := exec.LookPath(binaryPath)
   104  	if err != nil {
   105  		return "", errors.Wrapf(err, "unable to find binary at %s", binaryPath)
   106  	}
   107  
   108  	return filepath.Abs(checkedPath)
   109  }
   110  

View as plain text