mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
update persist state
This commit is contained in:
parent
03f5085026
commit
4fab46749a
@ -344,7 +344,7 @@ func (b *Local) opWait(
|
||||
|
||||
// try to force a PersistState just in case the process is terminated
|
||||
// before we can complete.
|
||||
if err := opStateMgr.PersistState(); err != nil {
|
||||
if err := opStateMgr.PersistState(nil); err != nil {
|
||||
// We can't error out from here, but warn the user if there was an error.
|
||||
// If this isn't transient, we will catch it again below, and
|
||||
// attempt to save the state another way.
|
||||
|
@ -53,7 +53,7 @@ func (b *Local) opApply(
|
||||
op.ReportResult(runningOp, diags)
|
||||
return
|
||||
}
|
||||
// the state was locked during succesfull context creation; unlock the state
|
||||
// the state was locked during successful context creation; unlock the state
|
||||
// when the operation completes
|
||||
defer func() {
|
||||
diags := op.StateLocker.Unlock()
|
||||
@ -68,19 +68,19 @@ func (b *Local) opApply(
|
||||
// operation.
|
||||
runningOp.State = lr.InputState
|
||||
|
||||
var plan *plans.Plan
|
||||
// If we weren't given a plan, then we refresh/plan
|
||||
if op.PlanFile == nil {
|
||||
// Perform the plan
|
||||
log.Printf("[INFO] backend/local: apply calling Plan")
|
||||
plan, moreDiags = lr.Core.Plan(lr.Config, lr.InputState, lr.PlanOpts)
|
||||
schemas, moreDiags := lr.Core.Schemas(lr.Config, lr.InputState)
|
||||
diags = diags.Append(moreDiags)
|
||||
if moreDiags.HasErrors() {
|
||||
op.ReportResult(runningOp, diags)
|
||||
return
|
||||
}
|
||||
|
||||
schemas, moreDiags := lr.Core.Schemas(lr.Config, lr.InputState)
|
||||
var plan *plans.Plan
|
||||
// If we weren't given a plan, then we refresh/plan
|
||||
if op.PlanFile == nil {
|
||||
// Perform the plan
|
||||
log.Printf("[INFO] backend/local: apply calling Plan")
|
||||
plan, moreDiags = lr.Core.Plan(lr.Config, lr.InputState, lr.PlanOpts)
|
||||
diags = diags.Append(moreDiags)
|
||||
if moreDiags.HasErrors() {
|
||||
op.ReportResult(runningOp, diags)
|
||||
@ -198,7 +198,7 @@ func (b *Local) opApply(
|
||||
|
||||
// Store the final state
|
||||
runningOp.State = applyState
|
||||
err := statemgr.WriteAndPersist(opState, applyState)
|
||||
err := statemgr.WriteAndPersist(opState, applyState, schemas)
|
||||
if err != nil {
|
||||
// Export the state file from the state manager and assign the new
|
||||
// state. This is needed to preserve the existing serial and lineage.
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
"github.com/hashicorp/terraform/internal/states/statefile"
|
||||
"github.com/hashicorp/terraform/internal/states/statemgr"
|
||||
"github.com/hashicorp/terraform/internal/terminal"
|
||||
"github.com/hashicorp/terraform/internal/terraform"
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
@ -233,6 +234,6 @@ func (s *stateStorageThatFailsRefresh) RefreshState() error {
|
||||
return fmt.Errorf("intentionally failing for testing purposes")
|
||||
}
|
||||
|
||||
func (s *stateStorageThatFailsRefresh) PersistState() error {
|
||||
func (s *stateStorageThatFailsRefresh) PersistState(schemas *terraform.Schemas) error {
|
||||
return fmt.Errorf("unimplemented")
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ func (b *Local) opRefresh(
|
||||
return
|
||||
}
|
||||
|
||||
// the state was locked during succesfull context creation; unlock the state
|
||||
// the state was locked during successful context creation; unlock the state
|
||||
// when the operation completes
|
||||
defer func() {
|
||||
diags := op.StateLocker.Unlock()
|
||||
@ -73,6 +73,14 @@ func (b *Local) opRefresh(
|
||||
))
|
||||
}
|
||||
|
||||
// get schemas before writing state
|
||||
schemas, moreDiags := lr.Core.Schemas(lr.Config, lr.InputState)
|
||||
diags = diags.Append(moreDiags)
|
||||
if moreDiags.HasErrors() {
|
||||
op.ReportResult(runningOp, diags)
|
||||
return
|
||||
}
|
||||
|
||||
// Perform the refresh in a goroutine so we can be interrupted
|
||||
var newState *states.State
|
||||
var refreshDiags tfdiags.Diagnostics
|
||||
@ -96,7 +104,7 @@ func (b *Local) opRefresh(
|
||||
return
|
||||
}
|
||||
|
||||
err := statemgr.WriteAndPersist(opState, newState)
|
||||
err := statemgr.WriteAndPersist(opState, newState, schemas)
|
||||
if err != nil {
|
||||
diags = diags.Append(fmt.Errorf("failed to write state: %w", err))
|
||||
op.ReportResult(runningOp, diags)
|
||||
|
@ -131,7 +131,7 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
|
||||
err = lockUnlock(err)
|
||||
return nil, err
|
||||
}
|
||||
if err := stateMgr.PersistState(); err != nil {
|
||||
if err := stateMgr.PersistState(nil); err != nil {
|
||||
err = lockUnlock(err)
|
||||
return nil, err
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
|
||||
err = lockUnlock(err)
|
||||
return nil, err
|
||||
}
|
||||
if err := stateMgr.PersistState(); err != nil {
|
||||
if err := stateMgr.PersistState(nil); err != nil {
|
||||
err = lockUnlock(err)
|
||||
return nil, err
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
|
||||
err = lockUnlock(err)
|
||||
return nil, err
|
||||
}
|
||||
if err := stateMgr.PersistState(); err != nil {
|
||||
if err := stateMgr.PersistState(nil); err != nil {
|
||||
err = lockUnlock(err)
|
||||
return nil, err
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
|
||||
if err := st.WriteState(states.NewState()); err != nil {
|
||||
return nil, unlock(err)
|
||||
}
|
||||
if err := st.PersistState(); err != nil {
|
||||
if err := st.PersistState(nil); err != nil {
|
||||
return nil, unlock(err)
|
||||
}
|
||||
|
||||
|
@ -141,7 +141,7 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
|
||||
if err := s.WriteState(statespkg.NewState()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := s.PersistState(); err != nil {
|
||||
if err := s.PersistState(nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,6 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/backend"
|
||||
statespkg "github.com/hashicorp/terraform/internal/states"
|
||||
"github.com/hashicorp/terraform/internal/states/remote"
|
||||
@ -82,7 +80,7 @@ func TestRemoteState(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := s.PersistState(); err != nil {
|
||||
if err := s.PersistState(nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -123,7 +123,7 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
|
||||
if err := stateMgr.WriteState(states.NewState()); err != nil {
|
||||
return nil, unlock(err)
|
||||
}
|
||||
if err := stateMgr.PersistState(); err != nil {
|
||||
if err := stateMgr.PersistState(nil); err != nil {
|
||||
return nil, unlock(err)
|
||||
}
|
||||
|
||||
|
@ -108,7 +108,7 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
|
||||
err = lockUnlock(err)
|
||||
return nil, err
|
||||
}
|
||||
if err := stateMgr.PersistState(); err != nil {
|
||||
if err := stateMgr.PersistState(nil); err != nil {
|
||||
err = lockUnlock(err)
|
||||
return nil, err
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
|
||||
err = lockUnlock(err)
|
||||
return nil, err
|
||||
}
|
||||
if err := stateMgr.PersistState(); err != nil {
|
||||
if err := stateMgr.PersistState(nil); err != nil {
|
||||
err = lockUnlock(err)
|
||||
return nil, err
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
|
||||
err = lockUnlock(err)
|
||||
return nil, err
|
||||
}
|
||||
if err := stateMgr.PersistState(); err != nil {
|
||||
if err := stateMgr.PersistState(nil); err != nil {
|
||||
err = lockUnlock(err)
|
||||
return nil, err
|
||||
}
|
||||
|
@ -330,7 +330,7 @@ func TestBackendConcurrentLock(t *testing.T) {
|
||||
t.Fatalf("failed to lock first state: %v", err)
|
||||
}
|
||||
|
||||
if err = s1.PersistState(); err != nil {
|
||||
if err = s1.PersistState(nil); err != nil {
|
||||
t.Fatalf("failed to persist state: %v", err)
|
||||
}
|
||||
|
||||
@ -343,7 +343,7 @@ func TestBackendConcurrentLock(t *testing.T) {
|
||||
t.Fatalf("failed to lock second state: %v", err)
|
||||
}
|
||||
|
||||
if err = s2.PersistState(); err != nil {
|
||||
if err = s2.PersistState(nil); err != nil {
|
||||
t.Fatalf("failed to persist state: %v", err)
|
||||
}
|
||||
|
||||
|
@ -184,7 +184,7 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
|
||||
err = lockUnlock(err)
|
||||
return nil, err
|
||||
}
|
||||
if err := stateMgr.PersistState(); err != nil {
|
||||
if err := stateMgr.PersistState(nil); err != nil {
|
||||
err = lockUnlock(err)
|
||||
return nil, err
|
||||
}
|
||||
|
@ -478,7 +478,7 @@ func TestBackendExtraPaths(t *testing.T) {
|
||||
// Write the first state
|
||||
stateMgr := &remote.State{Client: client}
|
||||
stateMgr.WriteState(s1)
|
||||
if err := stateMgr.PersistState(); err != nil {
|
||||
if err := stateMgr.PersistState(nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@ -488,7 +488,7 @@ func TestBackendExtraPaths(t *testing.T) {
|
||||
client.path = b.path("s2")
|
||||
stateMgr2 := &remote.State{Client: client}
|
||||
stateMgr2.WriteState(s2)
|
||||
if err := stateMgr2.PersistState(); err != nil {
|
||||
if err := stateMgr2.PersistState(nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@ -501,7 +501,7 @@ func TestBackendExtraPaths(t *testing.T) {
|
||||
// put a state in an env directory name
|
||||
client.path = b.workspaceKeyPrefix + "/error"
|
||||
stateMgr.WriteState(states.NewState())
|
||||
if err := stateMgr.PersistState(); err != nil {
|
||||
if err := stateMgr.PersistState(nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := checkStateList(b, []string{"default", "s1", "s2"}); err != nil {
|
||||
@ -511,7 +511,7 @@ func TestBackendExtraPaths(t *testing.T) {
|
||||
// add state with the wrong key for an existing env
|
||||
client.path = b.workspaceKeyPrefix + "/s2/notTestState"
|
||||
stateMgr.WriteState(states.NewState())
|
||||
if err := stateMgr.PersistState(); err != nil {
|
||||
if err := stateMgr.PersistState(nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := checkStateList(b, []string{"default", "s1", "s2"}); err != nil {
|
||||
@ -550,7 +550,7 @@ func TestBackendExtraPaths(t *testing.T) {
|
||||
// add a state with a key that matches an existing environment dir name
|
||||
client.path = b.workspaceKeyPrefix + "/s2/"
|
||||
stateMgr.WriteState(states.NewState())
|
||||
if err := stateMgr.PersistState(); err != nil {
|
||||
if err := stateMgr.PersistState(nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -172,7 +172,7 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
|
||||
err = lockUnlock(err)
|
||||
return nil, err
|
||||
}
|
||||
if err := stateMgr.PersistState(); err != nil {
|
||||
if err := stateMgr.PersistState(nil); err != nil {
|
||||
err = lockUnlock(err)
|
||||
return nil, err
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ func TestBackendStates(t *testing.T, b Backend) {
|
||||
if err := foo.WriteState(fooState); err != nil {
|
||||
t.Fatal("error writing foo state:", err)
|
||||
}
|
||||
if err := foo.PersistState(); err != nil {
|
||||
if err := foo.PersistState(nil); err != nil {
|
||||
t.Fatal("error persisting foo state:", err)
|
||||
}
|
||||
|
||||
@ -160,7 +160,7 @@ func TestBackendStates(t *testing.T, b Backend) {
|
||||
if err := bar.WriteState(barState); err != nil {
|
||||
t.Fatalf("bad: %s", err)
|
||||
}
|
||||
if err := bar.PersistState(); err != nil {
|
||||
if err := bar.PersistState(nil); err != nil {
|
||||
t.Fatalf("bad: %s", err)
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"github.com/hashicorp/terraform/internal/states"
|
||||
"github.com/hashicorp/terraform/internal/states/remote"
|
||||
"github.com/hashicorp/terraform/internal/states/statemgr"
|
||||
"github.com/hashicorp/terraform/internal/terraform"
|
||||
)
|
||||
|
||||
// State is similar to remote State and delegates to it, except in the case of output values,
|
||||
@ -63,9 +64,9 @@ func (s *State) RefreshState() error {
|
||||
return s.delegate.RefreshState()
|
||||
}
|
||||
|
||||
// RefreshState delegates calls to refresh State to the remote State
|
||||
func (s *State) PersistState() error {
|
||||
return s.delegate.PersistState()
|
||||
// PersistState delegates calls to persist State to the remote State
|
||||
func (s *State) PersistState(schemas *terraform.Schemas) error {
|
||||
return s.delegate.PersistState(schemas)
|
||||
}
|
||||
|
||||
// WriteState delegates calls to write State to the remote State
|
||||
|
34
internal/command/helper.go
Normal file
34
internal/command/helper.go
Normal file
@ -0,0 +1,34 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform/internal/configs"
|
||||
"github.com/hashicorp/terraform/internal/states"
|
||||
"github.com/hashicorp/terraform/internal/terraform"
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
func getSchemas(c *Meta, state *states.State, config *configs.Config) (*terraform.Schemas, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
if config != nil || state != nil {
|
||||
opts, err := c.contextOpts()
|
||||
if err != nil {
|
||||
diags = diags.Append(err)
|
||||
return nil, diags
|
||||
}
|
||||
tfCtx, ctxDiags := terraform.NewContext(opts)
|
||||
diags = diags.Append(ctxDiags)
|
||||
if ctxDiags.HasErrors() {
|
||||
return nil, diags
|
||||
}
|
||||
var schemaDiags tfdiags.Diagnostics
|
||||
schemas, schemaDiags := tfCtx.Schemas(config, state)
|
||||
diags = diags.Append(schemaDiags)
|
||||
if schemaDiags.HasErrors() {
|
||||
return nil, diags
|
||||
}
|
||||
return schemas, diags
|
||||
|
||||
}
|
||||
return nil, diags
|
||||
}
|
@ -248,13 +248,22 @@ func (c *ImportCommand) Run(args []string) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Get schemas, if possible, before writing state
|
||||
schemas, diags := getSchemas(&c.Meta, newState, config)
|
||||
if diags.HasErrors() {
|
||||
// MBANG TODO - add warning that the schema could not be initialized
|
||||
// and therefore the JSON state can not be created and may affect
|
||||
// external applications relying on that data format
|
||||
return 1
|
||||
}
|
||||
|
||||
// Persist the final state
|
||||
log.Printf("[INFO] Writing state output to: %s", c.Meta.StateOutPath())
|
||||
if err := state.WriteState(newState); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
|
||||
return 1
|
||||
}
|
||||
if err := state.PersistState(); err != nil {
|
||||
if err := state.PersistState(schemas); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
@ -998,7 +998,7 @@ func (m *Meta) backend_C_r_s(c *configs.Backend, cHash int, sMgr *clistate.Local
|
||||
diags = diags.Append(fmt.Errorf(errBackendMigrateLocalDelete, err))
|
||||
return nil, diags
|
||||
}
|
||||
if err := localState.PersistState(); err != nil {
|
||||
if err := localState.PersistState(nil); err != nil {
|
||||
diags = diags.Append(fmt.Errorf(errBackendMigrateLocalDelete, err))
|
||||
return nil, diags
|
||||
}
|
||||
|
@ -434,11 +434,27 @@ func (m *Meta) backendMigrateState_s_s(opts *backendMigrateOpts) error {
|
||||
// includes preserving any lineage/serial information where possible, if
|
||||
// both managers support such metadata.
|
||||
log.Print("[TRACE] backendMigrateState: migration confirmed, so migrating")
|
||||
|
||||
path, err := os.Getwd()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get working directory")
|
||||
}
|
||||
|
||||
config, diags := m.loadConfig(path)
|
||||
if diags.HasErrors() {
|
||||
return diags.Err()
|
||||
}
|
||||
|
||||
schemas, diags := getSchemas(m, destination, config)
|
||||
if diags.HasErrors() {
|
||||
return diags.Err()
|
||||
}
|
||||
|
||||
if err := statemgr.Migrate(destinationState, sourceState); err != nil {
|
||||
return fmt.Errorf(strings.TrimSpace(errBackendStateCopy),
|
||||
opts.SourceType, opts.DestinationType, err)
|
||||
}
|
||||
if err := destinationState.PersistState(); err != nil {
|
||||
if err := destinationState.PersistState(schemas); err != nil {
|
||||
return fmt.Errorf(strings.TrimSpace(errBackendStateCopy),
|
||||
opts.SourceType, opts.DestinationType, err)
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ func TestMetaBackend_emptyDir(t *testing.T) {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
s.WriteState(testState())
|
||||
if err := s.PersistState(); err != nil {
|
||||
if err := s.PersistState(nil); err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
@ -134,7 +134,7 @@ func TestMetaBackend_emptyWithDefaultState(t *testing.T) {
|
||||
next := testState()
|
||||
next.RootModule().SetOutputValue("foo", cty.StringVal("bar"), false)
|
||||
s.WriteState(next)
|
||||
if err := s.PersistState(); err != nil {
|
||||
if err := s.PersistState(nil); err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
@ -205,7 +205,7 @@ func TestMetaBackend_emptyWithExplicitState(t *testing.T) {
|
||||
next := testState()
|
||||
markStateForMatching(next, "bar") // just any change so it shows as different than before
|
||||
s.WriteState(next)
|
||||
if err := s.PersistState(); err != nil {
|
||||
if err := s.PersistState(nil); err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
@ -265,7 +265,7 @@ func TestMetaBackend_configureNew(t *testing.T) {
|
||||
mark := markStateForMatching(state, "changing")
|
||||
|
||||
s.WriteState(state)
|
||||
if err := s.PersistState(); err != nil {
|
||||
if err := s.PersistState(nil); err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
@ -339,7 +339,7 @@ func TestMetaBackend_configureNewWithState(t *testing.T) {
|
||||
state = states.NewState()
|
||||
mark := markStateForMatching(state, "changing")
|
||||
|
||||
if err := statemgr.WriteAndPersist(s, state); err != nil {
|
||||
if err := statemgr.WriteAndPersist(s, state, nil); err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
@ -505,7 +505,7 @@ func TestMetaBackend_configureNewWithStateExisting(t *testing.T) {
|
||||
mark := markStateForMatching(state, "changing")
|
||||
|
||||
s.WriteState(state)
|
||||
if err := s.PersistState(); err != nil {
|
||||
if err := s.PersistState(nil); err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
@ -576,7 +576,7 @@ func TestMetaBackend_configureNewWithStateExistingNoMigrate(t *testing.T) {
|
||||
state = states.NewState()
|
||||
mark := markStateForMatching(state, "changing")
|
||||
s.WriteState(state)
|
||||
if err := s.PersistState(); err != nil {
|
||||
if err := s.PersistState(nil); err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
@ -695,7 +695,7 @@ func TestMetaBackend_configuredChange(t *testing.T) {
|
||||
mark := markStateForMatching(state, "changing")
|
||||
|
||||
s.WriteState(state)
|
||||
if err := s.PersistState(); err != nil {
|
||||
if err := s.PersistState(nil); err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
@ -1448,7 +1448,7 @@ func TestMetaBackend_configuredUnset(t *testing.T) {
|
||||
|
||||
// Write some state
|
||||
s.WriteState(testState())
|
||||
if err := s.PersistState(); err != nil {
|
||||
if err := s.PersistState(nil); err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
@ -1506,7 +1506,7 @@ func TestMetaBackend_configuredUnsetCopy(t *testing.T) {
|
||||
|
||||
// Write some state
|
||||
s.WriteState(testState())
|
||||
if err := s.PersistState(); err != nil {
|
||||
if err := s.PersistState(nil); err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
@ -1585,7 +1585,7 @@ func TestMetaBackend_planLocal(t *testing.T) {
|
||||
mark := markStateForMatching(state, "changing")
|
||||
|
||||
s.WriteState(state)
|
||||
if err := s.PersistState(); err != nil {
|
||||
if err := s.PersistState(nil); err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
@ -1686,7 +1686,7 @@ func TestMetaBackend_planLocalStatePath(t *testing.T) {
|
||||
mark := markStateForMatching(state, "changing")
|
||||
|
||||
s.WriteState(state)
|
||||
if err := s.PersistState(); err != nil {
|
||||
if err := s.PersistState(nil); err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
@ -1773,7 +1773,7 @@ func TestMetaBackend_planLocalMatch(t *testing.T) {
|
||||
mark := markStateForMatching(state, "changing")
|
||||
|
||||
s.WriteState(state)
|
||||
if err := s.PersistState(); err != nil {
|
||||
if err := s.PersistState(nil); err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
|
@ -110,20 +110,8 @@ func (c *ShowCommand) show(path string) (*plans.Plan, *statefile.File, *configs.
|
||||
|
||||
// Get schemas, if possible
|
||||
if config != nil || stateFile != nil {
|
||||
opts, err := c.contextOpts()
|
||||
if err != nil {
|
||||
diags = diags.Append(err)
|
||||
return plan, stateFile, config, schemas, diags
|
||||
}
|
||||
tfCtx, ctxDiags := terraform.NewContext(opts)
|
||||
diags = diags.Append(ctxDiags)
|
||||
if ctxDiags.HasErrors() {
|
||||
return plan, stateFile, config, schemas, diags
|
||||
}
|
||||
var schemaDiags tfdiags.Diagnostics
|
||||
schemas, schemaDiags = tfCtx.Schemas(config, stateFile.State)
|
||||
diags = diags.Append(schemaDiags)
|
||||
if schemaDiags.HasErrors() {
|
||||
schemas, diags = getSchemas(&c.Meta, stateFile.State, config)
|
||||
if diags.HasErrors() {
|
||||
return plan, stateFile, config, schemas, diags
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/addrs"
|
||||
@ -385,12 +386,31 @@ func (c *StateMvCommand) Run(args []string) int {
|
||||
return 0 // This is as far as we go in dry-run mode
|
||||
}
|
||||
|
||||
path, err := os.Getwd()
|
||||
if err != nil {
|
||||
// MBANG TODO - add warning here too?
|
||||
return 1
|
||||
}
|
||||
|
||||
config, diags := c.loadConfig(path)
|
||||
if diags.HasErrors() {
|
||||
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
||||
return 1
|
||||
}
|
||||
|
||||
schemas, diags := getSchemas(&c.Meta, stateTo, config)
|
||||
if diags.HasErrors() {
|
||||
// MBANG TODO - is this the warning?
|
||||
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Write the new state
|
||||
if err := stateToMgr.WriteState(stateTo); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
||||
return 1
|
||||
}
|
||||
if err := stateToMgr.PersistState(); err != nil {
|
||||
if err := stateToMgr.PersistState(schemas); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
||||
return 1
|
||||
}
|
||||
@ -401,7 +421,7 @@ func (c *StateMvCommand) Run(args []string) int {
|
||||
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
||||
return 1
|
||||
}
|
||||
if err := stateFromMgr.PersistState(); err != nil {
|
||||
if err := stateFromMgr.PersistState(schemas); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
||||
return 1
|
||||
}
|
||||
|
@ -126,11 +126,28 @@ func (c *StatePushCommand) Run(args []string) int {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to write state: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Get schemas, if possible, before writing state
|
||||
path, err := os.Getwd()
|
||||
if err != nil {
|
||||
return 1
|
||||
}
|
||||
config, diags := c.loadConfig(path)
|
||||
if diags.HasErrors() {
|
||||
// MBANG TODO - add warnings here?
|
||||
return 1
|
||||
}
|
||||
schemas, diags := getSchemas(&c.Meta, srcStateFile.State, config)
|
||||
if diags.HasErrors() {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to load schemas: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
if err := stateMgr.WriteState(srcStateFile.State); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to write state: %s", err))
|
||||
return 1
|
||||
}
|
||||
if err := stateMgr.PersistState(); err != nil {
|
||||
if err := stateMgr.PersistState(schemas); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to persist state: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
@ -267,7 +267,7 @@ func TestStatePush_forceRemoteState(t *testing.T) {
|
||||
if err := sMgr.WriteState(states.NewState()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := sMgr.PersistState(); err != nil {
|
||||
if err := sMgr.PersistState(nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/addrs"
|
||||
@ -160,12 +161,30 @@ func (c *StateReplaceProviderCommand) Run(args []string) int {
|
||||
resource.ProviderConfig.Provider = to
|
||||
}
|
||||
|
||||
// Get schemas, if possible, before writing state
|
||||
path, err := os.Getwd()
|
||||
if err != nil {
|
||||
return 1
|
||||
}
|
||||
|
||||
config, diags := c.loadConfig(path)
|
||||
if diags.HasErrors() {
|
||||
// MBANG TODO - add warnings here?
|
||||
return 1
|
||||
}
|
||||
|
||||
schemas, diags := getSchemas(&c.Meta, state, config)
|
||||
if diags.HasErrors() {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to load schemas: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Write the updated state
|
||||
if err := stateMgr.WriteState(state); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
||||
return 1
|
||||
}
|
||||
if err := stateMgr.PersistState(); err != nil {
|
||||
if err := stateMgr.PersistState(schemas); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
||||
return 1
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/addrs"
|
||||
@ -110,11 +111,30 @@ func (c *StateRmCommand) Run(args []string) int {
|
||||
return 0 // This is as far as we go in dry-run mode
|
||||
}
|
||||
|
||||
// Get schemas, if possible, before writing state
|
||||
path, err := os.Getwd()
|
||||
if err != nil {
|
||||
// MBANG TODO - add warnings here?
|
||||
return 1
|
||||
}
|
||||
|
||||
config, diags := c.loadConfig(path)
|
||||
if diags.HasErrors() {
|
||||
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
||||
return 1
|
||||
}
|
||||
|
||||
schemas, diags := getSchemas(&c.Meta, state, config)
|
||||
if diags.HasErrors() {
|
||||
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
||||
return 1
|
||||
}
|
||||
|
||||
if err := stateMgr.WriteState(state); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
||||
return 1
|
||||
}
|
||||
if err := stateMgr.PersistState(); err != nil {
|
||||
if err := stateMgr.PersistState(schemas); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf(errStateRmPersist, err))
|
||||
return 1
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/addrs"
|
||||
@ -125,6 +126,25 @@ func (c *TaintCommand) Run(args []string) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Get schemas, if possible, before writing state
|
||||
path, err := os.Getwd()
|
||||
if err != nil {
|
||||
// MBANG TODO - add warnings here?
|
||||
return 1
|
||||
}
|
||||
|
||||
config, diags := c.loadConfig(path)
|
||||
if diags.HasErrors() {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to load config: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
schemas, diags := getSchemas(&c.Meta, state, config)
|
||||
if diags.HasErrors() {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to load config: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
ss := state.SyncWrapper()
|
||||
|
||||
// Get the resource and instance we're going to taint
|
||||
@ -171,7 +191,7 @@ func (c *TaintCommand) Run(args []string) int {
|
||||
c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
|
||||
return 1
|
||||
}
|
||||
if err := stateMgr.PersistState(); err != nil {
|
||||
if err := stateMgr.PersistState(schemas); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/addrs"
|
||||
@ -163,6 +164,25 @@ func (c *UntaintCommand) Run(args []string) int {
|
||||
c.showDiagnostics(diags)
|
||||
return 1
|
||||
}
|
||||
|
||||
// Get schemas, if possible, before writing state
|
||||
path, err := os.Getwd()
|
||||
if err != nil {
|
||||
// MBANG TODO - add warnings here?
|
||||
return 1
|
||||
}
|
||||
|
||||
config, diags := c.loadConfig(path)
|
||||
if diags.HasErrors() {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to load config: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
schemas, diags := getSchemas(&c.Meta, state, config)
|
||||
if diags.HasErrors() {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to load config: %s", err))
|
||||
return 1
|
||||
}
|
||||
obj.Status = states.ObjectReady
|
||||
ss.SetResourceInstanceCurrent(addr, obj, rs.ProviderConfig)
|
||||
|
||||
@ -170,7 +190,7 @@ func (c *UntaintCommand) Run(args []string) int {
|
||||
c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
|
||||
return 1
|
||||
}
|
||||
if err := stateMgr.PersistState(); err != nil {
|
||||
if err := stateMgr.PersistState(schemas); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ func (c *WorkspaceNewCommand) Run(args []string) int {
|
||||
c.Ui.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
err = stateMgr.PersistState()
|
||||
err = stateMgr.PersistState(nil)
|
||||
if err != nil {
|
||||
c.Ui.Error(err.Error())
|
||||
return 1
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"github.com/hashicorp/terraform/internal/states"
|
||||
"github.com/hashicorp/terraform/internal/states/statefile"
|
||||
"github.com/hashicorp/terraform/internal/states/statemgr"
|
||||
"github.com/hashicorp/terraform/internal/terraform"
|
||||
)
|
||||
|
||||
// State implements the State interfaces in the state package to handle
|
||||
@ -153,7 +154,7 @@ func (s *State) refreshState() error {
|
||||
}
|
||||
|
||||
// statemgr.Persister impl.
|
||||
func (s *State) PersistState() error {
|
||||
func (s *State) PersistState(schemas *terraform.Schemas) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
|
@ -37,7 +37,7 @@ func TestStateRace(t *testing.T) {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
s.WriteState(current)
|
||||
s.PersistState()
|
||||
s.PersistState(nil)
|
||||
s.RefreshState()
|
||||
}()
|
||||
}
|
||||
@ -252,7 +252,7 @@ func TestStatePersist(t *testing.T) {
|
||||
if err := mgr.WriteState(s); err != nil {
|
||||
t.Fatalf("failed to WriteState for %q: %s", tc.name, err)
|
||||
}
|
||||
if err := mgr.PersistState(); err != nil {
|
||||
if err := mgr.PersistState(nil); err != nil {
|
||||
t.Fatalf("failed to PersistState for %q: %s", tc.name, err)
|
||||
}
|
||||
|
||||
@ -447,7 +447,7 @@ func TestWriteStateForMigration(t *testing.T) {
|
||||
// At this point we should just do a normal write and persist
|
||||
// as would happen from the CLI
|
||||
mgr.WriteState(mgr.State())
|
||||
mgr.PersistState()
|
||||
mgr.PersistState(nil)
|
||||
|
||||
if logIdx >= len(mockClient.log) {
|
||||
t.Fatalf("request lock and index are out of sync on %q: idx=%d len=%d", tc.name, logIdx, len(mockClient.log))
|
||||
@ -611,7 +611,7 @@ func TestWriteStateForMigrationWithForcePushClient(t *testing.T) {
|
||||
// At this point we should just do a normal write and persist
|
||||
// as would happen from the CLI
|
||||
mgr.WriteState(mgr.State())
|
||||
mgr.PersistState()
|
||||
mgr.PersistState(nil)
|
||||
|
||||
if logIdx >= len(mockClient.log) {
|
||||
t.Fatalf("request lock and index are out of sync on %q: idx=%d len=%d", tc.name, logIdx, len(mockClient.log))
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
|
||||
"github.com/hashicorp/terraform/internal/states"
|
||||
"github.com/hashicorp/terraform/internal/states/statefile"
|
||||
"github.com/hashicorp/terraform/internal/terraform"
|
||||
)
|
||||
|
||||
// Filesystem is a full state manager that uses a file in the local filesystem
|
||||
@ -223,7 +224,7 @@ func (s *Filesystem) writeState(state *states.State, meta *SnapshotMeta) error {
|
||||
|
||||
// PersistState is an implementation of Persister that does nothing because
|
||||
// this type's Writer implementation does its own persistence.
|
||||
func (s *Filesystem) PersistState() error {
|
||||
func (s *Filesystem) PersistState(schemas *terraform.Schemas) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ package statemgr
|
||||
import (
|
||||
"github.com/hashicorp/terraform/internal/states"
|
||||
"github.com/hashicorp/terraform/internal/states/statefile"
|
||||
"github.com/hashicorp/terraform/internal/terraform"
|
||||
"github.com/hashicorp/terraform/version"
|
||||
)
|
||||
|
||||
@ -44,10 +45,10 @@ func RefreshAndRead(mgr Storage) (*states.State, error) {
|
||||
// out quickly with a user-facing error. In situations where more control
|
||||
// is required, call WriteState and PersistState on the state manager directly
|
||||
// and handle their errors.
|
||||
func WriteAndPersist(mgr Storage, state *states.State) error {
|
||||
func WriteAndPersist(mgr Storage, state *states.State, schemas *terraform.Schemas) error {
|
||||
err := mgr.WriteState(state)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return mgr.PersistState()
|
||||
return mgr.PersistState(schemas)
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
package statemgr
|
||||
|
||||
import "github.com/hashicorp/terraform/internal/states"
|
||||
import (
|
||||
"github.com/hashicorp/terraform/internal/states"
|
||||
"github.com/hashicorp/terraform/internal/terraform"
|
||||
)
|
||||
|
||||
// LockDisabled implements State and Locker but disables state locking.
|
||||
// If State doesn't support locking, this is a no-op. This is useful for
|
||||
@ -27,8 +30,8 @@ func (s *LockDisabled) RefreshState() error {
|
||||
return s.Inner.RefreshState()
|
||||
}
|
||||
|
||||
func (s *LockDisabled) PersistState() error {
|
||||
return s.Inner.PersistState()
|
||||
func (s *LockDisabled) PersistState(schemas *terraform.Schemas) error {
|
||||
return s.Inner.PersistState(schemas)
|
||||
}
|
||||
|
||||
func (s *LockDisabled) Lock(info *LockInfo) (string, error) {
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
version "github.com/hashicorp/go-version"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/states"
|
||||
"github.com/hashicorp/terraform/internal/terraform"
|
||||
)
|
||||
|
||||
// Persistent is a union of the Refresher and Persistent interfaces, for types
|
||||
@ -72,8 +73,12 @@ type Refresher interface {
|
||||
// is most commonly achieved by making use of atomic write capabilities on
|
||||
// the remote storage backend in conjunction with book-keeping with the
|
||||
// Serial and Lineage fields in the standard state file formats.
|
||||
//
|
||||
// Some implementations may optionally utilize config schema to persist
|
||||
// state. For example, when representing state in an external JSON
|
||||
// representation.
|
||||
type Persister interface {
|
||||
PersistState() error
|
||||
PersistState(*terraform.Schemas) error
|
||||
}
|
||||
|
||||
// PersistentMeta is an optional extension to Persistent that allows inspecting
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/states"
|
||||
"github.com/hashicorp/terraform/internal/terraform"
|
||||
)
|
||||
|
||||
// NewFullFake returns a full state manager that really only supports transient
|
||||
@ -61,7 +62,7 @@ func (m *fakeFull) RefreshState() error {
|
||||
return m.t.WriteState(m.fakeP.State())
|
||||
}
|
||||
|
||||
func (m *fakeFull) PersistState() error {
|
||||
func (m *fakeFull) PersistState(schemas *terraform.Schemas) error {
|
||||
return m.fakeP.WriteState(m.t.State())
|
||||
}
|
||||
|
||||
@ -127,7 +128,7 @@ func (m *fakeErrorFull) RefreshState() error {
|
||||
return errors.New("fake state manager error")
|
||||
}
|
||||
|
||||
func (m *fakeErrorFull) PersistState() error {
|
||||
func (m *fakeErrorFull) PersistState(schemas *terraform.Schemas) error {
|
||||
return errors.New("fake state manager error")
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ func TestFull(t *testing.T, s Full) {
|
||||
}
|
||||
|
||||
// Test persistence
|
||||
if err := s.PersistState(); err != nil {
|
||||
if err := s.PersistState(nil); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
@ -81,7 +81,7 @@ func TestFull(t *testing.T, s Full) {
|
||||
if err := s.WriteState(current); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if err := s.PersistState(); err != nil {
|
||||
if err := s.PersistState(nil); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
@ -104,7 +104,7 @@ func TestFull(t *testing.T, s Full) {
|
||||
if err := s.WriteState(current); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if err := s.PersistState(); err != nil {
|
||||
if err := s.PersistState(nil); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ type Reader interface {
|
||||
// since the caller may continue to modify the given state object after
|
||||
// WriteState returns.
|
||||
type Writer interface {
|
||||
// Write state saves a transient snapshot of the given state.
|
||||
// WriteState saves a transient snapshot of the given state.
|
||||
//
|
||||
// The caller must ensure that the given state object is not concurrently
|
||||
// modified while a WriteState call is in progress. WriteState itself
|
||||
|
Loading…
Reference in New Issue
Block a user