diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/svchost/auth/helper_program.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/svchost/auth/helper_program.go | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/svchost/auth/helper_program.go b/vendor/github.com/hashicorp/terraform/svchost/auth/helper_program.go new file mode 100644 index 0000000..d72ffe3 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/svchost/auth/helper_program.go | |||
@@ -0,0 +1,80 @@ | |||
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 | } | ||