pulumi/sdk/go/x/auto/up.go

128 lines
3.2 KiB
Go
Raw Normal View History

2020-07-07 23:25:11 +02:00
package auto
import (
"bytes"
"encoding/json"
"os/exec"
"github.com/pkg/errors"
)
func (s *Stack) Up() (UpResult, error) {
2020-07-10 07:30:52 +02:00
var upResult UpResult
2020-07-07 23:25:11 +02:00
// TODO setup - merge pulumi.yaml, set config, etc.
2020-07-10 07:30:52 +02:00
res, err := s.initOrSelectStack()
if err != nil {
return res, errors.Wrap(err, "could not initialize or select stack")
}
2020-07-07 23:25:11 +02:00
2020-07-10 07:30:52 +02:00
stdout, stderr, err := s.runCmd("pulumi", "up", "--yes")
2020-07-07 23:25:11 +02:00
if err != nil {
2020-07-10 07:30:52 +02:00
return UpResult{
StdErr: stderr,
StdOut: stdout,
}, errors.Wrapf(err, "stderr: %s", stderr)
2020-07-07 23:25:11 +02:00
}
outs, secrets, err := s.getOutputs()
if err != nil {
return upResult, err
}
// TODO - last histroy item.
return UpResult{
2020-07-10 07:30:52 +02:00
StdOut: stdout,
StdErr: stderr,
2020-07-07 23:25:11 +02:00
Outputs: outs,
SecretOutputs: secrets,
}, nil
}
type UpResult struct {
StdOut string
StdErr string
2020-07-10 07:30:52 +02:00
Outputs map[string]interface{}
SecretOutputs map[string]interface{}
2020-07-07 23:25:11 +02:00
Summary map[string]interface{}
}
2020-07-10 07:30:52 +02:00
func (s *Stack) initOrSelectStack() (UpResult, error) {
var upResult UpResult
_, _, err := s.runCmd("pulumi", "stack", "select", s.Name)
if err != nil {
initStdout, initStderr, err := s.runCmd("pulumi", "stack", "init", s.Name)
if err != nil {
return UpResult{
StdErr: initStderr,
StdOut: initStdout,
}, errors.Wrapf(err, "unable to select or init stack: %s", initStderr)
}
}
// now parse pulumi.yaml, pulumi.stack.yaml,
// merge with our model
// re-write
// pulumi config set, config set --secrets`
// TODO consider storing hash of the yaml files so we don't have to do this for every 'up'
return upResult, nil
}
2020-07-07 23:25:11 +02:00
const secretSentinel = "[secret]"
//getOutputs returns a set of plain outputs, secret outputs, and an error
2020-07-10 07:30:52 +02:00
func (s *Stack) getOutputs() (map[string]interface{}, map[string]interface{}, error) {
2020-07-07 23:25:11 +02:00
// standard outputs
2020-07-10 07:30:52 +02:00
outStdout, outStderr, err := s.runCmd("pulumi", "stack", "output", "--json")
2020-07-07 23:25:11 +02:00
if err != nil {
2020-07-10 07:30:52 +02:00
return nil, nil, errors.Wrapf(err, "could not get outputs: stderr: %s", outStderr)
2020-07-07 23:25:11 +02:00
}
// secret outputs
2020-07-10 07:30:52 +02:00
secretStdout, secretStderr, err := s.runCmd("pulumi", "stack", "output", "--json", "--show-secrets")
2020-07-07 23:25:11 +02:00
if err != nil {
2020-07-10 07:30:52 +02:00
return nil, nil, errors.Wrapf(err, "could not get secret outputs: stderr: %s", secretStderr)
2020-07-07 23:25:11 +02:00
}
2020-07-10 07:30:52 +02:00
var outputs map[string]interface{}
var secrets map[string]interface{}
2020-07-07 23:25:11 +02:00
2020-07-10 07:30:52 +02:00
if err = json.Unmarshal([]byte(outStdout), &outputs); err != nil {
return nil, nil, errors.Wrapf(err, "error unmarshalling outputs: %s", secretStderr)
2020-07-07 23:25:11 +02:00
}
2020-07-10 07:30:52 +02:00
if err = json.Unmarshal([]byte(secretStdout), &secrets); err != nil {
return nil, nil, errors.Wrapf(err, "error unmarshalling secret outputs: %s", secretStderr)
2020-07-07 23:25:11 +02:00
}
for k, v := range outputs {
if v == secretSentinel {
delete(outputs, k)
} else {
delete(secrets, k)
}
}
return outputs, secrets, nil
}
//summary - call history and get last item
// configure - write the pulumi.yaml, pulumi.<stack>.yaml, set config & secrets
2020-07-10 07:30:52 +02:00
// runCmd execs the given command with appropriate stack context
// returning stdout, stderr, and an error value
func (s *Stack) runCmd(name string, arg ...string) (string, string, error) {
cmd := exec.Command(name, arg...)
cmd.Dir = s.Project.SourcePath
var stdout bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
return stdout.String(), stderr.String(), err
}