opentofu/states/statemgr/statemgr_fake.go
Martin Atkins 53cafc542b statemgr: New package for state managers
This idea of a "state manager" was previously modelled via the
confusingly-named state.State interface, which we've been calling a "state
manager" only in some local variable names in situations where there were
also *terraform.State variables.

As part of reworking our state models to make room for the new type
system, we also need to change what was previously the state.StateReader
interface. Since we've found the previous organization confusing anyway,
here we just copy all of those interfaces over into statemgr where we can
make the relationship to states.State hopefully a little clearer.

This is not yet a complete move of the functionality from "state", since
we're not yet ready to break existing callers. In a future commit we'll
turn the interfaces in the old "state" package into aliases of the
interfaces in this package, and update all the implementers of what will
by then be statemgr.Reader to use *states.State instead of
*terraform.State.

This also includes an adaptation of what was previously state.LocalState
into statemgr.FileSystem, using the new state serialization functionality
from package statefile instead of the old terraform.ReadState and
terraform.WriteState.
2018-10-16 18:49:20 -07:00

97 lines
2.2 KiB
Go

package statemgr
import (
"errors"
"sync"
"github.com/hashicorp/terraform/states"
)
// NewFullFake returns a full state manager that really only supports transient
// snapshots. This is primarily intended for testing and is not suitable for
// general use.
//
// The persistent part of the interface is stubbed out as an in-memory store,
// and so its snapshots are effectively also transient.
//
// The given Transient implementation is used to implement the transient
// portion of the interface. If nil is given, NewTransientInMemory is
// automatically called to create an in-memory transient manager with no
// initial transient snapshot.
//
// If the given initial state is non-nil then a copy of it will be used as
// the initial persistent snapshot.
//
// The Locker portion of the returned manager uses a local mutex to simulate
// mutually-exclusive access to the fake persistent portion of the object.
func NewFullFake(t Transient, initial *states.State) Full {
if t == nil {
t = NewTransientInMemory(nil)
}
// The "persistent" part of our manager is actually just another in-memory
// transient used to fake a secondary storage layer.
fakeP := NewTransientInMemory(initial.DeepCopy())
return &fakeFull{
t: t,
fakeP: fakeP,
}
}
type fakeFull struct {
t Transient
fakeP Transient
lockLock sync.Mutex
locked bool
}
var _ Full = (*fakeFull)(nil)
func (m *fakeFull) State() *states.State {
return m.t.State()
}
func (m *fakeFull) WriteState(s *states.State) error {
return m.t.WriteState(s)
}
func (m *fakeFull) RefreshState() error {
return m.t.WriteState(m.fakeP.State())
}
func (m *fakeFull) PersistState() error {
return m.fakeP.WriteState(m.t.State())
}
func (m *fakeFull) Lock(info *LockInfo) (string, error) {
m.lockLock.Lock()
defer m.lockLock.Unlock()
if m.locked {
return "", &LockError{
Err: errors.New("fake state manager is locked"),
Info: info,
}
}
m.locked = true
return "placeholder", nil
}
func (m *fakeFull) Unlock(id string) error {
m.lockLock.Lock()
defer m.lockLock.Unlock()
if !m.locked {
return errors.New("fake state manager is not locked")
}
if id != "placeholder" {
return errors.New("wrong lock id for fake state manager")
}
m.locked = false
return nil
}