mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-28 01:41:48 -06:00
a3403f2766
Due to how often the state and plan types are referenced throughout Terraform, there isn't a great way to switch them out gradually. As a consequence, this huge commit gets us from the old world to a _compilable_ new world, but still has a large number of known test failures due to key functionality being stubbed out. The stubs here are for anything that interacts with providers, since we now need to do the follow-up work to similarly replace the old terraform.ResourceProvider interface with its replacement in the new "providers" package. That work, along with work to fix the remaining failing tests, will follow in subsequent commits. The aim here was to replace all references to terraform.State and its downstream types with states.State, terraform.Plan with plans.Plan, state.State with statemgr.State, and switch to the new implementations of the state and plan file formats. However, due to the number of times those types are used, this also ended up affecting numerous other parts of core such as terraform.Hook, the backend.Backend interface, and most of the CLI commands. Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize in advance to the person who inevitably just found this huge commit while spelunking through the commit history.
72 lines
2.7 KiB
Go
72 lines
2.7 KiB
Go
package statemgr
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/hashicorp/terraform/states"
|
|
"github.com/hashicorp/terraform/states/statefile"
|
|
)
|
|
|
|
// PlannedStateUpdate is a special helper to obtain a statefile representation
|
|
// of a not-yet-written state snapshot that can be written later by a call
|
|
// to the companion function WritePlannedStateUpdate.
|
|
//
|
|
// The statefile object returned here has an unusual interpretation of its
|
|
// metadata that is understood only by WritePlannedStateUpdate, and so the
|
|
// returned object should not be used for any other purpose.
|
|
//
|
|
// If the state manager implements Locker then it is the caller's
|
|
// responsibility to hold the lock at least for the duration of this call.
|
|
// It is not safe to modify the given state concurrently while
|
|
// PlannedStateUpdate is running.
|
|
func PlannedStateUpdate(mgr Transient, planned *states.State) *statefile.File {
|
|
ret := &statefile.File{
|
|
State: planned.DeepCopy(),
|
|
}
|
|
|
|
// If the given manager uses snapshot metadata then we'll save that
|
|
// in our file so we can check it again during WritePlannedStateUpdate.
|
|
if mr, ok := mgr.(PersistentMeta); ok {
|
|
m := mr.StateSnapshotMeta()
|
|
ret.Lineage = m.Lineage
|
|
ret.Serial = m.Serial
|
|
}
|
|
|
|
return ret
|
|
}
|
|
|
|
// WritePlannedStateUpdate is a companion to PlannedStateUpdate that attempts
|
|
// to apply a state update that was planned earlier to the given state
|
|
// manager.
|
|
//
|
|
// An error is returned if this function detects that a new state snapshot
|
|
// has been written to the backend since the update was planned, since that
|
|
// invalidates the plan. An error is returned also if the manager itself
|
|
// rejects the given state when asked to store it.
|
|
//
|
|
// If the returned error is nil, the given manager's transient state snapshot
|
|
// is updated to match what was planned. It is the caller's responsibility
|
|
// to then persist that state if the manager also implements Persistent and
|
|
// the snapshot should be written to the persistent store.
|
|
//
|
|
// If the state manager implements Locker then it is the caller's
|
|
// responsibility to hold the lock at least for the duration of this call.
|
|
func WritePlannedStateUpdate(mgr Transient, planned *statefile.File) error {
|
|
// If the given manager uses snapshot metadata then we'll check to make
|
|
// sure no new snapshots have been created since we planned to write
|
|
// the given state file.
|
|
if mr, ok := mgr.(PersistentMeta); ok {
|
|
m := mr.StateSnapshotMeta()
|
|
if planned.Lineage != "" {
|
|
if planned.Lineage != m.Lineage {
|
|
return fmt.Errorf("planned state update is from an unrelated state lineage than the current state")
|
|
}
|
|
if planned.Serial != m.Serial {
|
|
return fmt.Errorf("stored state has been changed by another operation since the given update was planned")
|
|
}
|
|
}
|
|
}
|
|
|
|
return mgr.WriteState(planned.State)
|
|
}
|