states: object Private data is []byte, not cty.Value

We're going to allow the provider to encode whatever it wants in here, so
a provider can use whatever is most convenient for its implementation
language and to avoid some of the bugs we saw with the prior model where
the forced round-trip through JSON and back into interface{} would cause
some loss of fidelity, leading to bugs.
This commit is contained in:
Martin Atkins 2018-08-17 16:11:07 -07:00
parent 08a8834882
commit fb57801dfe
7 changed files with 26 additions and 44 deletions

View File

@ -18,7 +18,7 @@ type ImportedObject struct {
// Private corresponds to the field of the same name on // Private corresponds to the field of the same name on
// ResourceInstanceObject, where the provider can record private data that // ResourceInstanceObject, where the provider can record private data that
// will be available for future operations. // will be available for future operations.
Private cty.Value Private []byte
} }
// AsInstanceObject converts the receiving ImportedObject into a // AsInstanceObject converts the receiving ImportedObject into a

View File

@ -23,7 +23,7 @@ type ResourceInstanceObject struct {
// last created or updated. Terraform Core does not use this value in // last created or updated. Terraform Core does not use this value in
// any way and it is not exposed anywhere in the user interface, so // any way and it is not exposed anywhere in the user interface, so
// a provider can use it for retaining any necessary private state. // a provider can use it for retaining any necessary private state.
Private cty.Value Private []byte
// Status represents the "readiness" of the object as of the last time // Status represents the "readiness" of the object as of the last time
// it was updated. // it was updated.

View File

@ -51,7 +51,7 @@ type ResourceInstanceObjectSrc struct {
// These fields all correspond to the fields of the same name on // These fields all correspond to the fields of the same name on
// ResourceInstanceObject. // ResourceInstanceObject.
Private cty.Value Private []byte
Status ObjectStatus Status ObjectStatus
Dependencies []addrs.Referenceable Dependencies []addrs.Referenceable
} }

View File

@ -38,7 +38,9 @@
"triggers.%": "1", "triggers.%": "1",
"triggers.index": "0" "triggers.index": "0"
}, },
"meta": {}, "meta": {
"schema_version": "1"
},
"tainted": false "tainted": false
}, },
"deposed": [], "deposed": [],
@ -80,7 +82,9 @@
"triggers.woot": "us-west-2", "triggers.woot": "us-west-2",
"triggers.workspace": "default" "triggers.workspace": "default"
}, },
"meta": {}, "meta": {
"foo": "bar"
},
"tainted": false "tainted": false
}, },
"deposed": [], "deposed": [],

View File

@ -38,7 +38,7 @@
}, },
"depends_on": ["null_resource.baz"], "depends_on": ["null_resource.baz"],
"index_key": 0, "index_key": 0,
"schema_version": 0 "schema_version": 1
}, },
{ {
"attributes_flat": { "attributes_flat": {
@ -72,7 +72,8 @@
"triggers.woot": "us-west-2", "triggers.woot": "us-west-2",
"triggers.workspace": "default" "triggers.workspace": "default"
}, },
"schema_version": 0 "schema_version": 0,
"private": "eyJmb28iOiJiYXIifQ=="
} }
] ]
}, },

View File

@ -224,12 +224,19 @@ func upgradeInstanceObjectV3ToV4(rsOld *resourceStateV2, isOld *instanceStateV2,
var schemaVersion uint64 var schemaVersion uint64
migratedSchemaVersion := false migratedSchemaVersion := false
if raw, exists := isOld.Meta["schema_version"]; exists { if raw, exists := isOld.Meta["schema_version"]; exists {
if rawStr, ok := raw.(string); ok { switch tv := raw.(type) {
v, err := strconv.ParseUint(rawStr, 10, 64) case string:
v, err := strconv.ParseUint(tv, 10, 64)
if err == nil { if err == nil {
schemaVersion = v schemaVersion = v
migratedSchemaVersion = true migratedSchemaVersion = true
} }
case int:
schemaVersion = uint64(tv)
migratedSchemaVersion = true
case float64:
schemaVersion = uint64(tv)
migratedSchemaVersion = true
} }
} }

View File

@ -7,7 +7,6 @@ import (
"sort" "sort"
version "github.com/hashicorp/go-version" version "github.com/hashicorp/go-version"
"github.com/zclconf/go-cty/cty"
ctyjson "github.com/zclconf/go-cty/cty/json" ctyjson "github.com/zclconf/go-cty/cty/json"
"github.com/hashicorp/terraform/addrs" "github.com/hashicorp/terraform/addrs"
@ -178,28 +177,7 @@ func prepareStateV4(sV4 *stateV4) (*File, tfdiags.Diagnostics) {
} }
if raw := isV4.PrivateRaw; len(raw) > 0 { if raw := isV4.PrivateRaw; len(raw) > 0 {
// Private metadata obj.Private = raw
ty, err := ctyjson.ImpliedType(raw)
if err != nil {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Invalid resource instance metadata in state",
fmt.Sprintf("Instance %s has invalid private metadata: %s.", instAddr.Absolute(moduleAddr), err),
))
continue
}
val, err := ctyjson.Unmarshal(raw, ty)
if err != nil {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Invalid resource instance metadata in state",
fmt.Sprintf("Instance %s has invalid private metadata: %s.", instAddr.Absolute(moduleAddr), err),
))
continue
}
obj.Private = val
} }
{ {
@ -475,17 +453,9 @@ func appendInstanceObjectStateV4(rs *states.Resource, is *states.ResourceInstanc
)) ))
} }
var privateRaw json.RawMessage var privateRaw []byte
if obj.Private != cty.NilVal { if len(obj.Private) > 0 {
var err error privateRaw = obj.Private
privateRaw, err = ctyjson.Marshal(obj.Private, obj.Private.Type())
if err != nil {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Failed to serialize resource instance in state",
fmt.Sprintf("Failed to serialize instance %s private metadata: %s.", rs.Addr.Instance(key), err),
))
}
} }
deps := make([]string, len(obj.Dependencies)) deps := make([]string, len(obj.Dependencies))
@ -565,7 +535,7 @@ type instanceObjectStateV4 struct {
AttributesRaw json.RawMessage `json:"attributes,omitempty"` AttributesRaw json.RawMessage `json:"attributes,omitempty"`
AttributesFlat map[string]string `json:"attributes_flat,omitempty"` AttributesFlat map[string]string `json:"attributes_flat,omitempty"`
PrivateRaw json.RawMessage `json:"private,omitempty"` PrivateRaw []byte `json:"private,omitempty"`
Dependencies []string `json:"depends_on,omitempty"` Dependencies []string `json:"depends_on,omitempty"`
} }