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  }