github.com/kevinklinger/open_terraform@v1.3.6/noninternal/cloud/e2e/migrate_state_tfc_to_tfc_test.go (about) 1 package main 2 3 import ( 4 "context" 5 "testing" 6 7 tfe "github.com/hashicorp/go-tfe" 8 tfversion "github.com/kevinklinger/open_terraform/version" 9 ) 10 11 func Test_migrate_tfc_to_tfc_single_workspace(t *testing.T) { 12 t.Parallel() 13 skipIfMissingEnvVar(t) 14 skipWithoutRemoteTerraformVersion(t) 15 16 ctx := context.Background() 17 18 cases := testCases{ 19 "migrating from name to name": { 20 operations: []operationSets{ 21 { 22 prep: func(t *testing.T, orgName, dir string) { 23 wsName := "prod" 24 // Creating the workspace here instead of it being created 25 // dynamically in the Cloud StateMgr because we want to ensure that 26 // the terraform version selected for the workspace matches the 27 // terraform version of this current branch. 28 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{ 29 Name: tfe.String("prod"), 30 TerraformVersion: tfe.String(tfversion.String()), 31 }) 32 tfBlock := terraformConfigCloudBackendName(orgName, wsName) 33 writeMainTF(t, tfBlock, dir) 34 }, 35 commands: []tfCommand{ 36 { 37 command: []string{"init"}, 38 expectedCmdOutput: `Terraform Cloud has been successfully initialized!`, 39 }, 40 { 41 command: []string{"workspace", "show"}, 42 expectedCmdOutput: `prod`, // this comes from the `prep` function 43 }, 44 { 45 command: []string{"apply", "-auto-approve"}, 46 postInputOutput: []string{`Apply complete!`}, 47 }, 48 }, 49 }, 50 { 51 prep: func(t *testing.T, orgName, dir string) { 52 wsName := "dev" 53 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{ 54 Name: tfe.String(wsName), 55 TerraformVersion: tfe.String(tfversion.String()), 56 }) 57 tfBlock := terraformConfigCloudBackendName(orgName, wsName) 58 writeMainTF(t, tfBlock, dir) 59 }, 60 commands: []tfCommand{ 61 { 62 command: []string{"init", "-ignore-remote-version"}, 63 postInputOutput: []string{`Terraform Cloud has been successfully initialized!`}, 64 }, 65 { 66 command: []string{"workspace", "show"}, 67 expectedCmdOutput: `dev`, // this comes from the `prep` function 68 }, 69 }, 70 }, 71 }, 72 validations: func(t *testing.T, orgName string) { 73 wsList, err := tfeClient.Workspaces.List(ctx, orgName, nil) 74 if err != nil { 75 t.Fatal(err) 76 } 77 // this workspace name is what exists in the cloud backend configuration block 78 if len(wsList.Items) != 2 { 79 t.Fatal("Expected number of workspaces to be 2") 80 } 81 }, 82 }, 83 "migrating from name to tags": { 84 operations: []operationSets{ 85 { 86 prep: func(t *testing.T, orgName, dir string) { 87 wsName := "prod" 88 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{ 89 Name: tfe.String("prod"), 90 TerraformVersion: tfe.String(tfversion.String()), 91 }) 92 tfBlock := terraformConfigCloudBackendName(orgName, wsName) 93 writeMainTF(t, tfBlock, dir) 94 }, 95 commands: []tfCommand{ 96 { 97 command: []string{"init"}, 98 expectedCmdOutput: `Terraform Cloud has been successfully initialized!`, 99 }, 100 { 101 command: []string{"apply", "-auto-approve"}, 102 postInputOutput: []string{`Apply complete!`}, 103 }, 104 }, 105 }, 106 { 107 prep: func(t *testing.T, orgName, dir string) { 108 tag := "app" 109 tfBlock := terraformConfigCloudBackendTags(orgName, tag) 110 writeMainTF(t, tfBlock, dir) 111 }, 112 commands: []tfCommand{ 113 { 114 command: []string{"init", "-ignore-remote-version"}, 115 expectedCmdOutput: `There are no workspaces with the configured tags (app)`, 116 userInput: []string{"new-workspace"}, 117 postInputOutput: []string{ 118 `Terraform can create a properly tagged workspace for you now.`, 119 `Terraform Cloud has been successfully initialized!`}, 120 }, 121 { 122 command: []string{"workspace", "show"}, 123 expectedCmdOutput: `new-workspace`, // this comes from the `prep` function 124 }, 125 }, 126 }, 127 }, 128 validations: func(t *testing.T, orgName string) { 129 wsList, err := tfeClient.Workspaces.List(ctx, orgName, &tfe.WorkspaceListOptions{ 130 Tags: "app", 131 }) 132 if err != nil { 133 t.Fatal(err) 134 } 135 // this workspace name is what exists in the cloud backend configuration block 136 if len(wsList.Items) != 1 { 137 t.Fatal("Expected number of workspaces to be 1") 138 } 139 }, 140 }, 141 "migrating from name to tags without ignore-version flag": { 142 operations: []operationSets{ 143 { 144 prep: func(t *testing.T, orgName, dir string) { 145 wsName := "prod" 146 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{ 147 Name: tfe.String("prod"), 148 TerraformVersion: tfe.String(tfversion.String()), 149 }) 150 tfBlock := terraformConfigCloudBackendName(orgName, wsName) 151 writeMainTF(t, tfBlock, dir) 152 }, 153 commands: []tfCommand{ 154 { 155 command: []string{"init"}, 156 expectedCmdOutput: `Terraform Cloud has been successfully initialized!`, 157 }, 158 { 159 command: []string{"apply", "-auto-approve"}, 160 postInputOutput: []string{`Apply complete!`}, 161 }, 162 }, 163 }, 164 { 165 prep: func(t *testing.T, orgName, dir string) { 166 tag := "app" 167 // This is only here to ensure that the updated terraform version is 168 // present in the workspace, and it does not default to a lower 169 // version that does not support `cloud`. 170 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{ 171 Name: tfe.String("new-workspace"), 172 TerraformVersion: tfe.String(tfversion.String()), 173 }) 174 tfBlock := terraformConfigCloudBackendTags(orgName, tag) 175 writeMainTF(t, tfBlock, dir) 176 }, 177 commands: []tfCommand{ 178 { 179 command: []string{"init"}, 180 expectedCmdOutput: `There are no workspaces with the configured tags (app)`, 181 userInput: []string{"new-workspace"}, 182 postInputOutput: []string{ 183 `Terraform can create a properly tagged workspace for you now.`, 184 `Terraform Cloud has been successfully initialized!`}, 185 }, 186 }, 187 }, 188 }, 189 validations: func(t *testing.T, orgName string) { 190 // We created the workspace, so it will be there. We could not complete the state migration, 191 // though, so the workspace should be empty. 192 ws, err := tfeClient.Workspaces.ReadWithOptions(ctx, orgName, "new-workspace", &tfe.WorkspaceReadOptions{Include: []tfe.WSIncludeOpt{tfe.WSCurrentRun}}) 193 if err != nil { 194 t.Fatal(err) 195 } 196 if ws.CurrentRun != nil { 197 t.Fatal("Expected to workspace be empty") 198 } 199 }, 200 }, 201 } 202 203 testRunner(t, cases, 1) 204 } 205 206 func Test_migrate_tfc_to_tfc_multiple_workspace(t *testing.T) { 207 t.Parallel() 208 skipIfMissingEnvVar(t) 209 skipWithoutRemoteTerraformVersion(t) 210 211 ctx := context.Background() 212 213 cases := testCases{ 214 "migrating from multiple workspaces via tags to name": { 215 operations: []operationSets{ 216 { 217 prep: func(t *testing.T, orgName, dir string) { 218 tag := "app" 219 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{ 220 Name: tfe.String("app-prod"), 221 Tags: []*tfe.Tag{{Name: tag}}, 222 TerraformVersion: tfe.String(tfversion.String()), 223 }) 224 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{ 225 Name: tfe.String("app-staging"), 226 Tags: []*tfe.Tag{{Name: tag}}, 227 TerraformVersion: tfe.String(tfversion.String()), 228 }) 229 tfBlock := terraformConfigCloudBackendTags(orgName, tag) 230 writeMainTF(t, tfBlock, dir) 231 }, 232 commands: []tfCommand{ 233 { 234 command: []string{"init"}, 235 expectedCmdOutput: `The currently selected workspace (default) does not exist.`, 236 userInput: []string{"1"}, 237 postInputOutput: []string{`Terraform Cloud has been successfully initialized!`}, 238 }, 239 { 240 command: []string{"apply"}, 241 expectedCmdOutput: `Do you want to perform these actions in workspace "app-prod"?`, 242 userInput: []string{"yes"}, 243 postInputOutput: []string{`Apply complete!`}, 244 }, 245 { 246 command: []string{"workspace", "select", "app-staging"}, 247 expectedCmdOutput: `Switched to workspace "app-staging".`, 248 }, 249 { 250 command: []string{"apply", "-auto-approve"}, 251 postInputOutput: []string{`Apply complete!`}, 252 }, 253 { 254 command: []string{"output"}, 255 expectedCmdOutput: `tag_val = "app"`, 256 }, 257 }, 258 }, 259 { 260 prep: func(t *testing.T, orgName, dir string) { 261 name := "service" 262 // Doing this here instead of relying on dynamic workspace creation 263 // because we want to set the terraform version here so that it is 264 // using the right version for post init operations. 265 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{ 266 Name: tfe.String(name), 267 TerraformVersion: tfe.String(tfversion.String()), 268 }) 269 tfBlock := terraformConfigCloudBackendName(orgName, name) 270 writeMainTF(t, tfBlock, dir) 271 }, 272 commands: []tfCommand{ 273 { 274 command: []string{"init", "-ignore-remote-version"}, 275 expectedCmdOutput: `Terraform Cloud has been successfully initialized!`, 276 postInputOutput: []string{`tag_val = "service"`}, 277 }, 278 { 279 command: []string{"workspace", "show"}, 280 expectedCmdOutput: `service`, // this comes from the `prep` function 281 }, 282 }, 283 }, 284 }, 285 validations: func(t *testing.T, orgName string) { 286 ws, err := tfeClient.Workspaces.Read(ctx, orgName, "service") 287 if err != nil { 288 t.Fatal(err) 289 } 290 if ws == nil { 291 t.Fatal("Expected to workspace not be empty") 292 } 293 }, 294 }, 295 "migrating from multiple workspaces via tags to other tags": { 296 operations: []operationSets{ 297 { 298 prep: func(t *testing.T, orgName, dir string) { 299 tag := "app" 300 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{ 301 Name: tfe.String("app-prod"), 302 Tags: []*tfe.Tag{{Name: tag}}, 303 TerraformVersion: tfe.String(tfversion.String()), 304 }) 305 _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{ 306 Name: tfe.String("app-staging"), 307 Tags: []*tfe.Tag{{Name: tag}}, 308 TerraformVersion: tfe.String(tfversion.String()), 309 }) 310 tfBlock := terraformConfigCloudBackendTags(orgName, tag) 311 writeMainTF(t, tfBlock, dir) 312 }, 313 commands: []tfCommand{ 314 { 315 command: []string{"init"}, 316 expectedCmdOutput: `The currently selected workspace (default) does not exist.`, 317 userInput: []string{"1"}, 318 postInputOutput: []string{`Terraform Cloud has been successfully initialized!`}, 319 }, 320 { 321 command: []string{"apply", "-auto-approve"}, 322 expectedCmdOutput: `Apply complete!`, 323 }, 324 { 325 command: []string{"workspace", "select", "app-staging"}, 326 expectedCmdOutput: `Switched to workspace "app-staging".`, 327 }, 328 { 329 command: []string{"apply", "-auto-approve"}, 330 expectedCmdOutput: `Apply complete!`, 331 }, 332 }, 333 }, 334 { 335 prep: func(t *testing.T, orgName, dir string) { 336 tag := "billing" 337 tfBlock := terraformConfigCloudBackendTags(orgName, tag) 338 writeMainTF(t, tfBlock, dir) 339 }, 340 commands: []tfCommand{ 341 { 342 command: []string{"init", "-ignore-remote-version"}, 343 expectedCmdOutput: `There are no workspaces with the configured tags (billing)`, 344 userInput: []string{"new-app-prod"}, 345 postInputOutput: []string{`Terraform Cloud has been successfully initialized!`}, 346 }, 347 }, 348 }, 349 }, 350 validations: func(t *testing.T, orgName string) { 351 wsList, err := tfeClient.Workspaces.List(ctx, orgName, &tfe.WorkspaceListOptions{ 352 Tags: "billing", 353 }) 354 if err != nil { 355 t.Fatal(err) 356 } 357 if len(wsList.Items) != 1 { 358 t.Logf("Expected the number of workspaces to be 2, but got %d", len(wsList.Items)) 359 } 360 _, empty := getWorkspace(wsList.Items, "new-app-prod") 361 if empty { 362 t.Fatalf("expected workspaces to include 'new-app-prod' but didn't.") 363 } 364 }, 365 }, 366 } 367 368 testRunner(t, cases, 1) 369 }