From f7b1299a9f90ed6570b5797ddf1d178c6d16b96b Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Thu, 4 Dec 2014 17:47:49 -0800 Subject: [PATCH] remote: working on atlas remote backend --- remote/atlas.go | 16 +++---- remote/atlas_test.go | 104 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 109 insertions(+), 11 deletions(-) diff --git a/remote/atlas.go b/remote/atlas.go index c600942d5..c59f4944d 100644 --- a/remote/atlas.go +++ b/remote/atlas.go @@ -32,7 +32,7 @@ func NewAtlasRemoteClient(conf map[string]string) (*AtlasRemoteClient, error) { if err := client.validateConfig(conf); err != nil { return nil, err } - return nil, nil + return client, nil } func (c *AtlasRemoteClient) validateConfig(conf map[string]string) error { @@ -53,14 +53,14 @@ func (c *AtlasRemoteClient) validateConfig(conf map[string]string) error { } c.accessToken = token - name, ok := conf["access_token"] + name, ok := conf["name"] if !ok || name == "" { return fmt.Errorf("missing 'name' configuration") } parts := strings.Split(name, "/") if len(parts) != 2 { - return fmt.Errorf("malformed slug '%s'", name) + return fmt.Errorf("malformed name '%s'", name) } c.user = parts[0] c.name = parts[1] @@ -69,7 +69,7 @@ func (c *AtlasRemoteClient) validateConfig(conf map[string]string) error { func (c *AtlasRemoteClient) GetState() (*RemoteStatePayload, error) { // Make the HTTP request - req, err := http.NewRequest("GET", c.url("show").String(), nil) + req, err := http.NewRequest("GET", c.url().String(), nil) if err != nil { return nil, fmt.Errorf("Failed to make HTTP request: %v", err) } @@ -129,7 +129,7 @@ func (c *AtlasRemoteClient) GetState() (*RemoteStatePayload, error) { func (c *AtlasRemoteClient) PutState(state []byte, force bool) error { // Get the target URL - base := c.url("update") + base := c.url() // Generate the MD5 hash := md5.Sum(state) @@ -181,7 +181,7 @@ func (c *AtlasRemoteClient) PutState(state []byte, force bool) error { func (c *AtlasRemoteClient) DeleteState() error { // Make the HTTP request - req, err := http.NewRequest("DELETE", c.url("destroy").String(), nil) + req, err := http.NewRequest("DELETE", c.url().String(), nil) if err != nil { return fmt.Errorf("Failed to make HTTP request: %v", err) } @@ -213,11 +213,11 @@ func (c *AtlasRemoteClient) DeleteState() error { return nil } -func (c *AtlasRemoteClient) url(route string) *url.URL { +func (c *AtlasRemoteClient) url() *url.URL { return &url.URL{ Scheme: c.serverURL.Scheme, Host: c.serverURL.Host, - Path: path.Join("api/v1/state", c.user, c.name, route), + Path: path.Join("api/v1/state", c.user, c.name), RawQuery: fmt.Sprintf("access_token=%s", c.accessToken), } } diff --git a/remote/atlas_test.go b/remote/atlas_test.go index be8e02fe2..7dc816541 100644 --- a/remote/atlas_test.go +++ b/remote/atlas_test.go @@ -1,6 +1,13 @@ package remote -import "testing" +import ( + "bytes" + "crypto/md5" + "os" + "testing" + + "github.com/hashicorp/terraform/terraform" +) func TestAtlasRemote_Interface(t *testing.T) { var client interface{} = &AtlasRemoteClient{} @@ -9,6 +16,97 @@ func TestAtlasRemote_Interface(t *testing.T) { } } -func TestAtlasRemote(t *testing.T) { - // TODO +func checkAtlas(t *testing.T) { + if os.Getenv("ATLAS_TOKEN") == "" { + t.SkipNow() + } +} + +func TestAtlasRemote_Validate(t *testing.T) { + conf := map[string]string{} + if _, err := NewAtlasRemoteClient(conf); err == nil { + t.Fatalf("expect error") + } + + conf["access_token"] = "test" + conf["name"] = "hashicorp/test-state" + if _, err := NewAtlasRemoteClient(conf); err != nil { + t.Fatalf("err: %v", err) + } +} + +func TestAtlasRemote(t *testing.T) { + checkAtlas(t) + remote := &terraform.RemoteState{ + Type: "atlas", + Config: map[string]string{ + "access_token": os.Getenv("ATLAS_TOKEN"), + "name": "hashicorp/test-remote-state", + }, + } + r, err := NewClientByState(remote) + if err != nil { + t.Fatalf("Err: %v", err) + } + + // Get a valid input + inp, err := blankState(remote) + if err != nil { + t.Fatalf("Err: %v", err) + } + inpMD5 := md5.Sum(inp) + hash := inpMD5[:16] + + // Delete the state, should be none + err = r.DeleteState() + if err != nil { + t.Fatalf("err: %v", err) + } + + // Ensure no state + payload, err := r.GetState() + if err != nil { + t.Fatalf("Err: %v", err) + } + if payload != nil { + t.Fatalf("unexpected payload") + } + + // Put the state + err = r.PutState(inp, false) + if err != nil { + t.Fatalf("err: %v", err) + } + + // Get it back + payload, err = r.GetState() + if err != nil { + t.Fatalf("Err: %v", err) + } + if payload != nil { + t.Fatalf("unexpected payload") + } + + // Check the payload + if !bytes.Equal(payload.State, inp) { + t.Fatalf("bad response: %v", payload) + } + if !bytes.Equal(payload.MD5, hash) { + t.Fatalf("bad response: %v", payload) + } + + // Delete the state + err = r.DeleteState() + if err != nil { + t.Fatalf("err: %v", err) + } + + // Should be gone + payload, err = r.GetState() + if err != nil { + t.Fatalf("Err: %v", err) + } + if payload != nil { + t.Fatalf("unexpected payload") + } }