Fix mustWrite for Input/Output PropertyMaps (#6396)

This commit is contained in:
Luke Hoban 2021-02-23 09:04:57 +11:00 committed by GitHub
parent 277dee6cc1
commit 8fc6f910b4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 59 additions and 1 deletions

View file

@ -32,6 +32,9 @@ _(none)_
- [sdk/nodejs] Don't error when loading multiple copies of the same version of a Node.js
component package. [#6387](https://github.com/pulumi/pulumi/pull/6387)
- [cli] Skip unnecessary state file writes to address performance regression introduced in 2.16.2.
[#6396](https://github.com/pulumi/pulumi/pulls/6396)
## 2.21.1 (2021-02-18)
### Bug Fixes

View file

@ -181,22 +181,26 @@ func (ssm *sameSnapshotMutation) mustWrite(step *deploy.SameStep) bool {
// If the URN of this resource has changed, we must write the checkpoint. This should only be possible when a
// resource is aliased.
if old.URN != new.URN {
logging.V(9).Infof("SnapshotManager: mustWrite() true because of URN")
return true
}
// If the type of this resource has changed, we must write the checkpoint. This should only be possible when a
// resource is aliased.
if old.Type != new.Type {
logging.V(9).Infof("SnapshotManager: mustWrite() true because of Type")
return true
}
// If the kind of this resource has changed, we must write the checkpoint.
if old.Custom != new.Custom {
logging.V(9).Infof("SnapshotManager: mustWrite() true because of Custom")
return true
}
// We need to persist the changes if CustomTimes have changed
if old.CustomTimeouts != new.CustomTimeouts {
logging.V(9).Infof("SnapshotManager: mustWrite() true because of CustomTimeouts")
return true
}
@ -205,23 +209,31 @@ func (ssm *sameSnapshotMutation) mustWrite(step *deploy.SameStep) bool {
// If this resource's provider has changed, we must write the checkpoint. This can happen in scenarios involving
// aliased providers or upgrades to default providers.
if old.Provider != new.Provider {
logging.V(9).Infof("SnapshotManager: mustWrite() true because of Provider")
return true
}
// If this resource's parent has changed, we must write the checkpoint.
if old.Parent != new.Parent {
logging.V(9).Infof("SnapshotManager: mustWrite() true because of Parent")
return true
}
// If the protection attribute of this resource has changed, we must write the checkpoint.
if old.Protect != new.Protect {
logging.V(9).Infof("SnapshotManager: mustWrite() true because of Protect")
return true
}
// If the inputs or outputs of this resource have changed, we must write the checkpoint. Note that it is possible
// for the inputs of a "same" resource to have changed even if the contents of the input bags are different if the
// resource's provider deems the physical change to be semantically irrelevant.
if !reflect.DeepEqual(old.Inputs, new.Inputs) || !reflect.DeepEqual(old.Outputs, new.Outputs) {
if !old.Inputs.DeepEquals(new.Inputs) {
logging.V(9).Infof("SnapshotManager: mustWrite() true because of Inputs")
return true
}
if !old.Outputs.DeepEquals(new.Outputs) {
logging.V(9).Infof("SnapshotManager: mustWrite() true because of Outputs")
return true
}
@ -235,6 +247,7 @@ func (ssm *sameSnapshotMutation) mustWrite(step *deploy.SameStep) bool {
// lists being empty ourselves.
if len(old.Dependencies) != 0 || len(new.Dependencies) != 0 {
if !reflect.DeepEqual(old.Dependencies, new.Dependencies) {
logging.V(9).Infof("SnapshotManager: mustWrite() true because of Dependencies")
return true
}
}
@ -242,6 +255,7 @@ func (ssm *sameSnapshotMutation) mustWrite(step *deploy.SameStep) bool {
// Init errors are strictly advisory, so we do not consider them when deciding whether or not to write the
// checkpoint.
logging.V(9).Infof("SnapshotManager: mustWrite() false")
return false
}
@ -275,6 +289,7 @@ func (ssm *sameSnapshotMutation) End(step deploy.Step, successful bool) error {
return false
}
logging.V(9).Infof("SnapshotManager: sameSnapshotMutation.End() not eliding write")
return true
})
}

View file

@ -21,10 +21,13 @@ import (
"github.com/stretchr/testify/assert"
"github.com/pulumi/pulumi/pkg/v2/resource/deploy"
"github.com/pulumi/pulumi/pkg/v2/resource/stack"
"github.com/pulumi/pulumi/pkg/v2/secrets"
"github.com/pulumi/pulumi/pkg/v2/secrets/b64"
"github.com/pulumi/pulumi/pkg/v2/version"
"github.com/pulumi/pulumi/sdk/v2/go/common/resource"
"github.com/pulumi/pulumi/sdk/v2/go/common/resource/config"
"github.com/pulumi/pulumi/sdk/v2/go/common/resource/plugin"
"github.com/pulumi/pulumi/sdk/v2/go/common/tokens"
)
@ -72,6 +75,16 @@ func NewResourceWithDeps(name string, deps []resource.URN) *resource.State {
}
}
func NewResourceWithInputs(name string, inputs resource.PropertyMap) *resource.State {
return &resource.State{
Type: tokens.Type("test"),
URN: resource.URN(name),
Inputs: inputs,
Outputs: make(resource.PropertyMap),
Dependencies: []resource.URN{},
}
}
func NewResource(name string, deps ...resource.URN) *resource.State {
return NewResourceWithDeps(name, deps)
}
@ -134,6 +147,33 @@ func TestSamesWithEmptyDependencies(t *testing.T) {
assert.Len(t, sp.SavedSnapshots, 0, "expected no snapshots to be saved for same step")
}
func TestSamesWithEmptyArraysInInputs(t *testing.T) {
// Model reading from state file
state := map[string]interface{}{"defaults": []interface{}{}}
inputs, err := stack.DeserializeProperties(state, config.NopDecrypter, config.NopEncrypter)
assert.NoError(t, err)
res := NewResourceWithInputs("a-unique-urn-resource-a", inputs)
snap := NewSnapshot([]*resource.State{
res,
})
manager, sp := MockSetup(t, snap)
// Model passing into and back out of RPC layer (e.g. via `Check`)
marshalledInputs, err := plugin.MarshalProperties(inputs, plugin.MarshalOptions{})
assert.NoError(t, err)
inputsUpdated, err := plugin.UnmarshalProperties(marshalledInputs, plugin.MarshalOptions{})
assert.NoError(t, err)
resUpdated := NewResourceWithInputs(string(res.URN), inputsUpdated)
same := deploy.NewSameStep(nil, nil, res, resUpdated)
mutation, err := manager.BeginMutation(same)
assert.NoError(t, err)
err = mutation.End(same, true)
assert.NoError(t, err)
assert.Len(t, sp.SavedSnapshots, 0, "expected no snapshots to be saved for same step")
}
// This test challenges the naive approach of mutating resources
// that are the targets of Same steps in-place by changing the dependencies
// of two resources in the snapshot, which is perfectly legal in our system