1package states 2 3import ( 4 "github.com/zclconf/go-cty/cty" 5 ctyjson "github.com/zclconf/go-cty/cty/json" 6 7 "github.com/hashicorp/terraform/internal/addrs" 8) 9 10// ResourceInstanceObject is the local representation of a specific remote 11// object associated with a resource instance. In practice not all remote 12// objects are actually remote in the sense of being accessed over the network, 13// but this is the most common case. 14// 15// It is not valid to mutate a ResourceInstanceObject once it has been created. 16// Instead, create a new object and replace the existing one. 17type ResourceInstanceObject struct { 18 // Value is the object-typed value representing the remote object within 19 // Terraform. 20 Value cty.Value 21 22 // Private is an opaque value set by the provider when this object was 23 // last created or updated. Terraform Core does not use this value in 24 // any way and it is not exposed anywhere in the user interface, so 25 // a provider can use it for retaining any necessary private state. 26 Private []byte 27 28 // Status represents the "readiness" of the object as of the last time 29 // it was updated. 30 Status ObjectStatus 31 32 // Dependencies is a set of absolute address to other resources this 33 // instance dependeded on when it was applied. This is used to construct 34 // the dependency relationships for an object whose configuration is no 35 // longer available, such as if it has been removed from configuration 36 // altogether, or is now deposed. 37 Dependencies []addrs.ConfigResource 38 39 // CreateBeforeDestroy reflects the status of the lifecycle 40 // create_before_destroy option when this instance was last updated. 41 // Because create_before_destroy also effects the overall ordering of the 42 // destroy operations, we need to record the status to ensure a resource 43 // removed from the config will still be destroyed in the same manner. 44 CreateBeforeDestroy bool 45} 46 47// ObjectStatus represents the status of a RemoteObject. 48type ObjectStatus rune 49 50//go:generate go run golang.org/x/tools/cmd/stringer -type ObjectStatus 51 52const ( 53 // ObjectReady is an object status for an object that is ready to use. 54 ObjectReady ObjectStatus = 'R' 55 56 // ObjectTainted is an object status representing an object that is in 57 // an unrecoverable bad state due to a partial failure during a create, 58 // update, or delete operation. Since it cannot be moved into the 59 // ObjectRead state, a tainted object must be replaced. 60 ObjectTainted ObjectStatus = 'T' 61 62 // ObjectPlanned is a special object status used only for the transient 63 // placeholder objects we place into state during the refresh and plan 64 // walks to stand in for objects that will be created during apply. 65 // 66 // Any object of this status must have a corresponding change recorded 67 // in the current plan, whose value must then be used in preference to 68 // the value stored in state when evaluating expressions. A planned 69 // object stored in state will be incomplete if any of its attributes are 70 // not yet known, and the plan must be consulted in order to "see" those 71 // unknown values, because the state is not able to represent them. 72 ObjectPlanned ObjectStatus = 'P' 73) 74 75// Encode marshals the value within the receiver to produce a 76// ResourceInstanceObjectSrc ready to be written to a state file. 77// 78// The given type must be the implied type of the resource type schema, and 79// the given value must conform to it. It is important to pass the schema 80// type and not the object's own type so that dynamically-typed attributes 81// will be stored correctly. The caller must also provide the version number 82// of the schema that the given type was derived from, which will be recorded 83// in the source object so it can be used to detect when schema migration is 84// required on read. 85// 86// The returned object may share internal references with the receiver and 87// so the caller must not mutate the receiver any further once once this 88// method is called. 89func (o *ResourceInstanceObject) Encode(ty cty.Type, schemaVersion uint64) (*ResourceInstanceObjectSrc, error) { 90 // If it contains marks, remove these marks before traversing the 91 // structure with UnknownAsNull, and save the PathValueMarks 92 // so we can save them in state. 93 val, pvm := o.Value.UnmarkDeepWithPaths() 94 95 // Our state serialization can't represent unknown values, so we convert 96 // them to nulls here. This is lossy, but nobody should be writing unknown 97 // values here and expecting to get them out again later. 98 // 99 // We get unknown values here while we're building out a "planned state" 100 // during the plan phase, but the value stored in the plan takes precedence 101 // for expression evaluation. The apply step should never produce unknown 102 // values, but if it does it's the responsibility of the caller to detect 103 // and raise an error about that. 104 val = cty.UnknownAsNull(val) 105 106 src, err := ctyjson.Marshal(val, ty) 107 if err != nil { 108 return nil, err 109 } 110 111 return &ResourceInstanceObjectSrc{ 112 SchemaVersion: schemaVersion, 113 AttrsJSON: src, 114 AttrSensitivePaths: pvm, 115 Private: o.Private, 116 Status: o.Status, 117 Dependencies: o.Dependencies, 118 CreateBeforeDestroy: o.CreateBeforeDestroy, 119 }, nil 120} 121 122// AsTainted returns a deep copy of the receiver with the status updated to 123// ObjectTainted. 124func (o *ResourceInstanceObject) AsTainted() *ResourceInstanceObject { 125 if o == nil { 126 // A nil object can't be tainted, but we'll allow this anyway to 127 // avoid a crash, since we presumably intend to eventually record 128 // the object has having been deleted anyway. 129 return nil 130 } 131 ret := o.DeepCopy() 132 ret.Status = ObjectTainted 133 return ret 134} 135