stackstate: Include correct object data when announcing applied resource

Previously we just had this just stubbed out to always return an empty
object because we didn't have the schema information available to
transcode the JSON-encoded state data into the form our RPC API wants to
produce.

An earlier commit added the schema information we need, so we can now
transcode just in time to produce the protocol buffers serialization of
the applied change description.

This is still otherwise just a stub implementation. We'll still need to
deal with emitting the "raw" representation of this state for use in
future plans, and make sure we're properly handling deposed objects, in
future commits.
pull/34738/head
Martin Atkins 2 years ago
parent 74215a4451
commit d91e5dc9f1

@ -1,7 +1,10 @@
package stackstate
import (
"fmt"
"github.com/hashicorp/terraform/internal/configs/configschema"
"github.com/hashicorp/terraform/internal/plans"
"github.com/hashicorp/terraform/internal/rpcapi/terraform1"
"github.com/hashicorp/terraform/internal/stacks/stackaddrs"
"github.com/hashicorp/terraform/internal/states"
@ -52,7 +55,28 @@ func (ac *AppliedChangeResourceInstance) AppliedChangeProto() (*terraform1.Appli
// but this is sufficient for this early stub since we're not yet emitting
// any other change types.
tmpKey := ac.ResourceInstanceAddr.String()
if ac.NewStateSrc.Current != nil {
if currentObjSrc := ac.NewStateSrc.Current; currentObjSrc != nil {
// TRICKY: For historical reasons, a states.ResourceInstance
// contains pre-JSON-encoded dynamic data ready to be
// inserted verbatim into Terraform CLI's traditional
// JSON-based state file format. However, our RPC API
// exclusively uses MessagePack encoding for dynamic
// values, and so we will need to use the ac.Schema to
// transcode the data.
ty := ac.Schema.ImpliedType()
currentObj, err := currentObjSrc.Decode(ty)
if err != nil {
// It would be _very_ strange to get here because we should just
// be reversing the same encoding operation done earlier to
// produce this object, using exactly the same schema.
return nil, fmt.Errorf("cannot decode new state for %s in preparation for saving it: %w", ac.ResourceInstanceAddr, err)
}
encValue, err := plans.NewDynamicValue(currentObj.Value, ty)
if err != nil {
return nil, fmt.Errorf("cannot encode new state for %s in preparation for saving it: %w", ac.ResourceInstanceAddr, err)
}
protoValue := terraform1.NewDynamicValue(encValue, currentObjSrc.AttrSensitivePaths)
descs = append(descs, &terraform1.AppliedChange_ChangeDescription{
Key: tmpKey,
Description: &terraform1.AppliedChange_ChangeDescription_ResourceInstance{
@ -61,23 +85,7 @@ func (ac *AppliedChangeResourceInstance) AppliedChangeProto() (*terraform1.Appli
ComponentInstanceAddr: ac.ResourceInstanceAddr.Component.String(),
ResourceInstanceAddr: ac.ResourceInstanceAddr.Item.String(),
},
// FIXME: The NewStateSrc values are serialized as JSON
// for inclusion in traditional Terraform's JSON state
// format, but we want MessagePack here for consistency
// with the rest of the RPC API protocol. However, we
// can't convert between the two without access to the
// provider schema. We'll need to handle that conversion
// upstream somewhere. For now we're just always returning
// an empty object here as placeholder, which is very wrong
// but is at least something we can use for early
// development of client code concurrently with working on
// the rest of this.
NewValue: &terraform1.DynamicValue{
Msgpack: []byte{
0b1000_0000, // MessagePack coding of a zero-length "fixmap"
},
},
NewValue: protoValue,
},
},
})

Loading…
Cancel
Save