github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/states/statefile/version2.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package statefile
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  
    10  	"github.com/terramate-io/tf/tfdiags"
    11  )
    12  
    13  func readStateV2(src []byte) (*File, tfdiags.Diagnostics) {
    14  	var diags tfdiags.Diagnostics
    15  	sV2 := &stateV2{}
    16  	err := json.Unmarshal(src, sV2)
    17  	if err != nil {
    18  		diags = diags.Append(jsonUnmarshalDiags(err))
    19  		return nil, diags
    20  	}
    21  
    22  	file, prepDiags := prepareStateV2(sV2)
    23  	diags = diags.Append(prepDiags)
    24  	return file, diags
    25  }
    26  
    27  func prepareStateV2(sV2 *stateV2) (*File, tfdiags.Diagnostics) {
    28  	var diags tfdiags.Diagnostics
    29  	sV3, err := upgradeStateV2ToV3(sV2)
    30  	if err != nil {
    31  		diags = diags.Append(tfdiags.Sourceless(
    32  			tfdiags.Error,
    33  			upgradeFailed,
    34  			fmt.Sprintf("Error upgrading state file format from version 2 to version 3: %s.", err),
    35  		))
    36  		return nil, diags
    37  	}
    38  
    39  	file, prepDiags := prepareStateV3(sV3)
    40  	diags = diags.Append(prepDiags)
    41  	return file, diags
    42  }
    43  
    44  // stateV2 is a representation of the legacy JSON state format version 2.
    45  //
    46  // It is only used to read version 2 JSON files prior to upgrading them to
    47  // the current format.
    48  type stateV2 struct {
    49  	// Version is the state file protocol version.
    50  	Version int `json:"version"`
    51  
    52  	// TFVersion is the version of Terraform that wrote this state.
    53  	TFVersion string `json:"terraform_version,omitempty"`
    54  
    55  	// Serial is incremented on any operation that modifies
    56  	// the State file. It is used to detect potentially conflicting
    57  	// updates.
    58  	Serial int64 `json:"serial"`
    59  
    60  	// Lineage is set when a new, blank state is created and then
    61  	// never updated. This allows us to determine whether the serials
    62  	// of two states can be meaningfully compared.
    63  	// Apart from the guarantee that collisions between two lineages
    64  	// are very unlikely, this value is opaque and external callers
    65  	// should only compare lineage strings byte-for-byte for equality.
    66  	Lineage string `json:"lineage"`
    67  
    68  	// Remote is used to track the metadata required to
    69  	// pull and push state files from a remote storage endpoint.
    70  	Remote *remoteStateV2 `json:"remote,omitempty"`
    71  
    72  	// Backend tracks the configuration for the backend in use with
    73  	// this state. This is used to track any changes in the backend
    74  	// configuration.
    75  	Backend *backendStateV2 `json:"backend,omitempty"`
    76  
    77  	// Modules contains all the modules in a breadth-first order
    78  	Modules []*moduleStateV2 `json:"modules"`
    79  }
    80  
    81  type remoteStateV2 struct {
    82  	// Type controls the client we use for the remote state
    83  	Type string `json:"type"`
    84  
    85  	// Config is used to store arbitrary configuration that
    86  	// is type specific
    87  	Config map[string]string `json:"config"`
    88  }
    89  
    90  type outputStateV2 struct {
    91  	// Sensitive describes whether the output is considered sensitive,
    92  	// which may lead to masking the value on screen in some cases.
    93  	Sensitive bool `json:"sensitive"`
    94  	// Type describes the structure of Value. Valid values are "string",
    95  	// "map" and "list"
    96  	Type string `json:"type"`
    97  	// Value contains the value of the output, in the structure described
    98  	// by the Type field.
    99  	Value interface{} `json:"value"`
   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  
   183  type instanceStateV2 struct {
   184  	// A unique ID for this resource. This is opaque to Terraform
   185  	// and is only meant as a lookup mechanism for the providers.
   186  	ID string `json:"id"`
   187  
   188  	// Attributes are basic information about the resource. Any keys here
   189  	// are accessible in variable format within Terraform configurations:
   190  	// ${resourcetype.name.attribute}.
   191  	Attributes map[string]string `json:"attributes"`
   192  
   193  	// Meta is a simple K/V map that is persisted to the State but otherwise
   194  	// ignored by Terraform core. It's meant to be used for accounting by
   195  	// external client code. The value here must only contain Go primitives
   196  	// and collections.
   197  	Meta map[string]interface{} `json:"meta"`
   198  
   199  	// Tainted is used to mark a resource for recreation.
   200  	Tainted bool `json:"tainted"`
   201  }
   202  
   203  type backendStateV2 struct {
   204  	Type      string          `json:"type"`   // Backend type
   205  	ConfigRaw json.RawMessage `json:"config"` // Backend raw config
   206  	Hash      uint64          `json:"hash"`   // Hash of portion of configuration from config files
   207  }