Start work on backups :monkey:
diff --git a/rackspace/db/v1/backups/doc.go b/rackspace/db/v1/backups/doc.go
new file mode 100644
index 0000000..b000aa0
--- /dev/null
+++ b/rackspace/db/v1/backups/doc.go
@@ -0,0 +1 @@
+package backups
diff --git a/rackspace/db/v1/backups/fixtures.go b/rackspace/db/v1/backups/fixtures.go
new file mode 100644
index 0000000..92b9c08
--- /dev/null
+++ b/rackspace/db/v1/backups/fixtures.go
@@ -0,0 +1,86 @@
+package backups
+
+import (
+ "fmt"
+ "net/http"
+ "testing"
+
+ th "github.com/rackspace/gophercloud/testhelper"
+ "github.com/rackspace/gophercloud/testhelper/client"
+)
+
+func SetupHandler(t *testing.T, url, method, requestBody, responseBody string, status int) {
+ th.Mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, method)
+ th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+
+ if requestBody != "" {
+ th.TestJSONRequest(t, r, requestBody)
+ }
+
+ if responseBody != "" {
+ w.Header().Add("Content-Type", "application/json")
+ }
+
+ w.WriteHeader(status)
+
+ if responseBody != "" {
+ fmt.Fprintf(w, responseBody)
+ }
+ })
+}
+
+func HandleCreateSuccessfully(t *testing.T) {
+ requestJSON := `
+{
+ "backup": {
+ "description": "My Backup",
+ "instance": "d4603f69-ec7e-4e9b-803f-600b9205576f",
+ "name": "snapshot"
+ }
+}
+`
+
+ responseJSON := `
+{
+ "backup": {
+ "created": "2014-02-13T21:47:16",
+ "description": "My Backup",
+ "id": "61f12fef-edb1-4561-8122-e7c00ef26a82",
+ "instance_id": "d4603f69-ec7e-4e9b-803f-600b9205576f",
+ "locationRef": null,
+ "name": "snapshot",
+ "parent_id": null,
+ "size": 100,
+ "status": "NEW",
+ "updated": "2014-02-13T21:47:16"
+ }
+}
+`
+
+ SetupHandler(t, "/backups", "POST", requestJSON, responseJSON, 202)
+}
+
+func HandleListSuccessfully(t *testing.T) {
+ responseJSON := `
+{
+ "backups": [
+ {
+ "status": "COMPLETED",
+ "updated": "2014-06-18T21:24:39",
+ "description": "Backup from Restored Instance",
+
+ "id": "87972694-4be2-40f5-83f8-501656e0032a",
+ "size": 0.141026,
+ "name": "restored_backup",
+ "created": "2014-06-18T21:23:35",
+ "instance_id": "29af2cd9-0674-48ab-b87a-b160f00208e6",
+ "parent_id": null,
+ "locationRef": "http://localhost/path/to/backup"
+ }
+ ]
+}
+`
+
+ SetupHandler(t, "/backups", "GET", "", responseJSON, 200)
+}
diff --git a/rackspace/db/v1/backups/requests.go b/rackspace/db/v1/backups/requests.go
new file mode 100644
index 0000000..7bc14ff
--- /dev/null
+++ b/rackspace/db/v1/backups/requests.go
@@ -0,0 +1,117 @@
+package backups
+
+import (
+ "errors"
+
+ "github.com/racker/perigee"
+ "github.com/rackspace/gophercloud"
+ "github.com/rackspace/gophercloud/pagination"
+)
+
+type CreateOptsBuilder interface {
+ ToBackupCreateMap() (map[string]interface{}, error)
+}
+
+type CreateOpts struct {
+ Name string
+
+ InstanceID string
+
+ Description string
+}
+
+func (opts CreateOpts) ToBackupCreateMap() (map[string]interface{}, error) {
+ if opts.Name == "" {
+ return nil, errors.New("Name is a required field")
+ }
+ if opts.InstanceID == "" {
+ return nil, errors.New("InstanceID is a required field")
+ }
+
+ backup := map[string]interface{}{
+ "name": opts.Name,
+ "instance": opts.InstanceID,
+ }
+
+ if opts.Description != "" {
+ backup["description"] = opts.Description
+ }
+
+ return map[string]interface{}{"backup": backup}, nil
+}
+
+func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
+ var res CreateResult
+
+ reqBody, err := opts.ToBackupCreateMap()
+ if err != nil {
+ res.Err = err
+ return res
+ }
+
+ _, res.Err = perigee.Request("POST", baseURL(client), perigee.Options{
+ MoreHeaders: client.AuthenticatedHeaders(),
+ ReqBody: &reqBody,
+ Results: &res.Body,
+ OkCodes: []int{202},
+ })
+
+ return res
+}
+
+type ListOptsBuilder interface {
+ ToBackupListQuery() (string, error)
+}
+
+type ListOpts struct {
+ Datastore string `q:"datastore"`
+}
+
+func (opts ListOpts) ToBackupListQuery() (string, error) {
+ q, err := gophercloud.BuildQueryString(opts)
+ if err != nil {
+ return "", err
+ }
+ return q.String(), nil
+}
+
+func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
+ url := baseURL(client)
+
+ if opts != nil {
+ query, err := opts.ToBackupListQuery()
+ if err != nil {
+ return pagination.Pager{Err: err}
+ }
+ url += query
+ }
+
+ pageFn := func(r pagination.PageResult) pagination.Page {
+ return BackupPage{pagination.SinglePageBase(r)}
+ }
+
+ return pagination.NewPager(client, url, pageFn)
+}
+
+func Get(client *gophercloud.ServiceClient, id string) GetResult {
+ var res GetResult
+
+ _, res.Err = perigee.Request("GET", resourceURL(client, id), perigee.Options{
+ MoreHeaders: client.AuthenticatedHeaders(),
+ Results: &res.Body,
+ OkCodes: []int{200},
+ })
+
+ return res
+}
+
+func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
+ var res DeleteResult
+
+ _, res.Err = perigee.Request("DELETE", resourceURL(client, id), perigee.Options{
+ MoreHeaders: client.AuthenticatedHeaders(),
+ OkCodes: []int{202},
+ })
+
+ return res
+}
diff --git a/rackspace/db/v1/backups/requests_test.go b/rackspace/db/v1/backups/requests_test.go
new file mode 100644
index 0000000..3f7681c
--- /dev/null
+++ b/rackspace/db/v1/backups/requests_test.go
@@ -0,0 +1,80 @@
+package backups
+
+import (
+ "testing"
+
+ "github.com/rackspace/gophercloud/pagination"
+ th "github.com/rackspace/gophercloud/testhelper"
+ fake "github.com/rackspace/gophercloud/testhelper/client"
+)
+
+//const instanceID = "{instanceID}"
+
+func TestCreate(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ HandleCreateSuccessfully(t)
+
+ opts := CreateOpts{
+ Name: "snapshot",
+ Description: "My Backup",
+ InstanceID: "d4603f69-ec7e-4e9b-803f-600b9205576f",
+ }
+
+ instance, err := Create(fake.ServiceClient(), opts).Extract()
+ th.AssertNoErr(t, err)
+
+ expected := &Backup{
+ Created: "2014-02-13T21:47:16",
+ Description: "My Backup",
+ ID: "61f12fef-edb1-4561-8122-e7c00ef26a82",
+ InstanceID: "d4603f69-ec7e-4e9b-803f-600b9205576f",
+ LocationRef: "",
+ Name: "snapshot",
+ ParentID: "",
+ Size: 100,
+ Status: "NEW",
+ Updated: "2014-02-13T21:47:16",
+ }
+
+ th.AssertDeepEquals(t, expected, instance)
+}
+
+func TestList(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ HandleListSuccessfully(t)
+
+ count := 0
+
+ List(fake.ServiceClient(), nil).EachPage(func(page pagination.Page) (bool, error) {
+ count++
+ actual, err := ExtractBackups(page)
+ th.AssertNoErr(t, err)
+
+ expected := []Backup{
+ Backup{
+ Created: "2014-06-18T21:23:35",
+ Description: "Backup from Restored Instance",
+ ID: "87972694-4be2-40f5-83f8-501656e0032a",
+ InstanceID: "29af2cd9-0674-48ab-b87a-b160f00208e6",
+ LocationRef: "http://localhost/path/to/backup",
+ Name: "restored_backup",
+ ParentID: "",
+ Size: 0.141026,
+ Status: "COMPLETED",
+ Updated: "2014-06-18T21:24:39",
+ },
+ }
+
+ th.AssertDeepEquals(t, expected, actual)
+
+ return true, nil
+ })
+
+ if count != 1 {
+ t.Errorf("Expected 1 page, got %d", count)
+ }
+}
diff --git a/rackspace/db/v1/backups/results.go b/rackspace/db/v1/backups/results.go
new file mode 100644
index 0000000..16a3e66
--- /dev/null
+++ b/rackspace/db/v1/backups/results.go
@@ -0,0 +1,73 @@
+package backups
+
+import (
+ "github.com/mitchellh/mapstructure"
+ "github.com/rackspace/gophercloud"
+ "github.com/rackspace/gophercloud/pagination"
+)
+
+type Backup struct {
+ Description string
+ ID string
+ InstanceID string `json:"instance_id" mapstructure:"instance_id"`
+ LocationRef string
+ Name string
+ ParentID string `json:"parent_id" mapstructure:"parent_id"`
+ Size float64
+ Status string
+ Created string
+ Updated string
+}
+
+type CreateResult struct {
+ commonResult
+}
+
+type GetResult struct {
+ commonResult
+}
+
+type commonResult struct {
+ gophercloud.Result
+}
+
+func (r commonResult) Extract() (*Backup, error) {
+ if r.Err != nil {
+ return nil, r.Err
+ }
+
+ var response struct {
+ Backup Backup `mapstructure:"backup"`
+ }
+
+ err := mapstructure.Decode(r.Body, &response)
+ return &response.Backup, err
+}
+
+type DeleteResult struct {
+ gophercloud.ErrResult
+}
+
+type BackupPage struct {
+ pagination.SinglePageBase
+}
+
+// IsEmpty checks whether an BackupPage struct is empty.
+func (r BackupPage) IsEmpty() (bool, error) {
+ is, err := ExtractBackups(r)
+ if err != nil {
+ return true, err
+ }
+ return len(is) == 0, nil
+}
+
+func ExtractBackups(page pagination.Page) ([]Backup, error) {
+ casted := page.(BackupPage).Body
+
+ var resp struct {
+ Backups []Backup `mapstructure:"backups" json:"backups"`
+ }
+
+ err := mapstructure.Decode(casted, &resp)
+ return resp.Backups, err
+}
diff --git a/rackspace/db/v1/backups/urls.go b/rackspace/db/v1/backups/urls.go
new file mode 100644
index 0000000..553444e
--- /dev/null
+++ b/rackspace/db/v1/backups/urls.go
@@ -0,0 +1,11 @@
+package backups
+
+import "github.com/rackspace/gophercloud"
+
+func baseURL(c *gophercloud.ServiceClient) string {
+ return c.ServiceURL("backups")
+}
+
+func resourceURL(c *gophercloud.ServiceClient, backupID string) string {
+ return c.ServiceURL("backups", backupID)
+}
diff --git a/rackspace/db/v1/instances/delegate.go b/rackspace/db/v1/instances/delegate.go
index f072d84..981e902 100644
--- a/rackspace/db/v1/instances/delegate.go
+++ b/rackspace/db/v1/instances/delegate.go
@@ -86,7 +86,7 @@
}
if opts.RestorePoint != "" {
- instance["restorePoint"] = opts.RestorePoint
+ instance["restorePoint"] = map[string]string{"backupRef": opts.RestorePoint}
}
return map[string]interface{}{"instance": instance}, nil
diff --git a/rackspace/db/v1/instances/fixtures.go b/rackspace/db/v1/instances/fixtures.go
index bbf578b..ac5c960 100644
--- a/rackspace/db/v1/instances/fixtures.go
+++ b/rackspace/db/v1/instances/fixtures.go
@@ -85,7 +85,9 @@
"volume": {
"size": 2
},
- "restorePoint": "1234567890"
+ "restorePoint": {
+ "backupRef": "1234567890"
+ }
}
}
`)
diff --git a/rackspace/db/v1/instances/requests.go b/rackspace/db/v1/instances/requests.go
index 60775dd..b4bade8 100644
--- a/rackspace/db/v1/instances/requests.go
+++ b/rackspace/db/v1/instances/requests.go
@@ -3,6 +3,7 @@
import (
"github.com/racker/perigee"
"github.com/rackspace/gophercloud"
+ "github.com/rackspace/gophercloud/pagination"
)
func GetDefaultConfig(client *gophercloud.ServiceClient, id string) ConfigResult {
@@ -38,3 +39,7 @@
return res
}
+
+func ListBackups(client *gophercloud.ServiceClient, instanceID string) pagination.Pager {
+
+}