Merge pull request #643 from pulumi/LateDecrypt
Decrypt configuration nearer to its use.
This commit is contained in:
commit
94645c313a
|
@ -177,8 +177,13 @@ func (b *localBackend) GetLogs(stackName tokens.QName, query operations.LogQuery
|
|||
contract.Assert(snap != nil)
|
||||
contract.Assert(target != nil)
|
||||
|
||||
config, err := target.Config.Decrypt(target.Decrypter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
components := operations.NewResourceTree(snap.Resources)
|
||||
ops := components.OperationsProvider(target.Config)
|
||||
ops := components.OperationsProvider(config)
|
||||
logs, err := ops.GetLogs(query)
|
||||
if logs == nil {
|
||||
return nil, err
|
||||
|
|
|
@ -39,17 +39,7 @@ func (p localStackProvider) GetTarget(name tokens.QName) (*deploy.Target, error)
|
|||
return nil, err
|
||||
}
|
||||
|
||||
decryptedConfig := make(map[tokens.ModuleMember]string)
|
||||
|
||||
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
|
||||
return &deploy.Target{Name: name, Config: config, Decrypter: p.decrypter}, nil
|
||||
}
|
||||
|
||||
func (p localStackProvider) GetSnapshot(name tokens.QName) (*deploy.Snapshot, error) {
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
"github.com/pulumi/pulumi/pkg/diag/colors"
|
||||
"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/plugin"
|
||||
"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))
|
||||
if config != nil {
|
||||
if cfg != nil {
|
||||
var keys []string
|
||||
for key := range config {
|
||||
for key := range cfg {
|
||||
keys = append(keys, string(key))
|
||||
}
|
||||
sort.Strings(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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
// so secrets will not be decrypted.
|
||||
func NewBlindingDecrypter() Decrypter {
|
||||
return &blindingDecrypter{}
|
||||
return blindingDecrypter{}
|
||||
}
|
||||
|
||||
type blindingDecrypter struct{}
|
||||
|
|
|
@ -12,6 +12,19 @@ import (
|
|||
// Map is a bag of config stored in the settings file.
|
||||
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.
|
||||
func (m Map) HasSecureValue() bool {
|
||||
for _, v := range m {
|
||||
|
|
|
@ -63,7 +63,7 @@ func (p *Plan) Start(opts Options) (*PlanIterator, error) {
|
|||
func (p *Plan) configure() error {
|
||||
var pkgs []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()
|
||||
pkgs = append(pkgs, string(pkg))
|
||||
pkgconfig, has := pkgconfigs[pkg]
|
||||
|
@ -71,6 +71,10 @@ func (p *Plan) configure() error {
|
|||
pkgconfig = make(map[tokens.ModuleMember]string)
|
||||
pkgconfigs[pkg] = pkgconfig
|
||||
}
|
||||
v, err := c.Value(p.target.Decrypter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pkgconfig[k] = v
|
||||
}
|
||||
sort.Strings(pkgs)
|
||||
|
|
|
@ -150,16 +150,24 @@ func (iter *evalSourceIterator) forkRun(opts Options) {
|
|||
go func() {
|
||||
// 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.
|
||||
rt := iter.src.runinfo.Pkg.Runtime
|
||||
langhost, err := iter.src.plugctx.Host.LanguageRuntime(rt, iter.mon.Address())
|
||||
if err != nil {
|
||||
err = errors.Wrapf(err, "failed to launch language host for '%v'", rt)
|
||||
} else if langhost == nil {
|
||||
err = errors.Errorf("could not load language plugin for '%v' from $PATH", rt)
|
||||
} else {
|
||||
run := func() error {
|
||||
rt := iter.src.runinfo.Pkg.Runtime
|
||||
langhost, err := iter.src.plugctx.Host.LanguageRuntime(rt, iter.mon.Address())
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to launch language host for '%v'", rt)
|
||||
} else if langhost == nil {
|
||||
return errors.Errorf("could not load language plugin for '%v' from $PATH", rt)
|
||||
}
|
||||
|
||||
// Make sure to clean up before exiting.
|
||||
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.
|
||||
var progerr string
|
||||
progerr, err = langhost.Run(plugin.RunInfo{
|
||||
|
@ -168,7 +176,7 @@ func (iter *evalSourceIterator) forkRun(opts Options) {
|
|||
Pwd: iter.src.runinfo.Pwd,
|
||||
Program: iter.src.runinfo.Program,
|
||||
Args: iter.src.runinfo.Args,
|
||||
Config: iter.src.runinfo.Target.Config,
|
||||
Config: config,
|
||||
DryRun: iter.src.dryRun,
|
||||
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.
|
||||
err = errors.Errorf("an unhandled error occurred: %v", progerr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Communicate the error, if it exists, or nil if the program exited cleanly.
|
||||
iter.finChan <- err
|
||||
iter.finChan <- run()
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,13 @@
|
|||
package deploy
|
||||
|
||||
import (
|
||||
"github.com/pulumi/pulumi/pkg/resource/config"
|
||||
"github.com/pulumi/pulumi/pkg/tokens"
|
||||
)
|
||||
|
||||
// Target represents information about a deployment target.
|
||||
type Target struct {
|
||||
Name tokens.QName // the target stack name.
|
||||
Config map[tokens.ModuleMember]string // optional configuration key/values.
|
||||
Name tokens.QName // the target stack name.
|
||||
Config config.Map // optional configuration key/value pairs.
|
||||
Decrypter config.Decrypter // decrypter for secret configuration values.
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue