github.com/opentofu/opentofu@v1.7.1/internal/states/statefile/version1.go (about)

     1  // Copyright (c) The OpenTofu Authors
     2  // SPDX-License-Identifier: MPL-2.0
     3  // Copyright (c) 2023 HashiCorp, Inc.
     4  // SPDX-License-Identifier: MPL-2.0
     5  
     6  package statefile
     7  
     8  import (
     9  	"encoding/json"
    10  	"fmt"
    11  
    12  	"github.com/opentofu/opentofu/internal/tfdiags"
    13  )
    14  
    15  func readStateV1(src []byte) (*File, tfdiags.Diagnostics) {
    16  	var diags tfdiags.Diagnostics
    17  	sV1 := &stateV1{}
    18  	err := json.Unmarshal(src, sV1)
    19  	if err != nil {
    20  		diags = diags.Append(jsonUnmarshalDiags(err))
    21  		return nil, diags
    22  	}
    23  
    24  	file, prepDiags := prepareStateV1(sV1)
    25  	diags = diags.Append(prepDiags)
    26  	return file, diags
    27  }
    28  
    29  func prepareStateV1(sV1 *stateV1) (*File, tfdiags.Diagnostics) {
    30  	var diags tfdiags.Diagnostics
    31  	sV2, err := upgradeStateV1ToV2(sV1)
    32  	if err != nil {
    33  		diags = diags.Append(tfdiags.Sourceless(
    34  			tfdiags.Error,
    35  			upgradeFailed,
    36  			fmt.Sprintf("Error upgrading state file format from version 1 to version 2: %s.", err),
    37  		))
    38  		return nil, diags
    39  	}
    40  
    41  	file, prepDiags := prepareStateV2(sV2)
    42  	diags = diags.Append(prepDiags)
    43  	return file, diags
    44  }
    45  
    46  // stateV1 is a representation of the legacy JSON state format version 1.
    47  //
    48  // It is only used to read version 1 JSON files prior to upgrading them to
    49  // the current format.
    50  type stateV1 struct {
    51  	// Version is the protocol version. "1" for a StateV1.
    52  	Version int `json:"version"`
    53  
    54  	// Serial is incremented on any operation that modifies
    55  	// the State file. It is used to detect potentially conflicting
    56  	// updates.
    57  	Serial int64 `json:"serial"`
    58  
    59  	// Remote is used to track the metadata required to
    60  	// pull and push state files from a remote storage endpoint.
    61  	Remote *remoteStateV1 `json:"remote,omitempty"`
    62  
    63  	// Modules contains all the modules in a breadth-first order
    64  	Modules []*moduleStateV1 `json:"modules"`
    65  }
    66  
    67  type remoteStateV1 struct {
    68  	// Type controls the client we use for the remote state
    69  	Type string `json:"type"`
    70  
    71  	// Config is used to store arbitrary configuration that
    72  	// is type specific
    73  	Config map[string]string `json:"config"`
    74  }
    75  
    76  type moduleStateV1 struct {
    77  	// Path is the import path from the root module. Modules imports are
    78  	// always disjoint, so the path represents amodule tree
    79  	Path []string `json:"path"`
    80  
    81  	// Outputs declared by the module and maintained for each module
    82  	// even though only the root module technically needs to be kept.
    83  	// This allows operators to inspect values at the boundaries.
    84  	Outputs map[string]string `json:"outputs"`
    85  
    86  	// Resources is a mapping of the logically named resource to
    87  	// the state of the resource. Each resource may actually have
    88  	// N instances underneath, although a user only needs to think
    89  	// about the 1:1 case.
    90  	Resources map[string]*resourceStateV1 `json:"resources"`
    91  
    92  	// Dependencies are a list of things that this module relies on
    93  	// existing to remain intact. For example: an module may depend
    94  	// on a VPC ID given by an aws_vpc resource.
    95  	//
    96  	// OpenTofu uses this information to build valid destruction
    97  	// orders and to warn the user if they're destroying a module that
    98  	// another resource depends on.
    99  	//
   100  	// Things can be put into this list that may not be managed by
   101  	// OpenTofu. If OpenTofu doesn't find a matching ID in the
   102  	// overall state, then it assumes it isn't managed and doesn't
   103  	// worry about it.
   104  	Dependencies []string `json:"depends_on,omitempty"`
   105  }
   106  
   107  type resourceStateV1 struct {
   108  	// This is filled in and managed by OpenTofu, and is the resource
   109  	// type itself such as "mycloud_instance". If a resource provider sets
   110  	// this value, it won't be persisted.
   111  	Type string `json:"type"`
   112  
   113  	// Dependencies are a list of things that this resource relies on
   114  	// existing to remain intact. For example: an AWS instance might
   115  	// depend on a subnet (which itself might depend on a VPC, and so
   116  	// on).
   117  	//
   118  	// OpenTofu uses this information to build valid destruction
   119  	// orders and to warn the user if they're destroying a resource that
   120  	// another resource depends on.
   121  	//
   122  	// Things can be put into this list that may not be managed by
   123  	// OpenTofu. If OpenTofu doesn't find a matching ID in the
   124  	// overall state, then it assumes it isn't managed and doesn't
   125  	// worry about it.
   126  	Dependencies []string `json:"depends_on,omitempty"`
   127  
   128  	// Primary is the current active instance for this resource.
   129  	// It can be replaced but only after a successful creation.
   130  	// This is the instances on which providers will act.
   131  	Primary *instanceStateV1 `json:"primary"`
   132  
   133  	// Tainted is used to track any underlying instances that
   134  	// have been created but are in a bad or unknown state and
   135  	// need to be cleaned up subsequently.  In the
   136  	// standard case, there is only at most a single instance.
   137  	// However, in pathological cases, it is possible for the number
   138  	// of instances to accumulate.
   139  	Tainted []*instanceStateV1 `json:"tainted,omitempty"`
   140  
   141  	// Deposed is used in the mechanics of CreateBeforeDestroy: the existing
   142  	// Primary is Deposed to get it out of the way for the replacement Primary to
   143  	// be created by Apply. If the replacement Primary creates successfully, the
   144  	// Deposed instance is cleaned up. If there were problems creating the
   145  	// replacement, the instance remains in the Deposed list so it can be
   146  	// destroyed in a future run. Functionally, Deposed instances are very
   147  	// similar to Tainted instances in that OpenTofu is only tracking them in
   148  	// order to remember to destroy them.
   149  	Deposed []*instanceStateV1 `json:"deposed,omitempty"`
   150  
   151  	// Provider is used when a resource is connected to a provider with an alias.
   152  	// If this string is empty, the resource is connected to the default provider,
   153  	// e.g. "aws_instance" goes with the "aws" provider.
   154  	// If the resource block contained a "provider" key, that value will be set here.
   155  	Provider string `json:"provider,omitempty"`
   156  }
   157  
   158  type instanceStateV1 struct {
   159  	// A unique ID for this resource. This is opaque to OpenTofu
   160  	// and is only meant as a lookup mechanism for the providers.
   161  	ID string `json:"id"`
   162  
   163  	// Attributes are basic information about the resource. Any keys here
   164  	// are accessible in variable format within OpenTofu configurations:
   165  	// ${resourcetype.name.attribute}.
   166  	Attributes map[string]string `json:"attributes,omitempty"`
   167  
   168  	// Meta is a simple K/V map that is persisted to the State but otherwise
   169  	// ignored by OpenTofu core. It's meant to be used for accounting by
   170  	// external client code.
   171  	Meta map[string]string `json:"meta,omitempty"`
   172  }