a plan with no diff should return proposed state

PlanResourceChange isn't returning the diff, but rather it is returning
the destired state. If the propsed state results in a nil diff, then,
the propsed state is what should be returned.

Make sure Meta fields are not nil, as the schema package expects those
to be initialised.
This commit is contained in:
James Bardin 2018-10-06 12:38:00 -04:00 committed by Martin Atkins
parent 795161f615
commit 0b8c38207a
2 changed files with 83 additions and 8 deletions

View File

@ -146,7 +146,7 @@ func (s *GRPCProviderServer) UpgradeResourceState(_ context.Context, req *proto.
var err error
// if there's a JSON state, we need to decode it.
if req.RawState.Json != nil {
if len(req.RawState.Json) > 0 {
err = json.Unmarshal(req.RawState.Json, &jsonMap)
if err != nil {
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
@ -390,6 +390,14 @@ func (s *GRPCProviderServer) PlanResourceChange(_ context.Context, req *proto.Pl
}
priorState := schema.InstanceStateFromStateValue(priorStateVal, res.SchemaVersion)
priorPrivate := make(map[string]interface{})
if len(req.PriorPrivate) > 0 {
if err := json.Unmarshal(req.PriorPrivate, &priorPrivate); err != nil {
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
return resp, nil
}
}
priorState.Meta = priorPrivate
// turn the propsed state into a legacy configuration
config := terraform.NewResourceConfigShimmed(proposedNewStateVal, block)
@ -403,9 +411,9 @@ func (s *GRPCProviderServer) PlanResourceChange(_ context.Context, req *proto.Pl
if diff == nil {
// schema.Provider.Diff returns nil if it ends up making a diff with
// no changes, but our new interface wants us to return an actual
// change description that _shows_ there are no changes, so we need
// to synthesize one here.
resp.PlannedState = req.PriorState
// change description that _shows_ there are no changes, so we return
// the proposed change that produces no diff.
resp.PlannedState = req.ProposedNewState
return resp, nil
}
@ -480,10 +488,12 @@ func (s *GRPCProviderServer) ApplyResourceChange(_ context.Context, req *proto.A
priorState := schema.InstanceStateFromStateValue(priorStateVal, res.SchemaVersion)
var private map[string]interface{}
if err := json.Unmarshal(req.PlannedPrivate, &private); err != nil {
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
return resp, nil
private := make(map[string]interface{})
if len(req.PlannedPrivate) > 0 {
if err := json.Unmarshal(req.PlannedPrivate, &private); err != nil {
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
return resp, nil
}
}
diff, err := schema.DiffFromValues(priorStateVal, plannedStateVal, res)
@ -492,6 +502,7 @@ func (s *GRPCProviderServer) ApplyResourceChange(_ context.Context, req *proto.A
return resp, nil
}
diff.Meta = private
newInstanceState, err := s.provider.Apply(info, priorState, diff)
if err != nil {
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)

View File

@ -1,6 +1,7 @@
package plugin
import (
"context"
"fmt"
"testing"
@ -293,3 +294,66 @@ func TestUpgradeState_flatmapState(t *testing.T) {
})
}
}
func TestPlanResourceChange(t *testing.T) {
r := &schema.Resource{
SchemaVersion: 4,
Schema: map[string]*schema.Schema{
"foo": {
Type: schema.TypeInt,
Optional: true,
},
},
}
server := &GRPCProviderServer{
provider: &schema.Provider{
ResourcesMap: map[string]*schema.Resource{
"test": r,
},
},
}
schema := r.CoreConfigSchema()
priorState, err := msgpack.Marshal(cty.NullVal(schema.ImpliedType()), schema.ImpliedType())
if err != nil {
t.Fatal(err)
}
// A propsed state with only the ID unknown will produce a nil diff, and
// should return the propsed state value.
proposedVal, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
}))
if err != nil {
t.Fatal(err)
}
proposedState, err := msgpack.Marshal(proposedVal, schema.ImpliedType())
if err != nil {
t.Fatal(err)
}
testReq := &proto.PlanResourceChange_Request{
TypeName: "test",
PriorState: &proto.DynamicValue{
Msgpack: priorState,
},
ProposedNewState: &proto.DynamicValue{
Msgpack: proposedState,
},
}
resp, err := server.PlanResourceChange(context.Background(), testReq)
if err != nil {
t.Fatal(err)
}
plannedStateVal, err := msgpack.Unmarshal(resp.PlannedState.Msgpack, schema.ImpliedType())
if err != nil {
t.Fatal(err)
}
if !cmp.Equal(proposedVal, plannedStateVal, valueComparer) {
t.Fatal(cmp.Diff(proposedVal, plannedStateVal, valueComparer))
}
}