Merge pull request #643 from pulumi/LateDecrypt

Decrypt configuration nearer to its use.
This commit is contained in:
Pat Gavlin 2017-12-04 17:27:59 -08:00 committed by GitHub
commit 94645c313a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 55 additions and 29 deletions

View file

@ -177,8 +177,13 @@ func (b *localBackend) GetLogs(stackName tokens.QName, query operations.LogQuery
contract.Assert(snap != nil) contract.Assert(snap != nil)
contract.Assert(target != nil) contract.Assert(target != nil)
config, err := target.Config.Decrypt(target.Decrypter)
if err != nil {
return nil, err
}
components := operations.NewResourceTree(snap.Resources) components := operations.NewResourceTree(snap.Resources)
ops := components.OperationsProvider(target.Config) ops := components.OperationsProvider(config)
logs, err := ops.GetLogs(query) logs, err := ops.GetLogs(query)
if logs == nil { if logs == nil {
return nil, err return nil, err

View file

@ -39,17 +39,7 @@ func (p localStackProvider) GetTarget(name tokens.QName) (*deploy.Target, error)
return nil, err return nil, err
} }
decryptedConfig := make(map[tokens.ModuleMember]string) return &deploy.Target{Name: name, Config: config, Decrypter: p.decrypter}, nil
for k, v := range config {
decrypted, err := v.Value(p.decrypter)
if err != nil {
return nil, errors.Wrap(err, "could not decrypt configuration value")
}
decryptedConfig[k] = decrypted
}
return &deploy.Target{Name: name, Config: decryptedConfig}, nil
} }
func (p localStackProvider) GetSnapshot(name tokens.QName) (*deploy.Snapshot, error) { func (p localStackProvider) GetSnapshot(name tokens.QName) (*deploy.Snapshot, error) {

View file

@ -14,6 +14,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/pulumi/pulumi/pkg/diag/colors" "github.com/pulumi/pulumi/pkg/diag/colors"
"github.com/pulumi/pulumi/pkg/resource" "github.com/pulumi/pulumi/pkg/resource"
"github.com/pulumi/pulumi/pkg/resource/config"
"github.com/pulumi/pulumi/pkg/resource/deploy" "github.com/pulumi/pulumi/pkg/resource/deploy"
"github.com/pulumi/pulumi/pkg/resource/plugin" "github.com/pulumi/pulumi/pkg/resource/plugin"
"github.com/pulumi/pulumi/pkg/tokens" "github.com/pulumi/pulumi/pkg/tokens"
@ -185,16 +186,18 @@ func printPrelude(b *bytes.Buffer, result *planResult, planning bool) {
} }
} }
func printConfig(b *bytes.Buffer, config map[tokens.ModuleMember]string) { func printConfig(b *bytes.Buffer, cfg config.Map) {
b.WriteString(fmt.Sprintf("%vConfiguration:%v\n", colors.SpecUnimportant, colors.Reset)) b.WriteString(fmt.Sprintf("%vConfiguration:%v\n", colors.SpecUnimportant, colors.Reset))
if config != nil { if cfg != nil {
var keys []string var keys []string
for key := range config { for key := range cfg {
keys = append(keys, string(key)) keys = append(keys, string(key))
} }
sort.Strings(keys) sort.Strings(keys)
for _, key := range keys { for _, key := range keys {
b.WriteString(fmt.Sprintf(" %v: %v\n", key, config[tokens.ModuleMember(key)])) v, err := cfg[tokens.ModuleMember(key)].Value(config.NewBlindingDecrypter())
contract.Assert(err == nil)
b.WriteString(fmt.Sprintf(" %v: %v\n", key, v))
} }
} }
} }

View file

