]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/terraform/eval_state_upgrade.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / terraform / eval_state_upgrade.go
1 package terraform
2
3 import (
4 "fmt"
5 "log"
6
7 "github.com/hashicorp/terraform/addrs"
8 "github.com/hashicorp/terraform/configs/configschema"
9 "github.com/hashicorp/terraform/providers"
10 "github.com/hashicorp/terraform/states"
11 "github.com/hashicorp/terraform/tfdiags"
12 )
13
14 // UpgradeResourceState will, if necessary, run the provider-defined upgrade
15 // logic against the given state object to make it compliant with the
16 // current schema version. This is a no-op if the given state object is
17 // already at the latest version.
18 //
19 // If any errors occur during upgrade, error diagnostics are returned. In that
20 // case it is not safe to proceed with using the original state object.
21 func UpgradeResourceState(addr addrs.AbsResourceInstance, provider providers.Interface, src *states.ResourceInstanceObjectSrc, currentSchema *configschema.Block, currentVersion uint64) (*states.ResourceInstanceObjectSrc, tfdiags.Diagnostics) {
22 if addr.Resource.Resource.Mode != addrs.ManagedResourceMode {
23 // We only do state upgrading for managed resources.
24 return src, nil
25 }
26
27 stateIsFlatmap := len(src.AttrsJSON) == 0
28
29 providerType := addr.Resource.Resource.DefaultProviderConfig().Type
30 if src.SchemaVersion > currentVersion {
31 log.Printf("[TRACE] UpgradeResourceState: can't downgrade state for %s from version %d to %d", addr, src.SchemaVersion, currentVersion)
32 var diags tfdiags.Diagnostics
33 diags = diags.Append(tfdiags.Sourceless(
34 tfdiags.Error,
35 "Resource instance managed by newer provider version",
36 // This is not a very good error message, but we don't retain enough
37 // information in state to give good feedback on what provider
38 // version might be required here. :(
39 fmt.Sprintf("The current state of %s was created by a newer provider version than is currently selected. Upgrade the %s provider to work with this state.", addr, providerType),
40 ))
41 return nil, diags
42 }
43
44 // If we get down here then we need to upgrade the state, with the
45 // provider's help.
46 // If this state was originally created by a version of Terraform prior to
47 // v0.12, this also includes translating from legacy flatmap to new-style
48 // representation, since only the provider has enough information to
49 // understand a flatmap built against an older schema.
50 if src.SchemaVersion != currentVersion {
51 log.Printf("[TRACE] UpgradeResourceState: upgrading state for %s from version %d to %d using provider %q", addr, src.SchemaVersion, currentVersion, providerType)
52 } else {
53 log.Printf("[TRACE] UpgradeResourceState: schema version of %s is still %d; calling provider %q for any other minor fixups", addr, currentVersion, providerType)
54 }
55
56 req := providers.UpgradeResourceStateRequest{
57 TypeName: addr.Resource.Resource.Type,
58
59 // TODO: The internal schema version representations are all using
60 // uint64 instead of int64, but unsigned integers aren't friendly
61 // to all protobuf target languages so in practice we use int64
62 // on the wire. In future we will change all of our internal
63 // representations to int64 too.
64 Version: int64(src.SchemaVersion),
65 }
66
67 if stateIsFlatmap {
68 req.RawStateFlatmap = src.AttrsFlat
69 } else {
70 req.RawStateJSON = src.AttrsJSON
71 }
72
73 resp := provider.UpgradeResourceState(req)
74 diags := resp.Diagnostics
75 if diags.HasErrors() {
76 return nil, diags
77 }
78
79 // After upgrading, the new value must conform to the current schema. When
80 // going over RPC this is actually already ensured by the
81 // marshaling/unmarshaling of the new value, but we'll check it here
82 // anyway for robustness, e.g. for in-process providers.
83 newValue := resp.UpgradedState
84 if errs := newValue.Type().TestConformance(currentSchema.ImpliedType()); len(errs) > 0 {
85 for _, err := range errs {
86 diags = diags.Append(tfdiags.Sourceless(
87 tfdiags.Error,
88 "Invalid resource state upgrade",
89 fmt.Sprintf("The %s provider upgraded the state for %s from a previous version, but produced an invalid result: %s.", providerType, addr, tfdiags.FormatError(err)),
90 ))
91 }
92 return nil, diags
93 }
94
95 new, err := src.CompleteUpgrade(newValue, currentSchema.ImpliedType(), uint64(currentVersion))
96 if err != nil {
97 // We already checked for type conformance above, so getting into this
98 // codepath should be rare and is probably a bug somewhere under CompleteUpgrade.
99 diags = diags.Append(tfdiags.Sourceless(
100 tfdiags.Error,
101 "Failed to encode result of resource state upgrade",
102 fmt.Sprintf("Failed to encode state for %s after resource schema upgrade: %s.", addr, tfdiags.FormatError(err)),
103 ))
104 }
105 return new, diags
106 }