github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/terraform/state_v1_test.go (about) 1 package terraform 2 3 import ( 4 "bytes" 5 "encoding/gob" 6 "errors" 7 "io" 8 "reflect" 9 "sync" 10 "testing" 11 ) 12 13 func TestReadWriteStateV1(t *testing.T) { 14 state := &StateV1{ 15 Resources: map[string]*ResourceStateV1{ 16 "foo": &ResourceStateV1{ 17 ID: "bar", 18 ConnInfo: map[string]string{ 19 "type": "ssh", 20 "user": "root", 21 "password": "supersecret", 22 }, 23 }, 24 }, 25 } 26 27 // Checksum before the write 28 chksum := checksumStruct(t, state) 29 30 buf := new(bytes.Buffer) 31 if err := testWriteStateV1(state, buf); err != nil { 32 t.Fatalf("err: %s", err) 33 } 34 35 // Checksum after the write 36 chksumAfter := checksumStruct(t, state) 37 if chksumAfter != chksum { 38 t.Fatalf("structure changed during serialization!") 39 } 40 41 actual, err := ReadStateV1(buf) 42 if err != nil { 43 t.Fatalf("err: %s", err) 44 } 45 46 // ReadState should not restore sensitive information! 47 state.Resources["foo"].ConnInfo = nil 48 49 if !reflect.DeepEqual(actual, state) { 50 t.Fatalf("bad: %#v", actual) 51 } 52 } 53 54 // sensitiveState is used to store sensitive state information 55 // that should not be serialized. This is only used temporarily 56 // and is restored into the state. 57 type sensitiveState struct { 58 ConnInfo map[string]map[string]string 59 60 once sync.Once 61 } 62 63 func (s *sensitiveState) init() { 64 s.once.Do(func() { 65 s.ConnInfo = make(map[string]map[string]string) 66 }) 67 } 68 69 // testWriteStateV1 writes a state somewhere in a binary format. 70 // Only for testing now 71 func testWriteStateV1(d *StateV1, dst io.Writer) error { 72 // Write the magic bytes so we can determine the file format later 73 n, err := dst.Write([]byte(stateFormatMagic)) 74 if err != nil { 75 return err 76 } 77 if n != len(stateFormatMagic) { 78 return errors.New("failed to write state format magic bytes") 79 } 80 81 // Write a version byte so we can iterate on version at some point 82 n, err = dst.Write([]byte{stateFormatVersion}) 83 if err != nil { 84 return err 85 } 86 if n != 1 { 87 return errors.New("failed to write state version byte") 88 } 89 90 // Prevent sensitive information from being serialized 91 sensitive := &sensitiveState{} 92 sensitive.init() 93 for name, r := range d.Resources { 94 if r.ConnInfo != nil { 95 sensitive.ConnInfo[name] = r.ConnInfo 96 r.ConnInfo = nil 97 } 98 } 99 100 // Serialize the state 101 err = gob.NewEncoder(dst).Encode(d) 102 103 // Restore the state 104 for name, info := range sensitive.ConnInfo { 105 d.Resources[name].ConnInfo = info 106 } 107 108 return err 109 }