Merge pull request #791 from pulumi/AllowUnknownsPreview
Supply unknown properties to providers during preview.
This commit is contained in:
commit
208b7296be
6 changed files with 32 additions and 20 deletions
|
@ -70,7 +70,7 @@ func plan(info *planContext, opts deployOptions) (*planResult, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a plan; this API handles all interesting cases (create, update, delete).
|
// 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{
|
return &planResult{
|
||||||
Ctx: ctx,
|
Ctx: ctx,
|
||||||
Info: info,
|
Info: info,
|
||||||
|
|
|
@ -23,6 +23,7 @@ type Plan struct {
|
||||||
olds map[resource.URN]*resource.State // a map of all old resources.
|
olds map[resource.URN]*resource.State // a map of all old resources.
|
||||||
source Source // the source of new resources.
|
source Source // the source of new resources.
|
||||||
analyzers []tokens.QName // the analyzers to run during this plan's generation.
|
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.
|
// 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
|
// 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.
|
// 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(ctx != nil)
|
||||||
contract.Assert(target != nil)
|
contract.Assert(target != nil)
|
||||||
contract.Assert(source != nil)
|
contract.Assert(source != nil)
|
||||||
|
@ -61,6 +64,7 @@ func NewPlan(ctx *plugin.Context, target *Target, prev *Snapshot, source Source,
|
||||||
olds: olds,
|
olds: olds,
|
||||||
source: source,
|
source: source,
|
||||||
analyzers: analyzers,
|
analyzers: analyzers,
|
||||||
|
preview: preview,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
// Ensure the provider is okay with this resource and fetch the inputs to pass to subsequent methods.
|
||||||
news, inputs := new.Inputs, new.Inputs
|
news, inputs := new.Inputs, new.Inputs
|
||||||
if prov != nil {
|
if prov != nil {
|
||||||
var failures []plugin.CheckFailure
|
var failures []plugin.CheckFailure
|
||||||
inputs, failures, err = prov.Check(urn, olds, news)
|
inputs, failures, err = prov.Check(urn, olds, news, allowUnknowns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if iter.issueCheckErrors(new, urn, failures) {
|
} 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.
|
// The properties changed; we need to figure out whether to do an update or replacement.
|
||||||
var diff plugin.DiffResult
|
var diff plugin.DiffResult
|
||||||
if prov != nil {
|
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
|
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.
|
// had assumed that we were going to carry them over from the old resource, which is no longer true.
|
||||||
if prov != nil {
|
if prov != nil {
|
||||||
var failures []plugin.CheckFailure
|
var failures []plugin.CheckFailure
|
||||||
inputs, failures, err = prov.Check(urn, nil, news)
|
inputs, failures, err = prov.Check(urn, nil, news, allowUnknowns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if iter.issueCheckErrors(new, urn, failures) {
|
} else if iter.issueCheckErrors(new, urn, failures) {
|
||||||
|
|
|
@ -24,7 +24,7 @@ func TestNullPlan(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
targ := &Target{Name: tokens.QName("null")}
|
targ := &Target{Name: tokens.QName("null")}
|
||||||
prev := NewSnapshot(targ.Name, Manifest{}, nil)
|
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{})
|
iter, err := plan.Start(Options{})
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.NotNil(t, iter)
|
assert.NotNil(t, iter)
|
||||||
|
@ -45,7 +45,7 @@ func TestErrorPlan(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
targ := &Target{Name: tokens.QName("errs")}
|
targ := &Target{Name: tokens.QName("errs")}
|
||||||
prev := NewSnapshot(targ.Name, Manifest{}, nil)
|
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{})
|
iter, err := plan.Start(Options{})
|
||||||
assert.Nil(t, iter)
|
assert.Nil(t, iter)
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
@ -60,7 +60,7 @@ func TestErrorPlan(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
targ := &Target{Name: tokens.QName("errs")}
|
targ := &Target{Name: tokens.QName("errs")}
|
||||||
prev := NewSnapshot(targ.Name, Manifest{}, nil)
|
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{})
|
iter, err := plan.Start(Options{})
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.NotNil(t, iter)
|
assert.NotNil(t, iter)
|
||||||
|
@ -216,7 +216,7 @@ func TestBasicCRUDPlan(t *testing.T) {
|
||||||
source := NewFixedSource(pkgname, []SourceEvent{newStateA, newStateB, newStateC})
|
source := NewFixedSource(pkgname, []SourceEvent{newStateA, newStateB, newStateC})
|
||||||
|
|
||||||
// Next up, create a plan from the new and old, and validate its shape.
|
// 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
|
// 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.
|
// 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)
|
return prov.config(vars)
|
||||||
}
|
}
|
||||||
func (prov *testProvider) Check(urn resource.URN,
|
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)
|
return prov.check(urn, olds, news)
|
||||||
}
|
}
|
||||||
func (prov *testProvider) Create(urn resource.URN, props resource.PropertyMap) (resource.ID,
|
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)
|
return prov.create(urn, props)
|
||||||
}
|
}
|
||||||
func (prov *testProvider) Diff(urn resource.URN, id resource.ID,
|
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)
|
return prov.diff(urn, id, olds, news)
|
||||||
}
|
}
|
||||||
func (prov *testProvider) Update(urn resource.URN, id resource.ID,
|
func (prov *testProvider) Update(urn resource.URN, id resource.ID,
|
||||||
|
|
|
@ -28,9 +28,11 @@ type Provider interface {
|
||||||
Configure(vars map[tokens.ModuleMember]string) error
|
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
|
// 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.
|
// 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 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 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)
|
Create(urn resource.URN, news resource.PropertyMap) (resource.ID, resource.PropertyMap, resource.Status, error)
|
||||||
// Update updates an existing resource with new values.
|
// Update updates an existing resource with new values.
|
||||||
|
|
|
@ -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.
|
// Check validates that the given property bag is valid for a resource of the given type.
|
||||||
func (p *provider) Check(urn resource.URN,
|
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)
|
label := fmt.Sprintf("%s.Check(%s)", p.label(), urn)
|
||||||
glog.V(7).Infof("%s executing (#olds=%d,#news=%d", label, len(olds), len(news))
|
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 {
|
if err != nil {
|
||||||
return nil, nil, err
|
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 {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -99,7 +101,7 @@ func (p *provider) Check(urn resource.URN,
|
||||||
var inputs resource.PropertyMap
|
var inputs resource.PropertyMap
|
||||||
if ins := resp.GetInputs(); ins != nil {
|
if ins := resp.GetInputs(); ins != nil {
|
||||||
inputs, err = UnmarshalProperties(ins, MarshalOptions{
|
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 {
|
if err != nil {
|
||||||
return nil, nil, err
|
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.
|
// Diff checks what impacts a hypothetical update will have on the resource's properties.
|
||||||
func (p *provider) Diff(urn resource.URN, id resource.ID,
|
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(urn != "")
|
||||||
contract.Assert(id != "")
|
contract.Assert(id != "")
|
||||||
contract.Assert(news != nil)
|
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))
|
glog.V(7).Infof("%s: executing (#olds=%d,#news=%d)", label, len(olds), len(news))
|
||||||
|
|
||||||
molds, err := MarshalProperties(olds, MarshalOptions{
|
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 {
|
if err != nil {
|
||||||
return DiffResult{}, err
|
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 {
|
if err != nil {
|
||||||
return DiffResult{}, err
|
return DiffResult{}, err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue