helper/plugin: Allow missing MigrateState for provider flatmap state upgrades

Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/8828

Prior to Terraform 0.12, providers were not required to implement the `MigrateState` function when increasing the `SchemaVersion` above `0`. Effectively there is no flatmap state difference between version 0 and defined `SchemaVersion` or lowest `StateUpgrader` `Version` (whichever is lowest) when `MigrateState` is undefined, so here we remove the error and increase the schema version automatically.
This commit is contained in:
Brian Flad 2019-06-05 23:23:45 -04:00
parent e71e3d85a9
commit 94078f9029
No known key found for this signature in database
GPG Key ID: EC6252B42B012823
2 changed files with 88 additions and 5 deletions

View File

@ -2,7 +2,6 @@ package plugin
import (
"encoding/json"
"errors"
"fmt"
"log"
"strconv"
@ -316,11 +315,15 @@ func (s *GRPCProviderServer) upgradeFlatmapState(version int, m map[string]strin
requiresMigrate = version < res.StateUpgraders[0].Version
}
if requiresMigrate {
if res.MigrateState == nil {
return nil, 0, errors.New("cannot upgrade state, missing MigrateState function")
if requiresMigrate && res.MigrateState == nil {
// Providers were previously allowed to bump the version
// without declaring MigrateState.
// If there are further upgraders, then we've only updated that far.
if len(res.StateUpgraders) > 0 {
schemaType = res.StateUpgraders[0].Type
upgradedVersion = res.StateUpgraders[0].Version
}
} else if requiresMigrate {
is := &terraform.InstanceState{
ID: m["id"],
Attributes: m,

View File

@ -437,6 +437,86 @@ func TestUpgradeState_flatmapState(t *testing.T) {
}
}
func TestUpgradeState_flatmapStateMissingMigrateState(t *testing.T) {
r := &schema.Resource{
SchemaVersion: 1,
Schema: map[string]*schema.Schema{
"one": {
Type: schema.TypeInt,
Required: true,
},
},
}
server := &GRPCProviderServer{
provider: &schema.Provider{
ResourcesMap: map[string]*schema.Resource{
"test": r,
},
},
}
testReqs := []*proto.UpgradeResourceState_Request{
{
TypeName: "test",
Version: 0,
RawState: &proto.RawState{
Flatmap: map[string]string{
"id": "bar",
"one": "1",
},
},
},
{
TypeName: "test",
Version: 1,
RawState: &proto.RawState{
Flatmap: map[string]string{
"id": "bar",
"one": "1",
},
},
},
{
TypeName: "test",
Version: 1,
RawState: &proto.RawState{
Json: []byte(`{"id":"bar","one":1}`),
},
},
}
for i, req := range testReqs {
t.Run(fmt.Sprintf("%d-%d", i, req.Version), func(t *testing.T) {
resp, err := server.UpgradeResourceState(nil, req)
if err != nil {
t.Fatal(err)
}
if len(resp.Diagnostics) > 0 {
for _, d := range resp.Diagnostics {
t.Errorf("%#v", d)
}
t.Fatal("error")
}
val, err := msgpack.Unmarshal(resp.UpgradedState.Msgpack, r.CoreConfigSchema().ImpliedType())
if err != nil {
t.Fatal(err)
}
expected := cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("bar"),
"one": cty.NumberIntVal(1),
})
if !cmp.Equal(expected, val, valueComparer, equateEmpty) {
t.Fatal(cmp.Diff(expected, val, valueComparer, equateEmpty))
}
})
}
}
func TestPlanResourceChange(t *testing.T) {
r := &schema.Resource{
SchemaVersion: 4,