github.com/jameswoolfenden/terraform@v0.11.12-beta1/svchost/auth/helper_program.go (about)

     1  package auth
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"os/exec"
     8  	"path/filepath"
     9  
    10  	"github.com/hashicorp/terraform/svchost"
    11  )
    12  
    13  type helperProgramCredentialsSource struct {
    14  	executable string
    15  	args       []string
    16  }
    17  
    18  // HelperProgramCredentialsSource returns a CredentialsSource that runs the
    19  // given program with the given arguments in order to obtain credentials.
    20  //
    21  // The given executable path must be an absolute path; it is the caller's
    22  // responsibility to validate and process a relative path or other input
    23  // provided by an end-user. If the given path is not absolute, this
    24  // function will panic.
    25  //
    26  // When credentials are requested, the program will be run in a child process
    27  // with the given arguments along with two additional arguments added to the
    28  // end of the list: the literal string "get", followed by the requested
    29  // hostname in ASCII compatibility form (punycode form).
    30  func HelperProgramCredentialsSource(executable string, args ...string) CredentialsSource {
    31  	if !filepath.IsAbs(executable) {
    32  		panic("NewCredentialsSourceHelperProgram requires absolute path to executable")
    33  	}
    34  
    35  	fullArgs := make([]string, len(args)+1)
    36  	fullArgs[0] = executable
    37  	copy(fullArgs[1:], args)
    38  
    39  	return &helperProgramCredentialsSource{
    40  		executable: executable,
    41  		args:       fullArgs,
    42  	}
    43  }
    44  
    45  func (s *helperProgramCredentialsSource) ForHost(host svchost.Hostname) (HostCredentials, error) {
    46  	args := make([]string, len(s.args), len(s.args)+2)
    47  	copy(args, s.args)
    48  	args = append(args, "get")
    49  	args = append(args, string(host))
    50  
    51  	outBuf := bytes.Buffer{}
    52  	errBuf := bytes.Buffer{}
    53  
    54  	cmd := exec.Cmd{
    55  		Path:   s.executable,
    56  		Args:   args,
    57  		Stdin:  nil,
    58  		Stdout: &outBuf,
    59  		Stderr: &errBuf,
    60  	}
    61  	err := cmd.Run()
    62  	if _, isExitErr := err.(*exec.ExitError); isExitErr {
    63  		errText := errBuf.String()
    64  		if errText == "" {
    65  			// Shouldn't happen for a well-behaved helper program
    66  			return nil, fmt.Errorf("error in %s, but it produced no error message", s.executable)
    67  		}
    68  		return nil, fmt.Errorf("error in %s: %s", s.executable, errText)
    69  	} else if err != nil {
    70  		return nil, fmt.Errorf("failed to run %s: %s", s.executable, err)
    71  	}
    72  
    73  	var m map[string]interface{}
    74  	err = json.Unmarshal(outBuf.Bytes(), &m)
    75  	if err != nil {
    76  		return nil, fmt.Errorf("malformed output from %s: %s", s.executable, err)
    77  	}
    78  
    79  	return HostCredentialsFromMap(m), nil
    80  }