state: only change serial if changed
This commit is contained in:
parent
bfe0edef51
commit
c2bf600603
|
@ -104,6 +104,8 @@ func (s *CacheState) RefreshState() error {
|
||||||
s.refreshResult = CacheRefreshNoop
|
s.refreshResult = CacheRefreshNoop
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cached = durable
|
||||||
}
|
}
|
||||||
|
|
||||||
s.state = cached
|
s.state = cached
|
||||||
|
|
|
@ -18,6 +18,7 @@ func (s *InmemState) RefreshState() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *InmemState) WriteState(state *terraform.State) error {
|
func (s *InmemState) WriteState(state *terraform.State) error {
|
||||||
|
state.IncrementSerialMaybe(s.state)
|
||||||
s.state = state
|
s.state = state
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,13 +15,15 @@ type LocalState struct {
|
||||||
Path string
|
Path string
|
||||||
PathOut string
|
PathOut string
|
||||||
|
|
||||||
state *terraform.State
|
state *terraform.State
|
||||||
written bool
|
readState *terraform.State
|
||||||
|
written bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetState will force a specific state in-memory for this local state.
|
// SetState will force a specific state in-memory for this local state.
|
||||||
func (s *LocalState) SetState(state *terraform.State) {
|
func (s *LocalState) SetState(state *terraform.State) {
|
||||||
s.state = state
|
s.state = state
|
||||||
|
s.readState = state
|
||||||
}
|
}
|
||||||
|
|
||||||
// StateReader impl.
|
// StateReader impl.
|
||||||
|
@ -61,6 +63,9 @@ func (s *LocalState) WriteState(state *terraform.State) error {
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
|
s.state.IncrementSerialMaybe(s.readState)
|
||||||
|
s.readState = s.state
|
||||||
|
|
||||||
if err := terraform.WriteState(s.state, f); err != nil {
|
if err := terraform.WriteState(s.state, f); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -105,5 +110,6 @@ func (s *LocalState) RefreshState() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
s.state = state
|
s.state = state
|
||||||
|
s.readState = state
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,7 @@ func TestState(t *testing.T, s interface{}) {
|
||||||
current := TestStateInitial()
|
current := TestStateInitial()
|
||||||
|
|
||||||
// Check that the initial state is correct
|
// Check that the initial state is correct
|
||||||
state := reader.State()
|
if state := reader.State(); !reflect.DeepEqual(state, current) {
|
||||||
current.Serial = state.Serial
|
|
||||||
if !reflect.DeepEqual(state, current) {
|
|
||||||
t.Fatalf("not initial: %#v\n\n%#v", state, current)
|
t.Fatalf("not initial: %#v\n\n%#v", state, current)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,11 +65,49 @@ func TestState(t *testing.T, s interface{}) {
|
||||||
|
|
||||||
// Just set the serials the same... Then compare.
|
// Just set the serials the same... Then compare.
|
||||||
actual := reader.State()
|
actual := reader.State()
|
||||||
actual.Serial = current.Serial
|
|
||||||
if !reflect.DeepEqual(actual, current) {
|
if !reflect.DeepEqual(actual, current) {
|
||||||
t.Fatalf("bad: %#v\n\n%#v", actual, current)
|
t.Fatalf("bad: %#v\n\n%#v", actual, current)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we can write and persist then verify that the serial
|
||||||
|
// is only implemented on change.
|
||||||
|
writer, writeOk := s.(StateWriter)
|
||||||
|
persister, persistOk := s.(StatePersister)
|
||||||
|
if writeOk && persistOk {
|
||||||
|
// Same serial
|
||||||
|
serial := current.Serial
|
||||||
|
if err := writer.WriteState(current); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
if err := persister.PersistState(); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if reader.State().Serial != serial {
|
||||||
|
t.Fatalf("bad: expected %d, got %d", serial, reader.State().Serial)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change the serial
|
||||||
|
currentCopy := *current
|
||||||
|
current = ¤tCopy
|
||||||
|
current.Modules = []*terraform.ModuleState{
|
||||||
|
&terraform.ModuleState{
|
||||||
|
Path: []string{"root", "somewhere"},
|
||||||
|
Outputs: map[string]string{"serialCheck": "true"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err := writer.WriteState(current); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
if err := persister.PersistState(); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if reader.State().Serial <= serial {
|
||||||
|
t.Fatalf("bad: expected %d, got %d", serial, reader.State().Serial)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestStateInitial is the initial state that a State should have
|
// TestStateInitial is the initial state that a State should have
|
||||||
|
|
|
@ -161,6 +161,11 @@ func (s *State) RootModule() *ModuleState {
|
||||||
|
|
||||||
// Equal tests if one state is equal to another.
|
// Equal tests if one state is equal to another.
|
||||||
func (s *State) Equal(other *State) bool {
|
func (s *State) Equal(other *State) bool {
|
||||||
|
// If one is nil, we do a direct check
|
||||||
|
if s == nil || other == nil {
|
||||||
|
return s == other
|
||||||
|
}
|
||||||
|
|
||||||
// If the versions are different, they're certainly not equal
|
// If the versions are different, they're certainly not equal
|
||||||
if s.Version != other.Version {
|
if s.Version != other.Version {
|
||||||
return false
|
return false
|
||||||
|
@ -183,6 +188,14 @@ func (s *State) Equal(other *State) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IncrementSerialMaybe increments the serial number of this state
|
||||||
|
// if it different from the other state.
|
||||||
|
func (s *State) IncrementSerialMaybe(other *State) {
|
||||||
|
if !s.Equal(other) {
|
||||||
|
s.Serial++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *State) init() {
|
func (s *State) init() {
|
||||||
if s.Version == 0 {
|
if s.Version == 0 {
|
||||||
s.Version = StateVersion
|
s.Version = StateVersion
|
||||||
|
@ -951,9 +964,6 @@ func WriteState(d *State, dst io.Writer) error {
|
||||||
// Ensure the version is set
|
// Ensure the version is set
|
||||||
d.Version = StateVersion
|
d.Version = StateVersion
|
||||||
|
|
||||||
// Always increment the serial number
|
|
||||||
d.Serial++
|
|
||||||
|
|
||||||
// Encode the data in a human-friendly way
|
// Encode the data in a human-friendly way
|
||||||
data, err := json.MarshalIndent(d, "", " ")
|
data, err := json.MarshalIndent(d, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -537,15 +537,6 @@ func TestReadWriteState(t *testing.T) {
|
||||||
t.Fatalf("bad version number: %d", state.Version)
|
t.Fatalf("bad version number: %d", state.Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify the serial number is incremented
|
|
||||||
if state.Serial != 10 {
|
|
||||||
t.Fatalf("bad serial: %d", state.Serial)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the changes or the checksum will fail
|
|
||||||
state.Version = 0
|
|
||||||
state.Serial = 9
|
|
||||||
|
|
||||||
// Checksum after the write
|
// Checksum after the write
|
||||||
chksumAfter := checksumStruct(t, state)
|
chksumAfter := checksumStruct(t, state)
|
||||||
if chksumAfter != chksum {
|
if chksumAfter != chksum {
|
||||||
|
@ -557,10 +548,6 @@ func TestReadWriteState(t *testing.T) {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify the changes came through
|
|
||||||
state.Version = StateVersion
|
|
||||||
state.Serial = 10
|
|
||||||
|
|
||||||
// ReadState should not restore sensitive information!
|
// ReadState should not restore sensitive information!
|
||||||
mod := state.RootModule()
|
mod := state.RootModule()
|
||||||
mod.Resources["foo"].Primary.Ephemeral = EphemeralState{}
|
mod.Resources["foo"].Primary.Ephemeral = EphemeralState{}
|
||||||
|
|
Loading…
Reference in New Issue