Adding support for replicas
diff --git a/rackspace/db/v1/instances/delegate.go b/rackspace/db/v1/instances/delegate.go
index d2e3c25..ca223eb 100644
--- a/rackspace/db/v1/instances/delegate.go
+++ b/rackspace/db/v1/instances/delegate.go
@@ -58,6 +58,8 @@
 	// - You can create new users or databases if you want, but they cannot be
 	// the same as the ones from the instance that was backed up.
 	RestorePoint string
+
+	ReplicaOf string
 }
 
 func (opts CreateOpts) ToInstanceCreateMap() (map[string]interface{}, error) {
@@ -91,6 +93,10 @@
 		instance["restorePoint"] = map[string]string{"backupRef": opts.RestorePoint}
 	}
 
+	if opts.ReplicaOf != "" {
+		instance["replica_of"] = opts.ReplicaOf
+	}
+
 	return map[string]interface{}{"instance": instance}, nil
 }
 
diff --git a/rackspace/db/v1/instances/fixtures.go b/rackspace/db/v1/instances/fixtures.go
index 55dc0a8..e144099 100644
--- a/rackspace/db/v1/instances/fixtures.go
+++ b/rackspace/db/v1/instances/fixtures.go
@@ -96,6 +96,104 @@
 	})
 }
 
+func HandleCreateReplicaSuccessfully(t *testing.T) {
+	th.Mux.HandleFunc("/instances", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "POST")
+		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+		th.TestJSONRequest(t, r, `
+{
+  "instance": {
+    "volume": {
+      "size": 1
+    },
+    "flavorRef": "9",
+    "name": "t2s1_ALT_GUEST",
+    "replica_of": "6bdca2fc-418e-40bd-a595-62abda61862d"
+  }
+}
+`)
+
+		w.Header().Set("Content-Type", "application/json")
+		w.WriteHeader(http.StatusOK)
+
+		fmt.Fprintf(w, `
+{
+  "instance": {
+    "status": "BUILD",
+    "updated": "2014-10-14T18:42:15",
+    "name": "t2s1_ALT_GUEST",
+    "links": [
+      {
+        "href": "https://ord.databases.api.rackspacecloud.com/v1.0/5919009/instances/8367c312-7c40-4a66-aab1-5767478914fc",
+        "rel": "self"
+      },
+      {
+        "href": "https://ord.databases.api.rackspacecloud.com/instances/8367c312-7c40-4a66-aab1-5767478914fc",
+        "rel": "bookmark"
+      }
+    ],
+    "created": "2014-10-14T18:42:15",
+    "id": "8367c312-7c40-4a66-aab1-5767478914fc",
+    "volume": {"size": 1},
+    "flavor": {"id": "9"},
+    "datastore": {
+      "version": "5.6",
+      "type": "mysql"
+    },
+    "replica_of": {"id": "6bdca2fc-418e-40bd-a595-62abda61862d"}
+  }
+}
+`)
+	})
+}
+
+func HandleListReplicasSuccessfully(t *testing.T) {
+	th.Mux.HandleFunc("/instances", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "GET")
+		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+
+		w.Header().Add("Content-Type", "application/json")
+
+		fmt.Fprintf(w, `
+{
+	"instances": [
+		{
+			"status": "ACTIVE",
+			"name": "t1s1_ALT_GUEST",
+			"links": [
+				{
+					"href": "https://ord.databases.api.rackspacecloud.com/v1.0/1234/instances/3c691f06-bf9a-4618-b7ec-2817ce0cf254",
+					"rel": "self"
+				},
+				{
+					"href": "https://ord.databases.api.rackspacecloud.com/instances/3c691f06-bf9a-4618-b7ec-2817ce0cf254",
+					"rel": "bookmark"
+				}
+			],
+			"ip": [
+				"10.0.0.3"
+			],
+			"id": "3c691f06-bf9a-4618-b7ec-2817ce0cf254",
+			"volume": {
+				"size": 1
+			},
+			"flavor": {
+				"id": "9"
+			},
+			"datastore": {
+				"version": "5.6",
+				"type": "mysql"
+			},
+			"replica_of": {
+				"id": "8b499b45-52d6-402d-b398-f9d8f279c69a"
+			}
+		}
+	]
+}
+`)
+	})
+}
+
 func HandleGetInstanceSuccessfully(t *testing.T, id string) {
 	th.Mux.HandleFunc("/instances/"+id, func(w http.ResponseWriter, r *http.Request) {
 		th.TestMethod(t, r, "GET")
@@ -107,6 +205,42 @@
 	})
 }
 
