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