@ -36,7 +36,7 @@ type Crypter interface {
// be used when you want to display configuration information to a user but don't want to prompt for a password // be used when you want to display configuration information to a user but don't want to prompt for a password
// so secrets will not be decrypted. // so secrets will not be decrypted.
func NewBlindingDecrypter() Decrypter { func NewBlindingDecrypter() Decrypter {
return &blindingDecrypter{} return blindingDecrypter{}
} }
type blindingDecrypter struct{} type blindingDecrypter struct{}

View file

@ -12,6 +12,19 @@ import (
// Map is a bag of config stored in the settings file. // Map is a bag of config stored in the settings file.
type Map map[tokens.ModuleMember]Value type Map map[tokens.ModuleMember]Value
// Decrypt returns the configuration as a map from module member to decrypted value.
func (m Map) Decrypt(decrypter Decrypter) (map[tokens.ModuleMember]string, error) {
r := map[tokens.ModuleMember]string{}
for k, c := range m {
v, err := c.Value(decrypter)
if err != nil {
return nil, err
}
r[k] = v
}
return r, nil
}
// HasSecureValue returns true if the config map contains a secure (encrypted) value. // HasSecureValue returns true if the config map contains a secure (encrypted) value.
func (m Map) HasSecureValue() bool { func (m Map) HasSecureValue() bool {
for _, v := range m { for _, v := range m {

View file

@ -63,7 +63,7 @@ func (p *Plan) Start(opts Options) (*PlanIterator, error) {
func (p *Plan) configure() error { func (p *Plan) configure() error {
var pkgs []string var pkgs []string
pkgconfigs := make(map[tokens.Package]map[tokens.ModuleMember]string) pkgconfigs := make(map[tokens.Package]map[tokens.ModuleMember]string)
for k, v := range p.target.Config { for k, c := range p.target.Config {
pkg := k.Package() pkg := k.Package()
pkgs = append(pkgs, string(pkg)) pkgs = append(pkgs, string(pkg))
pkgconfig, has := pkgconfigs[pkg] pkgconfig, has := pkgconfigs[pkg]
@ -71,6 +71,10 @@ func (p *Plan) configure() error {
pkgconfig = make(map[tokens.ModuleMember]string) pkgconfig = make(map[tokens.ModuleMember]string)
pkgconfigs[pkg] = pkgconfig pkgconfigs[pkg] = pkgconfig
} }
v, err := c.Value(p.target.Decrypter)
if err != nil {
return err
}
pkgconfig[k] = v pkgconfig[k] = v
} }
sort.Strings(pkgs) sort.Strings(pkgs)

View file

@ -150,16 +150,24 @@ func (iter *evalSourceIterator) forkRun(opts Options) {
go func() { go func() {
// Next, launch the language plugin. // Next, launch the language plugin.
// IDEA: cache these so we reuse the same language plugin instance; if we do this, monitors must be per-run. // IDEA: cache these so we reuse the same language plugin instance; if we do this, monitors must be per-run.
rt := iter.src.runinfo.Pkg.Runtime run := func() error {
langhost, err := iter.src.plugctx.Host.LanguageRuntime(rt, iter.mon.Address()) rt := iter.src.runinfo.Pkg.Runtime
if err != nil { langhost, err := iter.src.plugctx.Host.LanguageRuntime(rt, iter.mon.Address())
err = errors.Wrapf(err, "failed to launch language host for '%v'", rt) if err != nil {
} else if langhost == nil { return errors.Wrapf(err, "failed to launch language host for '%v'", rt)
err = errors.Errorf("could not load language plugin for '%v' from $PATH", rt) } else if langhost == nil {
} else { return errors.Errorf("could not load language plugin for '%v' from $PATH", rt)
}
// Make sure to clean up before exiting. // Make sure to clean up before exiting.
defer contract.IgnoreClose(langhost) defer contract.IgnoreClose(langhost)
// Decrypt the configuration.
config, err := iter.src.runinfo.Target.Config.Decrypt(iter.src.runinfo.Target.Decrypter)
if err != nil {
return err
}
// Now run the actual program. // Now run the actual program.
var progerr string var progerr string
progerr, err = langhost.Run(plugin.RunInfo{ progerr, err = langhost.Run(plugin.RunInfo{
@ -168,7 +176,7 @@ func (iter *evalSourceIterator) forkRun(opts Options) {
Pwd: iter.src.runinfo.Pwd, Pwd: iter.src.runinfo.Pwd,
Program: iter.src.runinfo.Program, Program: iter.src.runinfo.Program,
Args: iter.src.runinfo.Args, Args: iter.src.runinfo.Args,
Config: iter.src.runinfo.Target.Config, Config: config,
DryRun: iter.src.dryRun, DryRun: iter.src.dryRun,
Parallel: opts.Parallel, Parallel: opts.Parallel,
}) })
@ -176,10 +184,11 @@ func (iter *evalSourceIterator) forkRun(opts Options) {
// If the program had an unhandled error; propagate it to the caller. // If the program had an unhandled error; propagate it to the caller.
err = errors.Errorf("an unhandled error occurred: %v", progerr) err = errors.Errorf("an unhandled error occurred: %v", progerr)
} }
return err
} }
// Communicate the error, if it exists, or nil if the program exited cleanly. // Communicate the error, if it exists, or nil if the program exited cleanly.
iter.finChan <- err iter.finChan <- run()
}() }()
} }
} }

View file

@ -3,11 +3,13 @@
package deploy package deploy
import ( import (
"github.com/pulumi/pulumi/pkg/resource/config"
"github.com/pulumi/pulumi/pkg/tokens" "github.com/pulumi/pulumi/pkg/tokens"
) )
// Target represents information about a deployment target. // Target represents information about a deployment target.
type Target struct { type Target struct {
Name tokens.QName // the target stack name. Name tokens.QName // the target stack name.
Config map[tokens.ModuleMember]string // optional configuration key/values. Config config.Map // optional configuration key/value pairs.
Decrypter config.Decrypter // decrypter for secret configuration values.
} }