mirror of
https://github.com/hashicorp/terraform.git
synced 2026-02-03 20:50:59 -05:00
address PR feedback
This commit is contained in:
parent
f0fbe0f656
commit
8e1d04a388
2 changed files with 181 additions and 7 deletions
|
|
@ -4788,7 +4788,6 @@ func TestInit_backend_to_stateStore_singleWorkspace(t *testing.T) {
|
|||
args := []string{
|
||||
"-enable-pluggable-state-storage-experiment=true",
|
||||
"-force-copy",
|
||||
"-migrate-state",
|
||||
}
|
||||
code := c.Run(args)
|
||||
testOutput := done(t)
|
||||
|
|
@ -4835,6 +4834,131 @@ func TestInit_backend_to_stateStore_singleWorkspace(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestInit_backend_to_stateStore_noState(t *testing.T) {
|
||||
// Create a temporary working directory that is empty
|
||||
td := t.TempDir()
|
||||
|
||||
testBackend := new(httpBackend.TestHTTPBackend)
|
||||
ts := httptest.NewServer(http.HandlerFunc(testBackend.Handle))
|
||||
t.Cleanup(ts.Close)
|
||||
|
||||
cfg := fmt.Sprintf(`terraform {
|
||||
backend "http" {
|
||||
address = %q
|
||||
}
|
||||
}
|
||||
`, ts.URL)
|
||||
if err := os.WriteFile(filepath.Join(td, "main.tf"), []byte(cfg), 0644); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
t.Chdir(td)
|
||||
|
||||
mockProvider := mockPluggableStateStorageProvider()
|
||||
mockProviderAddress := addrs.NewDefaultProvider("test")
|
||||
providerSource, close := newMockProviderSource(t, map[string][]string{
|
||||
"hashicorp/test": {"1.2.3"},
|
||||
})
|
||||
defer close()
|
||||
|
||||
tOverrides := &testingOverrides{
|
||||
Providers: map[addrs.Provider]providers.Factory{
|
||||
mockProviderAddress: providers.FactoryFixed(mockProvider),
|
||||
},
|
||||
}
|
||||
{
|
||||
log.Printf("[TRACE] %s: beginning first init with backend", t.Name())
|
||||
// Init
|
||||
ui := cli.NewMockUi()
|
||||
view, done := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
View: view,
|
||||
AllowExperimentalFeatures: true,
|
||||
},
|
||||
}
|
||||
args := []string{
|
||||
"-enable-pluggable-state-storage-experiment=true",
|
||||
}
|
||||
code := c.Run(args)
|
||||
testOutput := done(t)
|
||||
if code != 0 {
|
||||
t.Fatalf("first init exited with non-zero code %d:\n%s", code, testOutput.Stderr())
|
||||
}
|
||||
log.Printf("[TRACE] %s: first init complete", t.Name())
|
||||
t.Logf("First run output:\n%s", testOutput.Stdout())
|
||||
t.Logf("First run errors:\n%s", testOutput.Stderr())
|
||||
|
||||
if testBackend.CallCount("POST") != 0 {
|
||||
t.Fatalf("expected 0 POST calls after init, got %d", testBackend.CallCount("POST"))
|
||||
}
|
||||
if testBackend.CallCount("GET") != 2 {
|
||||
t.Fatalf("expected 2 GET calls after init, got %d", testBackend.CallCount("GET"))
|
||||
}
|
||||
}
|
||||
{
|
||||
log.Printf("[TRACE] %s: beginning second init with state store", t.Name())
|
||||
|
||||
ssCfg := `terraform {
|
||||
required_providers {
|
||||
test = {
|
||||
source = "hashicorp/test"
|
||||
}
|
||||
}
|
||||
state_store "test_store" {
|
||||
provider "test" {}
|
||||
value = "foobar"
|
||||
}
|
||||
}
|
||||
`
|
||||
if err := os.WriteFile(filepath.Join(td, "main.tf"), []byte(ssCfg), 0644); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
ui := cli.NewMockUi()
|
||||
view, done := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: tOverrides,
|
||||
ProviderSource: providerSource,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
AllowExperimentalFeatures: true,
|
||||
},
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-enable-pluggable-state-storage-experiment=true",
|
||||
"-force-copy",
|
||||
// assume default -create-default-workspace=true
|
||||
}
|
||||
code := c.Run(args)
|
||||
testOutput := done(t)
|
||||
if code != 0 {
|
||||
t.Fatalf("second init exited with non-zero code %d:\n%s", code, testOutput.Stderr())
|
||||
}
|
||||
log.Printf("[TRACE] %s: second init with state store complete", t.Name())
|
||||
t.Logf("Second run output:\n%s", testOutput.Stdout())
|
||||
t.Logf("Second run errors:\n%s", testOutput.Stderr())
|
||||
|
||||
s := testDataStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename))
|
||||
if s.StateStore.Empty() {
|
||||
t.Fatal("should have StateStore config")
|
||||
}
|
||||
if !s.Backend.Empty() {
|
||||
t.Fatalf("expected backend to be empty")
|
||||
}
|
||||
|
||||
_, ok := mockProvider.MockStates[backend.DefaultStateName].([]byte)
|
||||
if !ok {
|
||||
t.Fatalf("expected %q state to exist in %s: %#v",
|
||||
backend.DefaultStateName,
|
||||
mockProviderAddress,
|
||||
mockProvider.MockStates)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInit_backend_to_stateStore_multipleWorkspaces(t *testing.T) {
|
||||
// Create a temporary working directory that is empty
|
||||
td := t.TempDir()
|
||||
|
|
|
|||
|
|
@ -1107,8 +1107,9 @@ func (m *Meta) backendFromConfig(opts *BackendOpts) (backend.Backend, tfdiags.Di
|
|||
)
|
||||
|
||||
if !opts.Init {
|
||||
initReason := fmt.Sprintf("Migrating from backend %q to state store %q",
|
||||
s.Backend.Type, stateStoreConfig.Type)
|
||||
initReason := fmt.Sprintf("Migrating from backend %q to state store %q in provider %s (%q)",
|
||||
s.Backend.Type, stateStoreConfig.Type,
|
||||
stateStoreConfig.Provider.Name, stateStoreConfig.ProviderAddr)
|
||||
diags = diags.Append(errBackendInitDiag(initReason))
|
||||
return nil, diags
|
||||
}
|
||||
|
|
@ -1959,9 +1960,6 @@ func (m *Meta) backend_to_stateStore(bcs *workdir.BackendConfigState, sMgr *clis
|
|||
return nil, diags
|
||||
}
|
||||
|
||||
// Update the stored metadata
|
||||
s.Backend = nil
|
||||
|
||||
if m.stateLock {
|
||||
view := views.NewStateLocker(vt, m.View)
|
||||
stateLocker := clistate.NewLocker(m.stateLockTimeout, view)
|
||||
|
|
@ -1975,7 +1973,7 @@ func (m *Meta) backend_to_stateStore(bcs *workdir.BackendConfigState, sMgr *clis
|
|||
// Store the state_store metadata in our saved state location
|
||||
|
||||
var pVersion *version.Version // This will remain nil for builtin providers or unmanaged providers.
|
||||
if c.ProviderAddr.Hostname == addrs.BuiltInProviderHost {
|
||||
if c.ProviderAddr.IsBuiltIn() {
|
||||
diags = diags.Append(&hcl.Diagnostic{
|
||||
Severity: hcl.DiagWarning,
|
||||
Summary: "State storage is using a builtin provider",
|
||||
|
|
@ -2005,6 +2003,7 @@ func (m *Meta) backend_to_stateStore(bcs *workdir.BackendConfigState, sMgr *clis
|
|||
}
|
||||
}
|
||||
|
||||
// Update the stored metadata
|
||||
s.Backend = nil
|
||||
s.StateStore = &workdir.StateStoreConfigState{
|
||||
Type: c.Type,
|
||||
|
|
@ -2030,6 +2029,57 @@ func (m *Meta) backend_to_stateStore(bcs *workdir.BackendConfigState, sMgr *clis
|
|||
return nil, diags
|
||||
}
|
||||
|
||||
// Verify that selected workspace exists in the state store.
|
||||
if opts.Init {
|
||||
err := m.selectWorkspace(ssBackend)
|
||||
if err != nil {
|
||||
if errors.Is(err, &errBackendNoExistingWorkspaces{}) {
|
||||
// If there are no workspaces, Terraform either needs to create the default workspace here
|
||||
// or instruct the user to run a `terraform workspace new` command.
|
||||
ws, err := m.Workspace()
|
||||
if err != nil {
|
||||
diags = diags.Append(fmt.Errorf("Failed to check current workspace: %w", err))
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
if ws == backend.DefaultStateName {
|
||||
// Users control if the default workspace is created through the -create-default-workspace flag (defaults to true)
|
||||
if opts.CreateDefaultWorkspace {
|
||||
diags = diags.Append(m.createDefaultWorkspace(c, ssBackend))
|
||||
if !diags.HasErrors() {
|
||||
// Report workspace creation to the view
|
||||
view := views.NewInit(vt, m.View)
|
||||
view.Output(views.DefaultWorkspaceCreatedMessage)
|
||||
}
|
||||
} else {
|
||||
diags = diags.Append(&hcl.Diagnostic{
|
||||
Severity: hcl.DiagWarning,
|
||||
Summary: "The default workspace does not exist",
|
||||
Detail: "Terraform has been configured to skip creation of the default workspace in the state store. To create it, either remove the `-create-default-workspace=false` flag and re-run the 'init' command, or create it using a 'workspace new' command",
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// User needs to run a `terraform workspace new` command to create the missing custom workspace.
|
||||
diags = append(diags, tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
fmt.Sprintf("Workspace %q has not been created yet", ws),
|
||||
fmt.Sprintf("State store %q in provider %s (%q) reports that no workspaces currently exist. To create the custom workspace %q use the command `terraform workspace new %s`.",
|
||||
c.Type,
|
||||
c.Provider.Name,
|
||||
c.ProviderAddr,
|
||||
ws,
|
||||
ws,
|
||||
),
|
||||
))
|
||||
return nil, diags
|
||||
}
|
||||
} else {
|
||||
// For all other errors, report via diagnostics
|
||||
diags = diags.Append(fmt.Errorf("Failed to select a workspace: %w", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update backend state file
|
||||
if err := sMgr.WriteState(s); err != nil {
|
||||
diags = diags.Append(errBackendWriteSavedDiag(err))
|
||||
|
|
|
|||
Loading…
Reference in a new issue