Skip to content

Commit 49cd416

Browse files
committed
feat(state_upgarder) refactor state upgrader for dns_record, page_rule
and load_balancer_pool
1 parent f765ef9 commit 49cd416

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+3742
-1188
lines changed

.github/workflows/migration-tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ env:
2828
CLOUDFLARE_HYPERDRIVE_DATABASE_HOSTNAME: ${{ secrets.CLOUDFLARE_HYPERDRIVE_DATABASE_HOSTNAME }}
2929
TF_ACC: 1
3030
TF_MIGRATE_BINARY_PATH: ${{ github.workspace }}/tf-migrate
31+
TF_MIG_TEST: true
3132

3233
jobs:
3334
migration-tests:

internal/acctest/acctest.go

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -917,25 +917,6 @@ func RunMigrationV2Command(t *testing.T, v4Config string, tmpDir string, sourceV
917917
t.Fatalf("tf-migrate binary not found at %s. Please set TF_MIGRATE_BINARY_PATH or ensure the binary is built.", migratorPath)
918918
}
919919

920-
// TODO:: Needs to be commented so the state upgraders run
921-
// Find state file in tmpDir
922-
//entries, err := os.ReadDir(tmpDir)
923-
//var stateDir string
924-
//if err != nil {
925-
// t.Logf("Failed to read test directory: %v", err)
926-
//} else {
927-
//for _, entry := range entries {
928-
// if entry.IsDir() {
929-
// inner_entries, _ := os.ReadDir(filepath.Join(tmpDir, entry.Name()))
930-
// for _, inner_entry := range inner_entries {
931-
// if inner_entry.Name() == "terraform.tfstate" {
932-
// stateDir = filepath.Join(tmpDir, entry.Name())
933-
// }
934-
// }
935-
// }
936-
//}
937-
//}
938-
939920
// Build the command
940921
args := []string{
941922
"migrate",
@@ -944,11 +925,6 @@ func RunMigrationV2Command(t *testing.T, v4Config string, tmpDir string, sourceV
944925
"--target-version", targetVersion,
945926
}
946927

947-
// Add state file argument if found
948-
//if stateDir != "" {
949-
// args = append(args, "--state-file", filepath.Join(stateDir, "terraform.tfstate"))
950-
//}
951-
952928
// Add debug logging if TF_LOG is set
953929
if strings.ToLower(os.Getenv("TF_LOG")) == "debug" {
954930
args = append(args, "--log-level", "debug")
@@ -1022,8 +998,8 @@ func RunMigrationCommand(t *testing.T, v4Config string, tmpDir string) {
1022998
cmd = exec.Command("go", "run", "-C", migratePath, ".",
1023999
"-config", tmpDir,
10241000
"-state", filepath.Join(stateDir, "terraform.tfstate"),
1025-
"-grit=false", // Disable Grit transformations
1026-
"-transformer=true", // Enable YAML transformations
1001+
"-grit=false", // Disable Grit transformations
1002+
"-transformer=true", // Enable YAML transformations
10271003
"-transformer-dir", transformerDir) // Use local YAML configs
10281004
cmd.Dir = tmpDir
10291005
// Capture output for debugging
@@ -1071,6 +1047,16 @@ func MigrationTestStepWithPlan(t *testing.T, v4Config string, tmpDir string, exa
10711047
return []resource.TestStep{migrationStep, planStep, validationStep}
10721048
}
10731049

1050+
// DetermineSourceTargetVersion determines the source and target versions for migration tests
1051+
// based on the test version being used. For v4 versions, returns "v4" -> "v5" migration.
1052+
// For v5 versions, returns "v5" -> "v5" which tests StateUpgrader idempotency only.
1053+
func DetermineSourceTargetVersion(version string) (source, target string) {
1054+
if strings.HasPrefix(version, "5.") {
1055+
return "v5", "v5"
1056+
}
1057+
return "v4", "v5"
1058+
}
1059+
10741060
// MigrationV2TestStepWithPlan creates multiple test steps for v2 migration with plan processing
10751061
// This is similar to MigrationTestStepWithPlan but uses the v2 migration command with explicit version parameters
10761062
func MigrationV2TestStepWithPlan(t *testing.T, v4Config string, tmpDir string, exactVersion string, sourceVersion string, targetVersion string, stateChecks []statecheck.StateCheck) []resource.TestStep {
@@ -1167,8 +1153,14 @@ func MigrationV2TestStep(t *testing.T, v4Config string, tmpDir string, exactVers
11671153
return resource.TestStep{
11681154
PreConfig: func() {
11691155
WriteOutConfig(t, v4Config, tmpDir)
1170-
debugLogf(t, "Running migration command for version: %s (%s -> %s)", exactVersion, sourceVersion, targetVersion)
1171-
RunMigrationV2Command(t, v4Config, tmpDir, sourceVersion, targetVersion)
1156+
// Only run migration command if source version is v4
1157+
// v5→v5 "migrations" only test StateUpgrader idempotency, no config changes needed
1158+
if sourceVersion == "v4" {
1159+
debugLogf(t, "Running migration command for version: %s (%s -> %s)", exactVersion, sourceVersion, targetVersion)
1160+
RunMigrationV2Command(t, v4Config, tmpDir, sourceVersion, targetVersion)
1161+
} else {
1162+
debugLogf(t, "Skipping migration command for version: %s (%s -> %s) - testing StateUpgrader only", exactVersion, sourceVersion, targetVersion)
1163+
}
11721164
},
11731165
ProtoV6ProviderFactories: TestAccProtoV6ProviderFactories,
11741166
ConfigDirectory: config.StaticDirectory(tmpDir),
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package v500
2+
3+
import (
4+
"context"
5+
6+
"github.com/hashicorp/terraform-plugin-framework/resource"
7+
"github.com/hashicorp/terraform-plugin-log/tflog"
8+
)
9+
10+
// UpgradeFromV0 handles state upgrades from earlier v500 versions (schema_version=0) to current v500.
11+
// This is a no-op upgrade since the schema is compatible - just copy state through.
12+
//
13+
// Why this exists: Terraform requires explicit upgraders to be defined for version tracking,
14+
// even when the schema is identical. This ensures the schema_version is updated in the statefile.
15+
func UpgradeFromV0(
16+
ctx context.Context,
17+
req resource.UpgradeStateRequest,
18+
resp *resource.UpgradeStateResponse,
19+
) {
20+
// No-op upgrade: schema is compatible, just copy raw state through
21+
// We use the raw state value directly to avoid issues with custom field type serialization
22+
resp.State.Raw = req.State.Raw
23+
}
24+
25+
// UpgradeFromV4 handles state upgrades from v5 releases with schema_version=4 to current v500.
26+
// This is a no-op upgrade since we only changed the version number from 4 to 500.
27+
// All v5.x.x releases up to 5.16.0 used schema_version=4 for cloudflare_dns_record.
28+
func UpgradeFromV4(
29+
ctx context.Context,
30+
req resource.UpgradeStateRequest,
31+
resp *resource.UpgradeStateResponse,
32+
) {
33+
tflog.Info(ctx, "Upgrading DNS record state from schema_version=4 to schema_version=500")
34+
// No-op upgrade: schema is identical, just copy raw state through
35+
// We use the raw state value directly to avoid issues with custom field type serialization
36+
resp.State.Raw = req.State.Raw
37+
}
38+
39+
// UpgradeFromLegacyV3 handles state upgrades from the legacy cloudflare_record resource to cloudflare_dns_record.
40+
// This is triggered when users manually run `terraform state mv cloudflare_record.x cloudflare_dns_record.x`
41+
// (Terraform < 1.8), which preserves the source schema_version=3 from the legacy provider.
42+
//
43+
// Note: schema_version=3 was the final schema version of cloudflare_record in the legacy (SDKv2) provider
44+
// before it was deprecated. The state structure matches SourceCloudflareRecordModel.
45+
func UpgradeFromLegacyV3(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) {
46+
tflog.Info(ctx, "Upgrading DNS record state from legacy cloudflare_record (schema_version=3)")
47+
48+
// Parse the state (schema_version=3, source resource type)
49+
var sourceState SourceCloudflareRecordModel
50+
resp.Diagnostics.Append(req.State.Get(ctx, &sourceState)...)
51+
if resp.Diagnostics.HasError() {
52+
return
53+
}
54+
55+
// Transform to target
56+
targetState, diags := Transform(ctx, sourceState)
57+
resp.Diagnostics.Append(diags...)
58+
if resp.Diagnostics.HasError() {
59+
return
60+
}
61+
62+
// Set the upgraded state
63+
resp.Diagnostics.Append(resp.State.Set(ctx, targetState)...)
64+
65+
tflog.Info(ctx, "State upgrade from legacy cloudflare_record completed successfully")
66+
}

0 commit comments

Comments
 (0)