merge lbaasv2, portsbinding, volumes v2; remove 'rackspace' refs; update docs
diff --git a/openstack/blockstorage/v2/volumes/testing/fixtures.go b/openstack/blockstorage/v2/volumes/testing/fixtures.go
new file mode 100644
index 0000000..d4b9da0
--- /dev/null
+++ b/openstack/blockstorage/v2/volumes/testing/fixtures.go
@@ -0,0 +1,202 @@
+package testing
+
+import (
+ "fmt"
+ "net/http"
+ "testing"
+
+ th "github.com/gophercloud/gophercloud/testhelper"
+ fake "github.com/gophercloud/gophercloud/testhelper/client"
+)
+
+func MockListResponse(t *testing.T) {
+ th.Mux.HandleFunc("/volumes/detail", 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")
+ w.WriteHeader(http.StatusOK)
+
+ fmt.Fprintf(w, `
+ {
+ "volumes": [
+ {
+ "volume_type": "lvmdriver-1",
+ "created_at": "2015-09-17T03:35:03.000000",
+ "bootable": "false",
+ "name": "vol-001",
+ "os-vol-mig-status-attr:name_id": null,
+ "consistencygroup_id": null,
+ "source_volid": null,
+ "os-volume-replication:driver_data": null,
+ "multiattach": false,
+ "snapshot_id": null,
+ "replication_status": "disabled",
+ "os-volume-replication:extended_status": null,
+ "encrypted": false,
+ "os-vol-host-attr:host": null,
+ "availability_zone": "nova",
+ "attachments": [
+ {
+ "id": "47e9ecc5-4045-4ee3-9a4b-d859d546a0cf",
+ "volume_id": "289da7f8-6440-407c-9fb4-7db01ec49164",
+ "instance_uuid": "d1c4788b-9435-42e2-9b81-29f3be1cd01f",
+ "attached_host": "stack",
+ "mountpoint": "/dev/vdc"
+ }
+ ],
+ "id": "289da7f8-6440-407c-9fb4-7db01ec49164",
+ "size": 75,
+ "user_id": "ff1ce52c03ab433aaba9108c2e3ef541",
+ "os-vol-tenant-attr:tenant_id": "304dc00909ac4d0da6c62d816bcb3459",
+ "os-vol-mig-status-attr:migstat": null,
+ "metadata": {"foo": "bar"},
+ "status": "available",
+ "description": null
+ },
+ {
+ "volume_type": "lvmdriver-1",
+ "created_at": "2015-09-17T03:32:29.000000",
+ "bootable": "false",
+ "name": "vol-002",
+ "os-vol-mig-status-attr:name_id": null,
+ "consistencygroup_id": null,
+ "source_volid": null,
+ "os-volume-replication:driver_data": null,
+ "multiattach": false,
+ "snapshot_id": null,
+ "replication_status": "disabled",
+ "os-volume-replication:extended_status": null,
+ "encrypted": false,
+ "os-vol-host-attr:host": null,
+ "availability_zone": "nova",
+ "attachments": [],
+ "id": "96c3bda7-c82a-4f50-be73-ca7621794835",
+ "size": 75,
+ "user_id": "ff1ce52c03ab433aaba9108c2e3ef541",
+ "os-vol-tenant-attr:tenant_id": "304dc00909ac4d0da6c62d816bcb3459",
+ "os-vol-mig-status-attr:migstat": null,
+ "metadata": {},
+ "status": "available",
+ "description": null
+ }
+ ]
+}
+ `)
+ })
+}
+
+func MockGetResponse(t *testing.T) {
+ th.Mux.HandleFunc("/volumes/d32019d3-bc6e-4319-9c1d-6722fc136a22", 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")
+ w.WriteHeader(http.StatusOK)
+ fmt.Fprintf(w, `
+{
+ "volume": {
+ "volume_type": "lvmdriver-1",
+ "created_at": "2015-09-17T03:32:29.000000",
+ "bootable": "false",
+ "name": "vol-001",
+ "os-vol-mig-status-attr:name_id": null,
+ "consistencygroup_id": null,
+ "source_volid": null,
+ "os-volume-replication:driver_data": null,
+ "multiattach": false,
+ "snapshot_id": null,
+ "replication_status": "disabled",
+ "os-volume-replication:extended_status": null,
+ "encrypted": false,
+ "os-vol-host-attr:host": null,
+ "availability_zone": "nova",
+ "attachments": [{
+ "attachment_id": "dbce64e3-f3b9-4423-a44f-a2b15deffa1b",
+ "id": "3eafc6f5-ed74-456d-90fb-f253f594dbae",
+ "volume_id": "d32019d3-bc6e-4319-9c1d-6722fc136a22",
+ "server_id": "d1c4788b-9435-42e2-9b81-29f3be1cd01f",
+ "host_name": "stack",
+ "device": "/dev/vdd"
+ }],
+ "id": "d32019d3-bc6e-4319-9c1d-6722fc136a22",
+ "size": 75,
+ "user_id": "ff1ce52c03ab433aaba9108c2e3ef541",
+ "os-vol-tenant-attr:tenant_id": "304dc00909ac4d0da6c62d816bcb3459",
+ "os-vol-mig-status-attr:migstat": null,
+ "metadata": {},
+ "status": "available",
+ "description": null
+ }
+}
+ `)
+ })
+}
+
+func MockCreateResponse(t *testing.T) {
+ th.Mux.HandleFunc("/volumes", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "POST")
+ th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+ th.TestHeader(t, r, "Content-Type", "application/json")
+ th.TestHeader(t, r, "Accept", "application/json")
+ th.TestJSONRequest(t, r, `
+{
+ "volume": {
+ "name": "vol-001",
+ "size": 75
+ }
+}
+ `)
+
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusAccepted)
+
+ fmt.Fprintf(w, `
+{
+ "volume": {
+ "size": 75,
+ "id": "d32019d3-bc6e-4319-9c1d-6722fc136a22",
+ "metadata": {},
+ "created_at": "2015-09-17T03:32:29.044216",
+ "encrypted": false,
+ "bootable": "false",
+ "availability_zone": "nova",
+ "attachments": [],
+ "user_id": "ff1ce52c03ab433aaba9108c2e3ef541",
+ "status": "creating",
+ "description": null,
+ "volume_type": "lvmdriver-1",
+ "name": "vol-001",
+ "replication_status": "disabled",
+ "consistencygroup_id": null,
+ "source_volid": null,
+ "snapshot_id": null,
+ "multiattach": false
+ }
+}
+ `)
+ })
+}
+
+func MockDeleteResponse(t *testing.T) {
+ th.Mux.HandleFunc("/volumes/d32019d3-bc6e-4319-9c1d-6722fc136a22", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "DELETE")
+ th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+ w.WriteHeader(http.StatusAccepted)
+ })
+}
+
+func MockUpdateResponse(t *testing.T) {
+ th.Mux.HandleFunc("/volumes/d32019d3-bc6e-4319-9c1d-6722fc136a22", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "PUT")
+ th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+ w.WriteHeader(http.StatusOK)
+ fmt.Fprintf(w, `
+{
+ "volume": {
+ "name": "vol-002"
+ }
+}
+ `)
+ })
+}
diff --git a/openstack/blockstorage/v2/volumes/testing/requests_test.go b/openstack/blockstorage/v2/volumes/testing/requests_test.go
new file mode 100644
index 0000000..147beb5
--- /dev/null
+++ b/openstack/blockstorage/v2/volumes/testing/requests_test.go
@@ -0,0 +1,212 @@
+package testing
+
+import (
+ "testing"
+ "time"
+
+ "github.com/gophercloud/gophercloud"
+ "github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes"
+ "github.com/gophercloud/gophercloud/pagination"
+ th "github.com/gophercloud/gophercloud/testhelper"
+ "github.com/gophercloud/gophercloud/testhelper/client"
+)
+
+func TestList(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ MockListResponse(t)
+
+ count := 0
+
+ volumes.List(client.ServiceClient(), &volumes.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
+ count++
+ actual, err := volumes.ExtractVolumes(page)
+ if err != nil {
+ t.Errorf("Failed to extract volumes: %v", err)
+ return false, err
+ }
+
+ expected := []volumes.Volume{
+ {
+ ID: "289da7f8-6440-407c-9fb4-7db01ec49164",
+ Name: "vol-001",
+ Attachments: []volumes.Attachment{{
+ ID: "47e9ecc5-4045-4ee3-9a4b-d859d546a0cf",
+ VolumeID: "289da7f8-6440-407c-9fb4-7db01ec49164",
+ ServerID: "d1c4788b-9435-42e2-9b81-29f3be1cd01f",
+ HostName: "stack",
+ Device: "/dev/vdc",
+ }},
+ AvailabilityZone: "nova",
+ Bootable: "false",
+ ConsistencyGroupID: "",
+ CreatedAt: gophercloud.JSONRFC3339MilliNoZ(time.Date(2015, 9, 17, 3, 35, 3, 0, time.UTC)),
+ Description: "",
+ Encrypted: false,
+ Metadata: map[string]string{"foo": "bar"},
+ Multiattach: false,
+ //TenantID: "304dc00909ac4d0da6c62d816bcb3459",
+ //ReplicationDriverData: "",
+ //ReplicationExtendedStatus: "",
+ ReplicationStatus: "disabled",
+ Size: 75,
+ SnapshotID: "",
+ SourceVolID: "",
+ Status: "available",
+ UserID: "ff1ce52c03ab433aaba9108c2e3ef541",
+ VolumeType: "lvmdriver-1",
+ },
+ {
+ ID: "96c3bda7-c82a-4f50-be73-ca7621794835",
+ Name: "vol-002",
+ Attachments: []volumes.Attachment{},
+ AvailabilityZone: "nova",
+ Bootable: "false",
+ ConsistencyGroupID: "",
+ CreatedAt: gophercloud.JSONRFC3339MilliNoZ(time.Date(2015, 9, 17, 3, 32, 29, 0, time.UTC)),
+ Description: "",
+ Encrypted: false,
+ Metadata: map[string]string{},
+ Multiattach: false,
+ //TenantID: "304dc00909ac4d0da6c62d816bcb3459",
+ //ReplicationDriverData: "",
+ //ReplicationExtendedStatus: "",
+ ReplicationStatus: "disabled",
+ Size: 75,
+ SnapshotID: "",
+ SourceVolID: "",
+ Status: "available",
+ UserID: "ff1ce52c03ab433aaba9108c2e3ef541",
+ VolumeType: "lvmdriver-1",
+ },
+ }
+
+ th.CheckDeepEquals(t, expected, actual)
+
+ return true, nil
+ })
+
+ if count != 1 {
+ t.Errorf("Expected 1 page, got %d", count)
+ }
+}
+
+func TestListAll(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ MockListResponse(t)
+
+ allPages, err := volumes.List(client.ServiceClient(), &volumes.ListOpts{}).AllPages()
+ th.AssertNoErr(t, err)
+ actual, err := volumes.ExtractVolumes(allPages)
+ th.AssertNoErr(t, err)
+
+ expected := []volumes.Volume{
+ {
+ ID: "289da7f8-6440-407c-9fb4-7db01ec49164",
+ Name: "vol-001",
+ Attachments: []volumes.Attachment{{
+ ID: "47e9ecc5-4045-4ee3-9a4b-d859d546a0cf",
+ VolumeID: "289da7f8-6440-407c-9fb4-7db01ec49164",
+ ServerID: "d1c4788b-9435-42e2-9b81-29f3be1cd01f",
+ HostName: "stack",
+ Device: "/dev/vdc",
+ }},
+ AvailabilityZone: "nova",
+ Bootable: "false",
+ ConsistencyGroupID: "",
+ CreatedAt: gophercloud.JSONRFC3339MilliNoZ(time.Date(2015, 9, 17, 3, 35, 3, 0, time.UTC)),
+ Description: "",
+ Encrypted: false,
+ Metadata: map[string]string{"foo": "bar"},
+ Multiattach: false,
+ //TenantID: "304dc00909ac4d0da6c62d816bcb3459",
+ //ReplicationDriverData: "",
+ //ReplicationExtendedStatus: "",
+ ReplicationStatus: "disabled",
+ Size: 75,
+ SnapshotID: "",
+ SourceVolID: "",
+ Status: "available",
+ UserID: "ff1ce52c03ab433aaba9108c2e3ef541",
+ VolumeType: "lvmdriver-1",
+ },
+ {
+ ID: "96c3bda7-c82a-4f50-be73-ca7621794835",
+ Name: "vol-002",
+ Attachments: []volumes.Attachment{},
+ AvailabilityZone: "nova",
+ Bootable: "false",
+ ConsistencyGroupID: "",
+ CreatedAt: gophercloud.JSONRFC3339MilliNoZ(time.Date(2015, 9, 17, 3, 32, 29, 0, time.UTC)),
+ Description: "",
+ Encrypted: false,
+ Metadata: map[string]string{},
+ Multiattach: false,
+ //TenantID: "304dc00909ac4d0da6c62d816bcb3459",
+ //ReplicationDriverData: "",
+ //ReplicationExtendedStatus: "",
+ ReplicationStatus: "disabled",
+ Size: 75,
+ SnapshotID: "",
+ SourceVolID: "",
+ Status: "available",
+ UserID: "ff1ce52c03ab433aaba9108c2e3ef541",
+ VolumeType: "lvmdriver-1",
+ },
+ }
+
+ th.CheckDeepEquals(t, expected, actual)
+
+}
+
+func TestGet(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ MockGetResponse(t)
+
+ v, err := volumes.Get(client.ServiceClient(), "d32019d3-bc6e-4319-9c1d-6722fc136a22").Extract()
+ th.AssertNoErr(t, err)
+
+ th.AssertEquals(t, v.Name, "vol-001")
+ th.AssertEquals(t, v.ID, "d32019d3-bc6e-4319-9c1d-6722fc136a22")
+}
+
+func TestCreate(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ MockCreateResponse(t)
+
+ options := &volumes.CreateOpts{Size: 75, Name: "vol-001"}
+ n, err := volumes.Create(client.ServiceClient(), options).Extract()
+ th.AssertNoErr(t, err)
+
+ th.AssertEquals(t, n.Size, 75)
+ th.AssertEquals(t, n.ID, "d32019d3-bc6e-4319-9c1d-6722fc136a22")
+}
+
+func TestDelete(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ MockDeleteResponse(t)
+
+ res := volumes.Delete(client.ServiceClient(), "d32019d3-bc6e-4319-9c1d-6722fc136a22")
+ th.AssertNoErr(t, res.Err)
+}
+
+func TestUpdate(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ MockUpdateResponse(t)
+
+ options := volumes.UpdateOpts{Name: "vol-002"}
+ v, err := volumes.Update(client.ServiceClient(), "d32019d3-bc6e-4319-9c1d-6722fc136a22", options).Extract()
+ th.AssertNoErr(t, err)
+ th.CheckEquals(t, "vol-002", v.Name)
+}