github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/cloud/e2e/migrate_state_multi_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 tfversion "github.com/terramate-io/tf/version" 12 ) 13 14 func Test_migrate_multi_to_tfc_cloud_name_strategy(t *testing.T) { 15 t.Parallel() 16 skipIfMissingEnvVar(t) 17 skipWithoutRemoteTerraformVersion(t) 18 19 ctx := context.Background() 20 21 cases := testCases{ 22 "migrating multiple workspaces to cloud using name strategy; current workspace is 'default'": { 23 operations: []operationSets{ 24 { 25 prep: func(t *testing.T, orgName, dir string) { 26 tfBlock := terraformConfigLocalBackend() 27 writeMainTF(t, tfBlock, dir) 28 }, 29 commands: []tfCommand{ 30 { 31 command: []string{"init"}, 32 expectedCmdOutput: `Successfully configured the backend "local"!`, 33 }, 34 { 35 command: []string{"apply", "-auto-approve"}, 36 postInputOutput: []string{`Apply complete!`}, 37 }, 38 { 39 command: []string{"workspace", "new", "prod"}, 40 expectedCmdOutput: `Created and switched to workspace "prod"!`, 41 }, 42 { 43 command: []string{"apply", "-auto-approve"}, 44 postInputOutput: []string{`Apply complete!`}, 45 }, 46 { 47 command: []string{"workspace", "select", "default"}, 48 expectedCmdOutput: `Switched to workspace "default".`, 49 }, 50 }, 51 }, 52 { 53 prep: func(t *testing.T, orgName, dir string) { 54 wsName := "new-workspace" 55 tfBlock := terraformConfigCloudBackendName(orgName, wsName) 56 writeMainTF(t, tfBlock, dir) 57 }, 58 commands: []tfCommand{ 59 { 60 command: []string{"init"}, 61 expectedCmdOutput: `Do you want to copy only your current workspace?`, 62 userInput: []string{"yes"}, 63 postInputOutput: []string{`Terraform Cloud has been successfully initialized!`}, 64 }, 65 { 66 command: []string{"workspace", "show"}, 67 expectedCmdOutput: `new-workspace`, // this comes from the `prep` function 68 }, 69 { 70 command: []string{"output"}, 71 expectedCmdOutput: `val = "default"`, // this was the output of the current workspace selected before migration 72 }, 73 }, 74 }, 75 }, 76 validations: func(t *testing.T, orgName string) { 77 wsList, err := tfeClient.Workspaces.List(ctx, orgName, nil) 78 if err != nil { 79 t.Fatal(err) 80 } 81 if len(wsList.Items) != 1 { 82 t.Fatalf("Expected the number of workspaces to be 1, but got %d", len(wsList.Items)) 83 } 84 ws := wsList.Items[0] 85 // this workspace name is what exists in the cloud backend configuration block 86 if ws.Name != "new-workspace" { 87 t.Fatalf("Expected workspace to be `new-workspace`, but is %s", ws.Name) 88 } 89 }, 90 }, 91 "migrating multiple workspaces to cloud using name strategy; current workspace is 'prod'": { 92 operations: []operationSets{ 93 { 94 prep: func(t *testing.T, orgName, dir string) { 95 tfBlock := terraformConfigLocalBackend() 96 writeMainTF(t, tfBlock, dir) 97 }, 98 commands: []tfCommand{ 99 { 100 command: []string{"init"}, 101 expectedCmdOutput: `Successfully configured the backend "local"!`, 102 }, 103 { 104 command: []string{"apply", "-auto-approve"}, 105 postInputOutput: []string{`Apply complete!`}, 106 }, 107 { 108 command: []string{"workspace", "new", "prod"}, 109 expectedCmdOutput: `Created and switched to workspace "prod"!`, 110 }, 111 { 112 command: []string{"apply", "-auto-approve"}, 113 postInputOutput: []string{`Apply complete!`}, 114 }, 115 }, 116 }, 117 { 118 prep: func(t *testing.T, orgName, dir string) { 119 wsName := "new-workspace" 120 tfBlock := terraformConfigCloudBackendName(orgName, wsName) 121 writeMainTF(t, tfBlock, dir) 122 }, 123 commands: []tfCommand{ 124 { 125 command: []string{"init"}, 126 expectedCmdOutput: `Do you want to copy only your current workspace?`, 127 userInput: []string{"yes"}, 128 postInputOutput: []string{`Terraform Cloud has been successfully initialized!`}, 129 }, 130 { 131 command: []string{"workspace", "list"}, 132 expectedCmdOutput: `new-workspace`, // this comes from the `prep` function 133 }, 134 { 135 command: []string{"output"}, 136 expectedCmdOutput: `val = "prod"`, 137 }, 138 }, 139 }, 140 }, 141 validations: func(t *testing.T, orgName string) { 142 wsList, err := tfeClient.Workspaces.List(ctx, orgName, nil) 143 if err != nil { 144 t.Fatal(err) 145 } 146 ws := wsList.Items[0] 147 // this workspace name is what exists in the cloud backend configuration block 148 if ws.Name != "new-workspace" { 149 t.Fatalf("Expected workspace to be `new-workspace`, but is %s", ws.Name) 150 } 151 }, 152 }, 153 "migrating multiple workspaces to cloud using name strategy; 'default' workspace is empty": { 154 operations: []operationSets{ 155 { 156 prep: func(t *testing.T, orgName, dir string) { 157 tfBlock := terraformConfigLocalBackend() 158 writeMainTF(t, tfBlock, dir) 159 }, 160 commands: []tfCommand{ 161 { 162 command: []string{"init"}, 163 expectedCmdOutput: `Successfully configured the backend "local"!`, 164 }, 165 { 166 command: []string{"workspace", "new", "workspace1"}, 167 expectedCmdOutput: `Created and switched to workspace "workspace1"!`, 168 }, 169 { 170 command: []string{"apply", "-auto-approve"}, 171 postInputOutput: []string{`Apply complete!`}, 172 }, 173 { 174 command: []string{"workspace", "new", "workspace2"}, 175 expectedCmdOutput: `Created and switched to workspace "workspace2"!`, 176 }, 177 { 178 command: []string{"apply", "-auto-approve"}, 179 postInputOutput: []string{`Apply complete!`}, 180 }, 181 }, 182 }, 183 { 184 prep: func(t *testing.T, orgName, dir string) { 185 wsName := "new-workspace" 186 tfBlock := terraformConfigCloudBackendName(orgName, wsName) 187 writeMainTF(t, tfBlock, dir) 188 }, 189 commands: []tfCommand{ 190 { 191 command: []string{"init"}, 192 expectedCmdOutput: `Do you want to copy only your current workspace?`, 193 userInput: []string{"yes"}, 194 postInputOutput: []string{`Terraform Cloud has been successfully initialized!`}, 195 }, 196 { 197 command: []string{"workspace", "select", "default"}, 198 expectError: true, 199 }, 200 { 201 command: []string{"output"}, 202 expectedCmdOutput: `val = "workspace2"`, // this was the output of the current workspace selected before migration 203 }, 204 }, 205 }, 206 }, 207 validations: func(t *testing.T, orgName string) { 208 wsList, err := tfeClient.Workspaces.List(ctx, orgName, nil) 209 if err != nil { 210 t.Fatal(err) 211 } 212 if len(wsList.Items) != 1 { 213 t.Fatalf("Expected the number of workspaces to be 1, but got %d", len(wsList.Items)) 214 } 215 ws := wsList.Items[0] 216 // this workspace name is what exists in the cloud backend configuration block 217 if ws.Name != "new-workspace" { 218 t.Fatalf("Expected workspace to be `new-workspace`, but is %s", ws.Name) 219 } 220 }, 221 }, 222 } 223 224 testRunner(t, cases, 1) 225 } 226 227 func Test_migrate_multi_to_tfc_cloud_tags_strategy(t *testing.T) { 228 t.Parallel() 229 skipIfMissingEnvVar(t) 230 skipWithoutRemoteTerraformVersion(t) 231 232 ctx := context.Background() 233 234 cases := map[string]struct { 235 operations []operationSets 236 validations func(t *testing.T, orgName string) 237 }{ 238 "migrating multiple workspaces to cloud using tags strategy; pattern is using prefix `app-*`": { 239 operations: []operationSets{ 240 { 241 prep: func(t *testing.T, orgName, dir string) { 242 tfBlock := terraformConfigLocalBackend() 243 writeMainTF(t, tfBlock, dir) 244 }, 245 commands: []tfCommand{ 246 { 247 command: []string{"init"}, 248 expectedCmdOutput: `Successfully configured the backend "local"!`, 249 }, 250 { 251 command: []string{"apply", "-auto-approve"}, 252 postInputOutput: []string{`Apply complete!`}, 253 }, 254 { 255 command: []string{"workspace", "new", "prod"}, 256 expectedCmdOutput: `Created and switched to workspace "prod"!`, 257 }, 258 { 259 command: []string{"apply", "-auto-approve"}, 260 postInputOutput: []string{`Apply complete!`}, 261 }, 262 { 263 command: []string{"workspace", "select", "default"}, 264 expectedCmdOutput: `Switched to workspace "default".`, 265 }, 266 { 267 command: []string{"output"}, 268 expectedCmdOutput: `val = "default"`, 269 }, 270 { 271 command: []string{"workspace", "select", "prod"}, 272 expectedCmdOutput: `Switched to workspace "prod".`, 273 }, 274 { 275 command: []string{"output"}, 276 expectedCmdOutput: `val = "prod"`, 277 }, 278 }, 279 }, 280 { 281 prep: func(t *testing.T, orgName, dir string) { 282 tag := "app" 283 tfBlock := terraformConfigCloudBackendTags(orgName, tag) 284 writeMainTF(t, tfBlock, dir) 285 }, 286 commands: []tfCommand{ 287 { 288 command: []string{"init"}, 289 expectedCmdOutput: `Terraform Cloud requires all workspaces to be given an explicit name.`, 290 userInput: []string{"dev", "1", "app-*"}, 291 postInputOutput: []string{ 292 `Would you like to rename your workspaces?`, 293 "How would you like to rename your workspaces?", 294 "Terraform Cloud has been successfully initialized!"}, 295 }, 296 { 297 command: []string{"workspace", "select", "app-dev"}, 298 expectedCmdOutput: `Switched to workspace "app-dev".`, 299 }, 300 { 301 command: []string{"output"}, 302 expectedCmdOutput: `val = "default"`, 303 }, 304 { 305 command: []string{"workspace", "select", "app-prod"}, 306 expectedCmdOutput: `Switched to workspace "app-prod".`, 307 }, 308 { 309 command: []string{"output"}, 310 expectedCmdOutput: `val = "prod"`, 311 }, 312 }, 313 }, 314 }, 315 validations: func(t *testing.T, orgName string) { 316 wsList, err := tfeClient.Workspaces.List(ctx, orgName, &tfe.WorkspaceListOptions{ 317 Tags: "app", 318 }) 319 if err != nil { 320 t.Fatal(err) 321 } 322 if len(wsList.Items) != 2 { 323 t.Fatalf("Expected the number of workspaecs to be 2, but got %d", len(wsList.Items)) 324 } 325 expectedWorkspaceNames := []string{"app-prod", "app-dev"} 326 for _, ws := range wsList.Items { 327 hasName := false 328 for _, expectedNames := range expectedWorkspaceNames { 329 if expectedNames == ws.Name { 330 hasName = true 331 } 332 } 333 if !hasName { 334 t.Fatalf("Worksapce %s is not in the expected list of workspaces", ws.Name) 335 } 336 } 337 }, 338 }, 339 "migrating multiple workspaces to cloud using tags strategy; existing workspaces": { 340 operations: []operationSets{ 341 { 342 prep: func(t *testing.T, orgName, dir string) { 343 tfBlock := terraformConfigLocalBackend() 344 writeMainTF(t, tfBlock, dir) 345 }, 346 commands: []tfCommand{ 347 { 348 command: []string{"init"}, 349 expectedCmdOutput: `Successfully configured the backend "local"!`, 350 }, 351 { 352 command: []string{"apply", "-auto-approve"}, 353 postInputOutput: []string{`Apply complete!`}, 354 }, 355 { 356 command: []string{"workspace", "new", "identity"}, 357 expectedCmdOutput: `Created and switched to workspace "identity"!`, 358 }, 359 { 360 command: []string{"apply", "-auto-approve"}, 361 postInputOutput: []string{`Apply complete!`}, 362 }, 363 { 364 command: []string{"workspace", "new", "billing"}, 365 expectedCmdOutput: `Created and switched to workspace "billing"!`, 366 }, 367 { 368 command: []string{"apply", "-auto-approve"}, 369 postInputOutput: []string{`Apply complete!`}, 370 }, 371 { 372 command: []string{"workspace", "select", "default"}, 373 expectedCmdOutput: `Switched to workspace "default".`, 374 }, 375 }, 376 }, 377 { 378 prep: func(t *testing.T, orgName, dir string) { 379 tag := "app" 380 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{ 381 Name: tfe.String("identity"), 382 TerraformVersion: tfe.String(tfversion.String()), 383 }) 384 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{ 385 Name: tfe.String("billing"), 386 TerraformVersion: tfe.String(tfversion.String()), 387 }) 388 tfBlock := terraformConfigCloudBackendTags(orgName, tag) 389 writeMainTF(t, tfBlock, dir) 390 }, 391 commands: []tfCommand{ 392 { 393 command: []string{"init"}, 394 expectedCmdOutput: `Terraform Cloud requires all workspaces to be given an explicit name.`, 395 userInput: []string{"dev", "1", "app-*"}, 396 postInputOutput: []string{ 397 `Would you like to rename your workspaces?`, 398 "How would you like to rename your workspaces?", 399 "Terraform Cloud has been successfully initialized!"}, 400 }, 401 { 402 command: []string{"workspace", "select", "app-billing"}, 403 expectedCmdOutput: `Switched to workspace "app-billing".`, 404 }, 405 { 406 command: []string{"workspace", "select", "app-identity"}, 407 expectedCmdOutput: `Switched to workspace "app-identity".`, 408 }, 409 { 410 command: []string{"workspace", "select", "app-dev"}, 411 expectedCmdOutput: `Switched to workspace "app-dev".`, 412 }, 413 }, 414 }, 415 }, 416 validations: func(t *testing.T, orgName string) { 417 wsList, err := tfeClient.Workspaces.List(ctx, orgName, &tfe.WorkspaceListOptions{ 418 Tags: "app", 419 }) 420 if err != nil { 421 t.Fatal(err) 422 } 423 if len(wsList.Items) != 3 { 424 t.Fatalf("Expected the number of workspaecs to be 3, but got %d", len(wsList.Items)) 425 } 426 expectedWorkspaceNames := []string{"app-billing", "app-dev", "app-identity"} 427 for _, ws := range wsList.Items { 428 hasName := false 429 for _, expectedNames := range expectedWorkspaceNames { 430 if expectedNames == ws.Name { 431 hasName = true 432 } 433 } 434 if !hasName { 435 t.Fatalf("Worksapce %s is not in the expected list of workspaces", ws.Name) 436 } 437 } 438 }, 439 }, 440 } 441 442 testRunner(t, cases, 1) 443 }