From 2dff41167908da983a23a2eebe82fa6624b4f0b4 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 18 Jun 2014 20:54:22 -0700 Subject: [PATCH] terraform: read/write state to reader/writer --- terraform/state.go | 47 +++++++++++++++++++++++++++++++++++++++++ terraform/state_test.go | 25 ++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/terraform/state.go b/terraform/state.go index 011a808fc..f99156736 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -2,7 +2,10 @@ package terraform import ( "bytes" + "encoding/gob" + "errors" "fmt" + "io" "sync" "github.com/hashicorp/terraform/config" @@ -38,6 +41,50 @@ func (s *State) String() string { return buf.String() } +// The format byte is prefixed into the state file format so that we have +// the ability in the future to change the file format if we want for any +// reason. +const stateFormatByte byte = 1 + +// ReadState reads a state structure out of a reader in the format that +// was written by WriteState. +func ReadState(src io.Reader) (*State, error) { + var result *State + + var formatByte [1]byte + n, err := src.Read(formatByte[:]) + if err != nil { + return nil, err + } + if n != len(formatByte) { + return nil, errors.New("failed to read state version byte") + } + + if formatByte[0] != stateFormatByte { + return nil, fmt.Errorf("unknown state file version: %d", formatByte[0]) + } + + dec := gob.NewDecoder(src) + if err := dec.Decode(&result); err != nil { + return nil, err + } + + return result, nil +} + +// WriteState writes a state somewhere in a binary format. +func WriteState(d *State, dst io.Writer) error { + n, err := dst.Write([]byte{stateFormatByte}) + if err != nil { + return err + } + if n != 1 { + return errors.New("failed to write state version byte") + } + + return gob.NewEncoder(dst).Encode(d) +} + // ResourceState holds the state of a resource that is used so that // a provider can find and manage an existing resource as well as for // storing attributes that are uesd to populate variables of child diff --git a/terraform/state_test.go b/terraform/state_test.go index 44b8d3e4e..60d966eaf 100644 --- a/terraform/state_test.go +++ b/terraform/state_test.go @@ -1,6 +1,7 @@ package terraform import ( + "bytes" "reflect" "testing" @@ -64,3 +65,27 @@ func TestResourceState_MergeDiff_nil(t *testing.T) { t.Fatalf("bad: %#v", rs2.Attributes) } } + +func TestReadWriteState(t *testing.T) { + state := &State{ + Resources: map[string]*ResourceState{ + "foo": &ResourceState{ + ID: "bar", + }, + }, + } + + buf := new(bytes.Buffer) + if err := WriteState(state, buf); err != nil { + t.Fatalf("err: %s", err) + } + + actual, err := ReadState(buf) + if err != nil { + t.Fatalf("err: %s", err) + } + + if !reflect.DeepEqual(actual, state) { + t.Fatalf("bad: %#v", actual) + } +}