Merge pull request #791 from pulumi/AllowUnknownsPreview

Supply unknown properties to providers during preview.
This commit is contained in:
Pat Gavlin 2018-01-09 19:15:17 -08:00 committed by GitHub
commit 208b7296be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 32 additions and 20 deletions

View file

@ -70,7 +70,7 @@ func plan(info *planContext, opts deployOptions) (*planResult, error) {
}
// Generate a plan; this API handles all interesting cases (create, update, delete).
plan := deploy.NewPlan(ctx, target, target.Snapshot, source, analyzers)
plan := deploy.NewPlan(ctx, target, target.Snapshot, source, analyzers, opts.DryRun)
return &planResult{
Ctx: ctx,
Info: info,

View file

@ -23,6 +23,7 @@ type Plan struct {
olds map[resource.URN]*resource.State // a map of all old resources.
source Source // the source of new resources.
analyzers []tokens.QName // the analyzers to run during this plan's generation.
preview bool // true if this plan is to be previewed rather than applied.
}
// NewPlan creates a new deployment plan from a resource snapshot plus a package to evaluate.
@ -34,7 +35,9 @@ type Plan struct {
//
// Note that a plan uses internal concurrency and parallelism in various ways, so it must be closed if for some reason
// a plan isn't carried out to its final conclusion. This will result in cancelation and reclamation of OS resources.
func NewPlan(ctx *plugin.Context, target *Target, prev *Snapshot, source Source, analyzers []tokens.QName) *Plan {
func NewPlan(ctx *plugin.Context, target *Target, prev *Snapshot, source Source, analyzers []tokens.QName,
preview bool) *Plan {
contract.Assert(ctx != nil)
contract.Assert(target != nil)
contract.Assert(source != nil)
@ -61,6 +64,7 @@ func NewPlan(ctx *plugin.Context, target *Target, prev *Snapshot, source Source,
olds: olds,
source: source,
analyzers: analyzers,
preview: preview,
}
}

View file

@ -296,11 +296,14 @@ func (iter *PlanIterator) makeRegisterResouceSteps(e RegisterResourceEvent) ([]S
}
}
// We only allow unknown property values to be exposed to the provider if we are performing a preview.
allowUnknowns := iter.p.preview
// Ensure the provider is okay with this resource and fetch the inputs to pass to subsequent methods.
news, inputs := new.Inputs, new.Inputs
if prov != nil {
var failures []plugin.CheckFailure
inputs, failures, err = prov.Check(urn, olds, news)
inputs, failures, err = prov.Check(urn, olds, news, allowUnknowns)
if err != nil {
return nil, err
} else if iter.issueCheckErrors(new, urn, failures) {
@ -354,7 +357,7 @@ func (iter *PlanIterator) makeRegisterResouceSteps(e RegisterResourceEvent) ([]S
// The properties changed; we need to figure out whether to do an update or replacement.
var diff plugin.DiffResult
if prov != nil {
if diff, err = prov.Diff(urn, old.ID, oldState, inputs); err != nil {
if diff, err = prov.Diff(urn, old.ID, oldState, inputs, allowUnknowns); err != nil {
return nil, err
}
}
@ -367,7 +370,7 @@ func (iter *PlanIterator) makeRegisterResouceSteps(e RegisterResourceEvent) ([]S
// had assumed that we were going to carry them over from the old resource, which is no longer true.
if prov != nil {
var failures []plugin.CheckFailure
inputs, failures, err = prov.Check(urn, nil, news)
inputs, failures, err = prov.Check(urn, nil, news, allowUnknowns)
if err != nil {
return nil, err
} else if iter.issueCheckErrors(new, urn, failures) {

View file

@ -24,7 +24,7 @@ func TestNullPlan(t *testing.T) {
assert.Nil(t, err)
targ := &Target{Name: tokens.QName("null")}
prev := NewSnapshot(targ.Name, Manifest{}, nil)
plan := NewPlan(ctx, targ, prev, NullSource, nil)
plan := NewPlan(ctx, targ, prev, NullSource, nil, false)
iter, err := plan.Start(Options{})
assert.Nil(t, err)
assert.NotNil(t, iter)
@ -45,7 +45,7 @@ func TestErrorPlan(t *testing.T) {
assert.Nil(t, err)
targ := &Target{Name: tokens.QName("errs")}
prev := NewSnapshot(targ.Name, Manifest{}, nil)
plan := NewPlan(ctx, targ, prev, &errorSource{err: errors.New("ITERATE"), duringIterate: true}, nil)
plan := NewPlan(ctx, targ, prev, &errorSource{err: errors.New("ITERATE"), duringIterate: true}, nil, false)
iter, err := plan.Start(Options{})
assert.Nil(t, iter)
assert.NotNil(t, err)
@ -60,7 +60,7 @@ func TestErrorPlan(t *testing.T) {
assert.Nil(t, err)
targ := &Target{Name: tokens.QName("errs")}
prev := NewSnapshot(targ.Name, Manifest{}, nil)
plan := NewPlan(ctx, targ, prev, &errorSource{err: errors.New("NEXT"), duringIterate: false}, nil)
plan := NewPlan(ctx, targ, prev, &errorSource{err: errors.New("NEXT"), duringIterate: false}, nil, false)
iter, err := plan.Start(Options{})
assert.Nil(t, err)
assert.NotNil(t, iter)
@ -216,7 +216,7 @@ func TestBasicCRUDPlan(t *testing.T) {
source := NewFixedSource(pkgname, []SourceEvent{newStateA, newStateB, newStateC})
// Next up, create a plan from the new and old, and validate its shape.
plan := NewPlan(ctx, targ, oldsnap, source, nil)
plan := NewPlan(ctx, targ, oldsnap, source, nil, false)
// Next, validate the steps and ensure that we see all of the expected ones. Note that there aren't any
// dependencies between the steps, so we must validate it in a way that's insensitive of order.
@ -398,7 +398,7 @@ func (prov *testProvider) Configure(vars map[tokens.ModuleMember]string) error {
return prov.config(vars)
}
func (prov *testProvider) Check(urn resource.URN,
olds, news resource.PropertyMap) (resource.PropertyMap, []plugin.CheckFailure, error) {
olds, news resource.PropertyMap, _ bool) (resource.PropertyMap, []plugin.CheckFailure, error) {
return prov.check(urn, olds, news)
}
func (prov *testProvider) Create(urn resource.URN, props resource.PropertyMap) (resource.ID,
@ -406,7 +406,7 @@ func (prov *testProvider) Create(urn resource.URN, props resource.PropertyMap) (
return prov.create(urn, props)
}
func (prov *testProvider) Diff(urn resource.URN, id resource.ID,
olds resource.PropertyMap, news resource.PropertyMap) (plugin.DiffResult, error) {
olds resource.PropertyMap, news resource.PropertyMap, _ bool) (plugin.DiffResult, error) {
return prov.diff(urn, id, olds, news)
}
func (prov *testProvider) Update(urn resource.URN, id resource.ID,

View file

@ -28,9 +28,11 @@ type Provider interface {
Configure(vars map[tokens.ModuleMember]string) error
// Check validates that the given property bag is valid for a resource of the given type and returns the inputs
// that should be passed to successive calls to Diff, Create, or Update for this resource.
Check(urn resource.URN, olds, news resource.PropertyMap) (resource.PropertyMap, []CheckFailure, error)
Check(urn resource.URN, olds, news resource.PropertyMap,
allowUnknowns bool) (resource.PropertyMap, []CheckFailure, error)
// Diff checks what impacts a hypothetical update will have on the resource's properties.
Diff(urn resource.URN, id resource.ID, olds resource.PropertyMap, news resource.PropertyMap) (DiffResult, error)
Diff(urn resource.URN, id resource.ID, olds resource.PropertyMap, news resource.PropertyMap,
allowUnknowns bool) (DiffResult, error)
// Create allocates a new instance of the provided resource and returns its unique resource.ID.
Create(urn resource.URN, news resource.PropertyMap) (resource.ID, resource.PropertyMap, resource.Status, error)
// Update updates an existing resource with new values.

View file

@ -71,16 +71,18 @@ func (p *provider) Configure(vars map[tokens.ModuleMember]string) error {
// Check validates that the given property bag is valid for a resource of the given type.
func (p *provider) Check(urn resource.URN,
olds, news resource.PropertyMap) (resource.PropertyMap, []CheckFailure, error) {
olds, news resource.PropertyMap, allowUnknowns bool) (resource.PropertyMap, []CheckFailure, error) {
label := fmt.Sprintf("%s.Check(%s)", p.label(), urn)
glog.V(7).Infof("%s executing (#olds=%d,#news=%d", label, len(olds), len(news))
molds, err := MarshalProperties(olds, MarshalOptions{Label: fmt.Sprintf("%s.olds", label)})
molds, err := MarshalProperties(olds, MarshalOptions{Label: fmt.Sprintf("%s.olds", label),
KeepUnknowns: allowUnknowns})
if err != nil {
return nil, nil, err
}
mnews, err := MarshalProperties(news, MarshalOptions{Label: fmt.Sprintf("%s.news", label)})
mnews, err := MarshalProperties(news, MarshalOptions{Label: fmt.Sprintf("%s.news", label),
KeepUnknowns: allowUnknowns})
if err != nil {
return nil, nil, err
}
@ -99,7 +101,7 @@ func (p *provider) Check(urn resource.URN,
var inputs resource.PropertyMap
if ins := resp.GetInputs(); ins != nil {
inputs, err = UnmarshalProperties(ins, MarshalOptions{
Label: fmt.Sprintf("%s.inputs", label), RejectUnknowns: true})
Label: fmt.Sprintf("%s.inputs", label), KeepUnknowns: allowUnknowns, RejectUnknowns: !allowUnknowns})
if err != nil {
return nil, nil, err
}
@ -117,7 +119,7 @@ func (p *provider) Check(urn resource.URN,
// Diff checks what impacts a hypothetical update will have on the resource's properties.
func (p *provider) Diff(urn resource.URN, id resource.ID,
olds resource.PropertyMap, news resource.PropertyMap) (DiffResult, error) {
olds resource.PropertyMap, news resource.PropertyMap, allowUnknowns bool) (DiffResult, error) {
contract.Assert(urn != "")
contract.Assert(id != "")
contract.Assert(news != nil)
@ -127,11 +129,12 @@ func (p *provider) Diff(urn resource.URN, id resource.ID,
glog.V(7).Infof("%s: executing (#olds=%d,#news=%d)", label, len(olds), len(news))
molds, err := MarshalProperties(olds, MarshalOptions{
Label: fmt.Sprintf("%s.olds", label), ElideAssetContents: true})
Label: fmt.Sprintf("%s.olds", label), ElideAssetContents: true, KeepUnknowns: allowUnknowns})
if err != nil {
return DiffResult{}, err
}
mnews, err := MarshalProperties(news, MarshalOptions{Label: fmt.Sprintf("%s.news", label)})
mnews, err := MarshalProperties(news, MarshalOptions{Label: fmt.Sprintf("%s.news", label),
KeepUnknowns: allowUnknowns})
if err != nil {
return DiffResult{}, err
}