Skip to content

Commit

Permalink
fix: add migrate state function to avoid state issues when update the…
Browse files Browse the repository at this point in the history
… provider
  • Loading branch information
marinsalinas committed Apr 3, 2020
1 parent 14f36f1 commit 71424e5
Show file tree
Hide file tree
Showing 4 changed files with 221 additions and 0 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module github.com/terraform-providers/terraform-provider-nutanix

require (
github.com/gogo/protobuf v1.2.0
github.com/golang/protobuf v1.3.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/terraform v0.12.3
Expand Down
82 changes: 82 additions & 0 deletions nutanix/categories_schema_migrate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package nutanix

import (
"fmt"
"log"
"sort"
"strings"

"github.com/hashicorp/terraform/terraform"
)

func resourceNutanixCategoriesMigrateState(
v int, is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) {
switch v {
case 0:
log.Println("[INFO] Found Nutanix State v0; migrating to v1")
return migrateNutanixCategoriesV0toV1(is)
default:
return is, fmt.Errorf("Unexpected schema version: %d", v)
}
}

func migrateNutanixCategoriesV0toV1(is *terraform.InstanceState) (*terraform.InstanceState, error) {
if is.Empty() || is.Attributes == nil {
log.Println("[DEBUG] Empty InstanceState; nothing to migrate.")
return is, nil
}

keys := make([]string, 0, len(is.Attributes))
for k := range is.Attributes {
keys = append(keys, k)
}

sort.Strings(keys)

log.Printf("[DEBUG] Attributes before migration: %#v", is.Attributes)

if l, ok := is.Attributes["categories.%"]; ok && l != "" {
var tempCat []map[string]string

for _, k := range keys {
v := is.Attributes[k]

if k == "categories.%" {
is.Attributes["categories.#"] = v
delete(is.Attributes, "categories.%")
continue
}

if strings.HasPrefix(k, "categories.") {
path := strings.Split(k, ".")
if len(path) != 2 {
return is, fmt.Errorf("found unexpected categories field: %#v", k)
}

if path[1] == "#" {
continue
}

log.Printf("[DEBUG] key=%s", k)

tempCat = append(tempCat, map[string]string{
"name": path[1],
"value": v,
})

delete(is.Attributes, k)
}
}
flattenTempCategories(tempCat, is)
}
log.Printf("[DEBUG] Attributes after migration: %#v", is.Attributes)
return is, nil
}

func flattenTempCategories(categories []map[string]string, is *terraform.InstanceState) {
for index, category := range categories {
for key, value := range category {
is.Attributes[fmt.Sprintf("categories.%d.%s", index, key)] = value
}
}
}
131 changes: 131 additions & 0 deletions nutanix/categories_schema_migrate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package nutanix

import (
"testing"

"github.com/hashicorp/terraform/terraform"
)

func TestResourceNutanixCategoriesteUpgradeV0(t *testing.T) {
cases := map[string]struct {
StateVersion int
Attributes map[string]string
Expected map[string]string
Meta interface{}
}{
"v0_without_values": {
StateVersion: 0,
Attributes: map[string]string{
"categories.%": "0",
},
Expected: map[string]string{
"categories.#": "0",
},
},
"v0_with_values": {
StateVersion: 0,
Attributes: map[string]string{
"categories.%": "2",
"categories.os_type": "ubuntu",
"categories.os_version": "18.04",
},
Expected: map[string]string{
"categories.#": "2",
"categories.0.name": "os_type",
"categories.0.value": "ubuntu",
"categories.1.name": "os_version",
"categories.1.value": "18.04",
},
},
"v0_categories_not_set": {
StateVersion: 0,
Attributes: map[string]string{
"name": "test-name",
},
Expected: map[string]string{
"name": "test-name",
},
},
"v0_multiple_categories": {
StateVersion: 0,
Attributes: map[string]string{
"categories.%": "3",
"categories.os_type": "ubuntu",
"categories.os_version": "18.04",
"categories.tier": "application",
"categories.test": "test-value",
},
Expected: map[string]string{
"categories.#": "3",
"categories.0.name": "os_type",
"categories.0.value": "ubuntu",
"categories.1.name": "os_version",
"categories.1.value": "18.04",
"categories.2.name": "test",
"categories.2.value": "test-value",
"categories.3.name": "tier",
"categories.3.value": "application",
},
},
"v0_already_migrated": {
StateVersion: 0,
Attributes: map[string]string{
"categories.#": "3",
"categories.0.name": "os_type",
"categories.0.value": "ubuntu",
"categories.1.name": "os_version",
"categories.1.value": "18.04",
"categories.2.name": "tier",
"categories.2.value": "application",
},
Expected: map[string]string{
"categories.#": "3",
"categories.0.name": "os_type",
"categories.0.value": "ubuntu",
"categories.1.name": "os_version",
"categories.1.value": "18.04",
"categories.2.name": "tier",
"categories.2.value": "application",
},
},
"v0_empty_value": {
StateVersion: 0,
Attributes: map[string]string{
"categories.%": "3",
"categories.os_type": "",
"categories.os_version": "",
"categories.tier": "",
},
Expected: map[string]string{
"categories.#": "3",
"categories.0.name": "os_type",
"categories.0.value": "",
"categories.1.name": "os_version",
"categories.1.value": "",
"categories.2.name": "tier",
"categories.2.value": "",
},
},
}

for tn, tc := range cases {
is := &terraform.InstanceState{
ID: "i-abc123",
Attributes: tc.Attributes,
}
is, err := resourceNutanixCategoriesMigrateState(
tc.StateVersion, is, tc.Meta)

if err != nil {
t.Fatalf("bad: %s, err: %#v", tn, err)
}

for k, v := range tc.Expected {
if is.Attributes[k] != v {
t.Fatalf(
"bad: %s\n\n expected: %#v -> %#v\n got: %#v -> %#v\n in: %#v",
tn, k, v, k, is.Attributes[k], is.Attributes)
}
}
}
}
7 changes: 7 additions & 0 deletions nutanix/resource_nutanix_virtual_machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
"github.com/hashicorp/terraform/terraform"
)

var (
Expand All @@ -33,6 +34,8 @@ func resourceNutanixVirtualMachine() *schema.Resource {
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
SchemaVersion: 1,
MigrateState: resourceVirtualMachineInstanceStateUpgradeV0,
Schema: map[string]*schema.Schema{
"metadata": {
Type: schema.TypeMap,
Expand Down Expand Up @@ -1941,3 +1944,7 @@ func CountDiskListCdrom(dl []*v3.VMDisk) (int, error) {
}
return counter, nil
}

func resourceVirtualMachineInstanceStateUpgradeV0(v int, is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) {
return resourceNutanixCategoriesMigrateState(v, is, meta)
}

0 comments on commit 71424e5

Please sign in to comment.