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