github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/states/statefile/version2.go (about) 1 package statefile 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "sync" 7 8 "github.com/hashicorp/terraform/tfdiags" 9 ) 10 11 func readStateV2(src []byte) (*File, tfdiags.Diagnostics) { 12 var diags tfdiags.Diagnostics 13 sV2 := &stateV2{} 14 err := json.Unmarshal(src, sV2) 15 if err != nil { 16 diags = diags.Append(jsonUnmarshalDiags(err)) 17 return nil, diags 18 } 19 20 file, prepDiags := prepareStateV2(sV2) 21 diags = diags.Append(prepDiags) 22 return file, diags 23 } 24 25 func prepareStateV2(sV2 *stateV2) (*File, tfdiags.Diagnostics) { 26 var diags tfdiags.Diagnostics 27 sV3, err := upgradeStateV2ToV3(sV2) 28 if err != nil { 29 diags = diags.Append(tfdiags.Sourceless( 30 tfdiags.Error, 31 upgradeFailed, 32 fmt.Sprintf("Error upgrading state file format from version 2 to version 3: %s.", err), 33 )) 34 return nil, diags 35 } 36 37 file, prepDiags := prepareStateV3(sV3) 38 diags = diags.Append(prepDiags) 39 return file, diags 40 } 41 42 // stateV2 is a representation of the legacy JSON state format version 2. 43 // 44 // It is only used to read version 2 JSON files prior to upgrading them to 45 // the current format. 46 type stateV2 struct { 47 // Version is the state file protocol version. 48 Version int `json:"version"` 49 50 // TFVersion is the version of Terraform that wrote this state. 51 TFVersion string `json:"terraform_version,omitempty"` 52 53 // Serial is incremented on any operation that modifies 54 // the State file. It is used to detect potentially conflicting 55 // updates. 56 Serial int64 `json:"serial"` 57 58 // Lineage is set when a new, blank state is created and then 59 // never updated. This allows us to determine whether the serials 60 // of two states can be meaningfully compared. 61 // Apart from the guarantee that collisions between two lineages 62 // are very unlikely, this value is opaque and external callers 63 // should only compare lineage strings byte-for-byte for equality. 64 Lineage string `json:"lineage"` 65 66 // Remote is used to track the metadata required to 67 // pull and push state files from a remote storage endpoint. 68 Remote *remoteStateV2 `json:"remote,omitempty"` 69 70 // Backend tracks the configuration for the backend in use with 71 // this state. This is used to track any changes in the backend 72 // configuration. 73 Backend *backendStateV2 `json:"backend,omitempty"` 74 75 // Modules contains all the modules in a breadth-first order 76 Modules []*moduleStateV2 `json:"modules"` 77 } 78 79 type remoteStateV2 struct { 80 // Type controls the client we use for the remote state 81 Type string `json:"type"` 82 83 // Config is used to store arbitrary configuration that 84 // is type specific 85 Config map[string]string `json:"config"` 86 } 87 88 type outputStateV2 struct { 89 // Sensitive describes whether the output is considered sensitive, 90 // which may lead to masking the value on screen in some cases. 91 Sensitive bool `json:"sensitive"` 92 // Type describes the structure of Value. Valid values are "string", 93 // "map" and "list" 94 Type string `json:"type"` 95 // Value contains the value of the output, in the structure described 96 // by the Type field. 97 Value interface{} `json:"value"` 98 99 mu sync.Mutex 100 } 101 102 type moduleStateV2 struct { 103 // Path is the import path from the root module. Modules imports are 104 // always disjoint, so the path represents amodule tree 105 Path []string `json:"path"` 106 107 // Locals are kept only transiently in-memory, because we can always 108 // re-compute them. 109 Locals map[string]interface{} `json:"-"` 110 111 // Outputs declared by the module and maintained for each module 112 // even though only the root module technically needs to be kept. 113 // This allows operators to inspect values at the boundaries. 114 Outputs map[string]*outputStateV2 `json:"outputs"` 115 116 // Resources is a mapping of the logically named resource to 117 // the state of the resource. Each resource may actually have 118 // N instances underneath, although a user only needs to think 119 // about the 1:1 case. 120 Resources map[string]*resourceStateV2 `json:"resources"` 121 122 // Dependencies are a list of things that this module relies on 123 // existing to remain intact. For example: an module may depend 124 // on a VPC ID given by an aws_vpc resource. 125 // 126 // Terraform uses this information to build valid destruction 127 // orders and to warn the user if they're destroying a module that 128 // another resource depends on. 129 // 130 // Things can be put into this list that may not be managed by 131 // Terraform. If Terraform doesn't find a matching ID in the 132 // overall state, then it assumes it isn't managed and doesn't 133 // worry about it. 134 Dependencies []string `json:"depends_on"` 135 } 136 137 type resourceStateV2 struct { 138 // This is filled in and managed by Terraform, and is the resource 139 // type itself such as "mycloud_instance". If a resource provider sets 140 // this value, it won't be persisted. 141 Type string `json:"type"` 142 143 // Dependencies are a list of things that this resource relies on 144 // existing to remain intact. For example: an AWS instance might 145 // depend on a subnet (which itself might depend on a VPC, and so 146 // on). 147 // 148 // Terraform uses this information to build valid destruction 149 // orders and to warn the user if they're destroying a resource that 150 // another resource depends on. 151 // 152 // Things can be put into this list that may not be managed by 153 // Terraform. If Terraform doesn't find a matching ID in the 154 // overall state, then it assumes it isn't managed and doesn't 155 // worry about it. 156 Dependencies []string `json:"depends_on"` 157 158 // Primary is the current active instance for this resource. 159 // It can be replaced but only after a successful creation. 160 // This is the instances on which providers will act. 161 Primary *instanceStateV2 `json:"primary"` 162 163 // Deposed is used in the mechanics of CreateBeforeDestroy: the existing 164 // Primary is Deposed to get it out of the way for the replacement Primary to 165 // be created by Apply. If the replacement Primary creates successfully, the 166 // Deposed instance is cleaned up. 167 // 168 // If there were problems creating the replacement Primary, the Deposed 169 // instance and the (now tainted) replacement Primary will be swapped so the 170 // tainted replacement will be cleaned up instead. 171 // 172 // An instance will remain in the Deposed list until it is successfully 173 // destroyed and purged. 174 Deposed []*instanceStateV2 `json:"deposed"` 175 176 // Provider is used when a resource is connected to a provider with an alias. 177 // If this string is empty, the resource is connected to the default provider, 178 // e.g. "aws_instance" goes with the "aws" provider. 179 // If the resource block contained a "provider" key, that value will be set here. 180 Provider string `json:"provider"` 181 182 mu sync.Mutex 183 } 184 185 type instanceStateV2 struct { 186 // A unique ID for this resource. This is opaque to Terraform 187 // and is only meant as a lookup mechanism for the providers. 188 ID string `json:"id"` 189 190 // Attributes are basic information about the resource. Any keys here 191 // are accessible in variable format within Terraform configurations: 192 // ${resourcetype.name.attribute}. 193 Attributes map[string]string `json:"attributes"` 194 195 // Meta is a simple K/V map that is persisted to the State but otherwise 196 // ignored by Terraform core. It's meant to be used for accounting by 197 // external client code. The value here must only contain Go primitives 198 // and collections. 199 Meta map[string]interface{} `json:"meta"` 200 201 // Tainted is used to mark a resource for recreation. 202 Tainted bool `json:"tainted"` 203 } 204 205 type backendStateV2 struct { 206 Type string `json:"type"` // Backend type 207 ConfigRaw json.RawMessage `json:"config"` // Backend raw config 208 Hash uint64 `json:"hash"` // Hash of portion of configuration from config files 209 }