+func HandleGetReplicaSuccessfully(t *testing.T, id string) {
+	th.Mux.HandleFunc("/instances/"+id, func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "GET")
+		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+
+		w.Header().Add("Content-Type", "application/json")
+
+		fmt.Fprintf(w, `
+{
+  "instance": {
+    "status": "ACTIVE",
+    "updated": "2014-09-26T19:15:57",
+    "name": "t1_ALT_GUEST",
+    "created": "2014-09-26T19:15:50",
+    "ip": [
+      "10.0.0.2"
+    ],
+    "replicas": [
+			{"id": "3c691f06-bf9a-4618-b7ec-2817ce0cf254"}
+    ],
+    "id": "8b499b45-52d6-402d-b398-f9d8f279c69a",
+    "volume": {
+      "used": 0.54,
+      "size": 1
+    },
+    "flavor": {"id": "9"},
+    "datastore": {
+      "version": "5.6",
+      "type": "mysql"
+    }
+  }
+}
+`)
+	})
+}
+
 func HandleGetConfigSuccessfully(t *testing.T, id string) {
 	th.Mux.HandleFunc("/instances/"+id+"/configuration", func(w http.ResponseWriter, r *http.Request) {
 		th.TestMethod(t, r, "GET")
@@ -212,3 +346,22 @@
 `)
 	})
 }
+
+func HandleDetachReplicaSuccessfully(t *testing.T, id string) {
+	th.Mux.HandleFunc("/instances/"+id, func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "PATCH")
+		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+
+		th.TestJSONRequest(t, r, `
+{
+	"instance": {
+		"replica_of": "",
+		"slave_of": ""
+	}
+}
+`)
+
+		w.Header().Add("Content-Type", "application/json")
+		w.WriteHeader(http.StatusAccepted)
+	})
+}
diff --git a/rackspace/db/v1/instances/requests.go b/rackspace/db/v1/instances/requests.go
index b311289..66bc872 100644
--- a/rackspace/db/v1/instances/requests.go
+++ b/rackspace/db/v1/instances/requests.go
@@ -41,3 +41,15 @@
 	}
 	return pagination.NewPager(client, backupsURL(client, instanceID), pageFn)
 }
+
+func DetachReplica(client *gophercloud.ServiceClient, replicaID string) DetachResult {
+	var res DetachResult
+
+	_, res.Err = perigee.Request("PATCH", resourceURL(client, replicaID), perigee.Options{
+		MoreHeaders: client.AuthenticatedHeaders(),
+		ReqBody:     map[string]interface{}{"instance": map[string]string{"replica_of": "", "slave_of": ""}},
+		OkCodes:     []int{202},
+	})
+
+	return res
+}
diff --git a/rackspace/db/v1/instances/requests_test.go b/rackspace/db/v1/instances/requests_test.go
index 66d58fd..2cafa22 100644
--- a/rackspace/db/v1/instances/requests_test.go
+++ b/rackspace/db/v1/instances/requests_test.go
@@ -3,12 +3,32 @@
 import (
 	"testing"
 
+	"github.com/rackspace/gophercloud"
+	os "github.com/rackspace/gophercloud/openstack/db/v1/instances"
 	"github.com/rackspace/gophercloud/pagination"
 	"github.com/rackspace/gophercloud/rackspace/db/v1/backups"
 	th "github.com/rackspace/gophercloud/testhelper"
 	fake "github.com/rackspace/gophercloud/testhelper/client"
 )
 
+var expectedReplica = &Instance{
+	Status:  "BUILD",
+	Updated: "2014-10-14T18:42:15",
+	Name:    "t2s1_ALT_GUEST",
+	Links: []gophercloud.Link{
+		gophercloud.Link{Rel: "self", Href: "https://ord.databases.api.rackspacecloud.com/v1.0/5919009/instances/8367c312-7c40-4a66-aab1-5767478914fc"},
+		gophercloud.Link{Rel: "bookmark", Href: "https://ord.databases.api.rackspacecloud.com/instances/8367c312-7c40-4a66-aab1-5767478914fc"},
+	},
+	Created:   "2014-10-14T18:42:15",
+	ID:        "8367c312-7c40-4a66-aab1-5767478914fc",
+	Volume:    os.Volume{Size: 1},
+	Flavor:    os.Flavor{ID: "9"},
+	Datastore: Datastore{Version: "5.6", Type: "mysql"},
+	ReplicaOf: &Instance{
+		ID: "6bdca2fc-418e-40bd-a595-62abda61862d",
+	},
+}
+
 func TestGetConfig(t *testing.T) {
 	th.SetupHTTP()
 	defer th.TeardownHTTP()
@@ -114,3 +134,113 @@
 		t.Errorf("Expected 1 page, got %d", count)
 	}
 }
+
+func TestCreateReplica(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	HandleCreateReplicaSuccessfully(t)
+
+	opts := CreateOpts{
+		Name:      "t2s1_ALT_GUEST",
+		FlavorRef: "9",
+		Size:      1,
+		ReplicaOf: "6bdca2fc-418e-40bd-a595-62abda61862d",
+	}
+
+	replica, err := Create(fake.ServiceClient(), opts).Extract()
+	th.AssertNoErr(t, err)
+
+	th.AssertDeepEquals(t, expectedReplica, replica)
+}
+
+func TestListReplicas(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	HandleListReplicasSuccessfully(t)
+
+	pages := 0
+	err := List(fake.ServiceClient()).EachPage(func(page pagination.Page) (bool, error) {
+		pages++
+
+		actual, err := ExtractInstances(page)
+		if err != nil {
+			return false, err
+		}
+
+		expected := []Instance{
+			Instance{
+				Status: "ACTIVE",
+				Name:   "t1s1_ALT_GUEST",
+				Links: []gophercloud.Link{
+					gophercloud.Link{Rel: "self", Href: "https://ord.databases.api.rackspacecloud.com/v1.0/1234/instances/3c691f06-bf9a-4618-b7ec-2817ce0cf254"},
+					gophercloud.Link{Rel: "bookmark", Href: "https://ord.databases.api.rackspacecloud.com/instances/3c691f06-bf9a-4618-b7ec-2817ce0cf254"},
+				},
+				ID:        "3c691f06-bf9a-4618-b7ec-2817ce0cf254",
+				IP:        []string{"10.0.0.3"},
+				Volume:    os.Volume{Size: 1},
+				Flavor:    os.Flavor{ID: "9"},
+				Datastore: Datastore{Version: "5.6", Type: "mysql"},
+				ReplicaOf: &Instance{
+					ID: "8b499b45-52d6-402d-b398-f9d8f279c69a",
+				},
+			},
+		}
+
+		th.CheckDeepEquals(t, expected, actual)
+
+		return true, nil
+	})
+
+	th.AssertNoErr(t, err)
+
+	if pages != 1 {
+		t.Errorf("Expected 1 page, saw %d", pages)
+	}
+}
+
+func TestGetReplica(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	HandleGetReplicaSuccessfully(t, instanceID)
+
+	replica, err := Get(fake.ServiceClient(), instanceID).Extract()
+	th.AssertNoErr(t, err)
+
+	expectedReplica := &Instance{
+		Status:  "ACTIVE",
+		Updated: "2014-09-26T19:15:57",
+		Name:    "t1_ALT_GUEST",
+		Created: "2014-09-26T19:15:50",
+		IP: []string{
+			"10.0.0.2",
+		},
+		Replicas: []Instance{
+			Instance{ID: "3c691f06-bf9a-4618-b7ec-2817ce0cf254"},
+		},
+		ID: "8b499b45-52d6-402d-b398-f9d8f279c69a",
+		Volume: os.Volume{
+			Used: 0.54,
+			Size: 1,
+		},
+		Flavor: os.Flavor{ID: "9"},
+		Datastore: Datastore{
+			Version: "5.6",
+			Type:    "mysql",
+		},
+	}
+
+	th.AssertDeepEquals(t, replica, expectedReplica)
+}
+
+func TestDetachReplica(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	HandleDetachReplicaSuccessfully(t, "{replicaID}")
+
+	err := DetachReplica(fake.ServiceClient(), "{replicaID}").ExtractErr()
+	th.AssertNoErr(t, err)
+}
diff --git a/rackspace/db/v1/instances/results.go b/rackspace/db/v1/instances/results.go
index d2eff6b..760e5a7 100644
--- a/rackspace/db/v1/instances/results.go
+++ b/rackspace/db/v1/instances/results.go
@@ -4,6 +4,7 @@
 	"github.com/mitchellh/mapstructure"
 	"github.com/rackspace/gophercloud"
 	os "github.com/rackspace/gophercloud/openstack/db/v1/instances"
+	"github.com/rackspace/gophercloud/pagination"
 )
 
 type Datastore struct {
@@ -47,6 +48,12 @@
 
 	// Information about the attached volume of the instance.
 	Volume os.Volume
+
+	IP []string
+
+	ReplicaOf *Instance `mapstructure:"replica_of" json:"replica_of"`
+
+	Replicas []Instance
 }
 
 func commonExtract(err error, body interface{}) (*Instance, error) {
@@ -85,6 +92,10 @@
 	gophercloud.Result
 }
 
+type DetachResult struct {
+	gophercloud.ErrResult
+}
+
 // Extract will extract the configuration information (in the form of a map)
 // about a particular instance.
 func (r ConfigResult) Extract() (map[string]string, error) {
@@ -106,3 +117,14 @@
 type UpdateResult struct {
 	gophercloud.ErrResult
 }
+
+func ExtractInstances(page pagination.Page) ([]Instance, error) {
+	casted := page.(os.InstancePage).Body
+
+	var response struct {
+		Instances []Instance `mapstructure:"instances"`
+	}
+
+	err := mapstructure.Decode(casted, &response)
+	return response.Instances, err
+}