github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/cloud/e2e/migrate_state_remote_backend_to_tfc_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package main 5 6 import ( 7 "context" 8 "testing" 9 10 tfe "github.com/hashicorp/go-tfe" 11 ) 12 13 func Test_migrate_remote_backend_single_org(t *testing.T) { 14 t.Parallel() 15 skipIfMissingEnvVar(t) 16 skipWithoutRemoteTerraformVersion(t) 17 18 ctx := context.Background() 19 cases := testCases{ 20 "migrate remote backend name to tfc name": { 21 operations: []operationSets{ 22 { 23 prep: func(t *testing.T, orgName, dir string) { 24 remoteWorkspace := "remote-workspace" 25 tfBlock := terraformConfigRemoteBackendName(orgName, remoteWorkspace) 26 writeMainTF(t, tfBlock, dir) 27 }, 28 commands: []tfCommand{ 29 { 30 command: []string{"init"}, 31 expectedCmdOutput: `Successfully configured the backend "remote"!`, 32 }, 33 { 34 command: []string{"apply", "-auto-approve"}, 35 expectedCmdOutput: `Apply complete!`, 36 }, 37 }, 38 }, 39 { 40 prep: func(t *testing.T, orgName, dir string) { 41 wsName := "cloud-workspace" 42 tfBlock := terraformConfigCloudBackendName(orgName, wsName) 43 writeMainTF(t, tfBlock, dir) 44 }, 45 commands: []tfCommand{ 46 { 47 command: []string{"init", "-ignore-remote-version"}, 48 expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, 49 userInput: []string{"yes", "yes"}, 50 postInputOutput: []string{ 51 `Should Terraform migrate your existing state?`, 52 `Terraform Cloud has been successfully initialized!`}, 53 }, 54 { 55 command: []string{"workspace", "show"}, 56 expectedCmdOutput: `cloud-workspace`, 57 }, 58 }, 59 }, 60 }, 61 validations: func(t *testing.T, orgName string) { 62 expectedName := "cloud-workspace" 63 ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) 64 if err != nil { 65 t.Fatal(err) 66 } 67 if ws == nil { 68 t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) 69 } 70 }, 71 }, 72 "migrate remote backend name to tfc same name": { 73 operations: []operationSets{ 74 { 75 prep: func(t *testing.T, orgName, dir string) { 76 remoteWorkspace := "remote-workspace" 77 tfBlock := terraformConfigRemoteBackendName(orgName, remoteWorkspace) 78 writeMainTF(t, tfBlock, dir) 79 }, 80 commands: []tfCommand{ 81 { 82 command: []string{"init"}, 83 expectedCmdOutput: `Successfully configured the backend "remote"!`, 84 }, 85 { 86 command: []string{"apply", "-auto-approve"}, 87 postInputOutput: []string{`Apply complete!`}, 88 }, 89 }, 90 }, 91 { 92 prep: func(t *testing.T, orgName, dir string) { 93 wsName := "remote-workspace" 94 tfBlock := terraformConfigCloudBackendName(orgName, wsName) 95 writeMainTF(t, tfBlock, dir) 96 }, 97 commands: []tfCommand{ 98 { 99 command: []string{"init", "-ignore-remote-version"}, 100 expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, 101 userInput: []string{"yes", "yes"}, 102 postInputOutput: []string{ 103 `Should Terraform migrate your existing state?`, 104 `Terraform Cloud has been successfully initialized!`}, 105 }, 106 { 107 command: []string{"workspace", "show"}, 108 expectedCmdOutput: `remote-workspace`, 109 }, 110 }, 111 }, 112 }, 113 validations: func(t *testing.T, orgName string) { 114 expectedName := "remote-workspace" 115 ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) 116 if err != nil { 117 t.Fatal(err) 118 } 119 if ws == nil { 120 t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) 121 } 122 }, 123 }, 124 "migrate remote backend name to tfc tags": { 125 operations: []operationSets{ 126 { 127 prep: func(t *testing.T, orgName, dir string) { 128 remoteWorkspace := "remote-workspace" 129 tfBlock := terraformConfigRemoteBackendName(orgName, remoteWorkspace) 130 writeMainTF(t, tfBlock, dir) 131 }, 132 commands: []tfCommand{ 133 { 134 command: []string{"init"}, 135 expectedCmdOutput: `Successfully configured the backend "remote"!`, 136 }, 137 { 138 command: []string{"apply", "-auto-approve"}, 139 postInputOutput: []string{`Apply complete!`}, 140 }, 141 { 142 command: []string{"workspace", "show"}, 143 expectedCmdOutput: `default`, 144 }, 145 }, 146 }, 147 { 148 prep: func(t *testing.T, orgName, dir string) { 149 tag := "app" 150 tfBlock := terraformConfigCloudBackendTags(orgName, tag) 151 writeMainTF(t, tfBlock, dir) 152 }, 153 commands: []tfCommand{ 154 { 155 command: []string{"init", "-ignore-remote-version"}, 156 expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, 157 userInput: []string{"yes", "cloud-workspace", "yes"}, 158 postInputOutput: []string{ 159 `Should Terraform migrate your existing state?`, 160 `Terraform Cloud requires all workspaces to be given an explicit name.`, 161 `Terraform Cloud has been successfully initialized!`}, 162 }, 163 { 164 command: []string{"workspace", "show"}, 165 expectedCmdOutput: `cloud-workspace`, 166 }, 167 }, 168 }, 169 }, 170 validations: func(t *testing.T, orgName string) { 171 wsList, err := tfeClient.Workspaces.List(ctx, orgName, &tfe.WorkspaceListOptions{ 172 Tags: "app", 173 }) 174 if err != nil { 175 t.Fatal(err) 176 } 177 if len(wsList.Items) != 1 { 178 t.Fatalf("Expected number of workspaces to be 1, but got %d", len(wsList.Items)) 179 } 180 ws := wsList.Items[0] 181 if ws.Name != "cloud-workspace" { 182 t.Fatalf("Expected workspace to be `cloud-workspace`, but is %s", ws.Name) 183 } 184 }, 185 }, 186 "migrate remote backend prefix to tfc name strategy single workspace": { 187 operations: []operationSets{ 188 { 189 prep: func(t *testing.T, orgName, dir string) { 190 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-one")}) 191 prefix := "app-" 192 tfBlock := terraformConfigRemoteBackendPrefix(orgName, prefix) 193 writeMainTF(t, tfBlock, dir) 194 }, 195 commands: []tfCommand{ 196 { 197 command: []string{"init"}, 198 expectedCmdOutput: `Terraform has been successfully initialized!`, 199 }, 200 { 201 command: []string{"apply", "-auto-approve"}, 202 postInputOutput: []string{`Apply complete!`}, 203 }, 204 }, 205 }, 206 { 207 prep: func(t *testing.T, orgName, dir string) { 208 wsName := "cloud-workspace" 209 tfBlock := terraformConfigCloudBackendName(orgName, wsName) 210 writeMainTF(t, tfBlock, dir) 211 }, 212 commands: []tfCommand{ 213 { 214 command: []string{"init", "-ignore-remote-version"}, 215 expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, 216 userInput: []string{"yes", "yes"}, 217 postInputOutput: []string{ 218 `Should Terraform migrate your existing state?`, 219 `Terraform Cloud has been successfully initialized!`}, 220 }, 221 { 222 command: []string{"workspace", "show"}, 223 expectedCmdOutput: `cloud-workspace`, 224 }, 225 }, 226 }, 227 }, 228 validations: func(t *testing.T, orgName string) { 229 expectedName := "cloud-workspace" 230 ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) 231 if err != nil { 232 t.Fatal(err) 233 } 234 if ws == nil { 235 t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) 236 } 237 }, 238 }, 239 "migrate remote backend prefix to tfc name strategy multi workspace": { 240 operations: []operationSets{ 241 { 242 prep: func(t *testing.T, orgName, dir string) { 243 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-one")}) 244 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-two")}) 245 prefix := "app-" 246 tfBlock := terraformConfigRemoteBackendPrefix(orgName, prefix) 247 writeMainTF(t, tfBlock, dir) 248 }, 249 commands: []tfCommand{ 250 { 251 command: []string{"init"}, 252 expectedCmdOutput: `The currently selected workspace (default) does not exist.`, 253 userInput: []string{"1"}, 254 postInputOutput: []string{`Terraform has been successfully initialized!`}, 255 }, 256 { 257 command: []string{"apply", "-auto-approve"}, 258 postInputOutput: []string{`Apply complete!`}, 259 }, 260 { 261 command: []string{"workspace", "list"}, 262 expectedCmdOutput: "* one", // app name retrieved via prefix 263 }, 264 { 265 command: []string{"workspace", "select", "two"}, 266 expectedCmdOutput: `Switched to workspace "two".`, // app name retrieved via prefix 267 }, 268 }, 269 }, 270 { 271 prep: func(t *testing.T, orgName, dir string) { 272 wsName := "cloud-workspace" 273 tfBlock := terraformConfigCloudBackendName(orgName, wsName) 274 writeMainTF(t, tfBlock, dir) 275 }, 276 commands: []tfCommand{ 277 { 278 command: []string{"init", "-ignore-remote-version"}, 279 expectedCmdOutput: `Do you want to copy only your current workspace?`, 280 userInput: []string{"yes"}, 281 postInputOutput: []string{ 282 `Terraform Cloud has been successfully initialized!`}, 283 }, 284 { 285 command: []string{"workspace", "show"}, 286 expectedCmdOutput: `cloud-workspace`, 287 }, 288 }, 289 }, 290 }, 291 validations: func(t *testing.T, orgName string) { 292 expectedName := "cloud-workspace" 293 ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) 294 if err != nil { 295 t.Fatal(err) 296 } 297 if ws == nil { 298 t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) 299 } 300 wsList, err := tfeClient.Workspaces.List(ctx, orgName, nil) 301 if err != nil { 302 t.Fatal(err) 303 } 304 if len(wsList.Items) != 3 { 305 t.Fatalf("expected number of workspaces in this org to be 3, but got %d", len(wsList.Items)) 306 } 307 _, empty := getWorkspace(wsList.Items, "cloud-workspace") 308 if empty { 309 t.Fatalf("expected workspaces to include 'cloud-workspace' but didn't.") 310 } 311 _, empty = getWorkspace(wsList.Items, "app-one") 312 if empty { 313 t.Fatalf("expected workspaces to include 'app-one' but didn't.") 314 } 315 _, empty = getWorkspace(wsList.Items, "app-two") 316 if empty { 317 t.Fatalf("expected workspaces to include 'app-two' but didn't.") 318 } 319 }, 320 }, 321 "migrate remote backend prefix to tfc tags strategy single workspace": { 322 operations: []operationSets{ 323 { 324 prep: func(t *testing.T, orgName, dir string) { 325 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-one")}) 326 prefix := "app-" 327 tfBlock := terraformConfigRemoteBackendPrefix(orgName, prefix) 328 writeMainTF(t, tfBlock, dir) 329 }, 330 commands: []tfCommand{ 331 { 332 command: []string{"init"}, 333 expectedCmdOutput: `Terraform has been successfully initialized!`, 334 }, 335 { 336 command: []string{"apply", "-auto-approve"}, 337 postInputOutput: []string{`Apply complete!`}, 338 }, 339 }, 340 }, 341 { 342 prep: func(t *testing.T, orgName, dir string) { 343 tag := "app" 344 tfBlock := terraformConfigCloudBackendTags(orgName, tag) 345 writeMainTF(t, tfBlock, dir) 346 }, 347 commands: []tfCommand{ 348 { 349 command: []string{"init", "-ignore-remote-version"}, 350 expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, 351 userInput: []string{"yes", "cloud-workspace", "yes"}, 352 postInputOutput: []string{ 353 `Should Terraform migrate your existing state?`, 354 `Terraform Cloud requires all workspaces to be given an explicit name.`, 355 `Terraform Cloud has been successfully initialized!`}, 356 }, 357 { 358 command: []string{"workspace", "list"}, 359 expectedCmdOutput: `cloud-workspace`, 360 }, 361 }, 362 }, 363 }, 364 validations: func(t *testing.T, orgName string) { 365 expectedName := "cloud-workspace" 366 ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) 367 if err != nil { 368 t.Fatal(err) 369 } 370 if ws == nil { 371 t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) 372 } 373 }, 374 }, 375 "migrate remote backend prefix to tfc tags strategy multi workspace": { 376 operations: []operationSets{ 377 { 378 prep: func(t *testing.T, orgName, dir string) { 379 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-one")}) 380 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-two")}) 381 prefix := "app-" 382 tfBlock := terraformConfigRemoteBackendPrefix(orgName, prefix) 383 writeMainTF(t, tfBlock, dir) 384 }, 385 commands: []tfCommand{ 386 { 387 command: []string{"init"}, 388 expectedCmdOutput: `The currently selected workspace (default) does not exist.`, 389 userInput: []string{"1"}, 390 postInputOutput: []string{`Terraform has been successfully initialized!`}, 391 }, 392 { 393 command: []string{"apply"}, 394 expectedCmdOutput: `Do you want to perform these actions in workspace "app-one"?`, 395 userInput: []string{"yes"}, 396 postInputOutput: []string{`Apply complete!`}, 397 }, 398 { 399 command: []string{"workspace", "select", "two"}, 400 }, 401 { 402 command: []string{"apply"}, 403 expectedCmdOutput: `Do you want to perform these actions in workspace "app-two"?`, 404 userInput: []string{"yes"}, 405 postInputOutput: []string{`Apply complete!`}, 406 }, 407 }, 408 }, 409 { 410 prep: func(t *testing.T, orgName, dir string) { 411 tag := "app" 412 tfBlock := terraformConfigCloudBackendTags(orgName, tag) 413 writeMainTF(t, tfBlock, dir) 414 }, 415 commands: []tfCommand{ 416 { 417 command: []string{"init", "-ignore-remote-version"}, 418 expectedCmdOutput: `Do you wish to proceed?`, 419 userInput: []string{"yes"}, 420 postInputOutput: []string{`Terraform Cloud has been successfully initialized!`}, 421 }, 422 { 423 command: []string{"workspace", "show"}, 424 expectedCmdOutput: "app-two", 425 }, 426 { 427 command: []string{"workspace", "select", "app-one"}, 428 expectedCmdOutput: `Switched to workspace "app-one".`, 429 }, 430 }, 431 }, 432 }, 433 validations: func(t *testing.T, orgName string) { 434 wsList, err := tfeClient.Workspaces.List(ctx, orgName, &tfe.WorkspaceListOptions{ 435 Tags: "app", 436 }) 437 if err != nil { 438 t.Fatal(err) 439 } 440 if len(wsList.Items) != 2 { 441 t.Logf("Expected the number of workspaces to be 2, but got %d", len(wsList.Items)) 442 } 443 ws, empty := getWorkspace(wsList.Items, "app-one") 444 if empty { 445 t.Fatalf("expected workspaces to include 'app-one' but didn't.") 446 } 447 if len(ws.TagNames) == 0 { 448 t.Fatalf("expected workspaces 'one' to have tags.") 449 } 450 ws, empty = getWorkspace(wsList.Items, "app-two") 451 if empty { 452 t.Fatalf("expected workspaces to include 'app-two' but didn't.") 453 } 454 if len(ws.TagNames) == 0 { 455 t.Fatalf("expected workspaces 'app-two' to have tags.") 456 } 457 }, 458 }, 459 } 460 461 testRunner(t, cases, 1) 462 } 463 464 func Test_migrate_remote_backend_multi_org(t *testing.T) { 465 t.Parallel() 466 skipIfMissingEnvVar(t) 467 skipWithoutRemoteTerraformVersion(t) 468 469 ctx := context.Background() 470 cases := testCases{ 471 "migrate remote backend name to tfc name": { 472 operations: []operationSets{ 473 { 474 prep: func(t *testing.T, orgName, dir string) { 475 remoteWorkspace := "remote-workspace" 476 tfBlock := terraformConfigRemoteBackendName(orgName, remoteWorkspace) 477 writeMainTF(t, tfBlock, dir) 478 }, 479 commands: []tfCommand{ 480 { 481 command: []string{"init"}, 482 expectedCmdOutput: `Successfully configured the backend "remote"!`, 483 }, 484 { 485 command: []string{"apply", "-auto-approve"}, 486 postInputOutput: []string{`Apply complete!`}, 487 }, 488 }, 489 }, 490 { 491 prep: func(t *testing.T, orgName, dir string) { 492 wsName := "remote-workspace" 493 tfBlock := terraformConfigCloudBackendName(orgName, wsName) 494 writeMainTF(t, tfBlock, dir) 495 }, 496 commands: []tfCommand{ 497 { 498 command: []string{"init", "-ignore-remote-version"}, 499 expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, 500 userInput: []string{"yes", "yes"}, 501 postInputOutput: []string{ 502 `Should Terraform migrate your existing state?`, 503 `Terraform Cloud has been successfully initialized!`}, 504 }, 505 { 506 command: []string{"workspace", "show"}, 507 expectedCmdOutput: `remote-workspace`, 508 }, 509 }, 510 }, 511 }, 512 validations: func(t *testing.T, orgName string) { 513 expectedName := "remote-workspace" 514 ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) 515 if err != nil { 516 t.Fatal(err) 517 } 518 if ws == nil { 519 t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) 520 } 521 }, 522 }, 523 } 524 525 testRunner(t, cases, 2) 526 }