vendor: Updating Gophercloud dependencies

This commit is contained in:
Joe Topjian 2016-05-17 13:20:36 +00:00
parent b204d35e19
commit 54335be3aa
10 changed files with 767 additions and 83 deletions

169
Godeps/Godeps.json generated
View File

@ -1,7 +1,7 @@
{
"ImportPath": "github.com/hashicorp/terraform",
"GoVersion": "go1.6",
"GodepVersion": "v62",
"GodepVersion": "v67",
"Packages": [
"./..."
],
@ -455,6 +455,11 @@
"Comment": "v1.1.15",
"Rev": "2cc71659118a868dc7544a7ef0808eb42d487011"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/service/emr/emriface",
"Comment": "v1.1.23",
"Rev": "2cc71659118a868dc7544a7ef0808eb42d487011"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/service/firehose",
"Comment": "v1.1.23",
@ -1045,198 +1050,198 @@
},
{
"ImportPath": "github.com/rackspace/gophercloud",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/blockstorage/v1/volumes",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/blockstorage/v2/volumes",
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/bootfromvolume",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/floatingip",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/schedulerhints",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/servergroups",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/volumeattach",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/flavors",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/images",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/servers",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/identity/v2/tenants",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/identity/v2/tokens",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/identity/v3/tokens",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/policies",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/rules",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/floatingips",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/routers",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/members",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/monitors",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/pools",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/vips",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/groups",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/rules",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/networks",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/ports",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/subnets",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/objectstorage/v1/accounts",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/objectstorage/v1/containers",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/objectstorage/v1/objects",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/openstack/utils",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/pagination",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/testhelper",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/rackspace/gophercloud/testhelper/client",
"Comment": "v1.0.0-884-gc54bbac",
"Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de"
},
{
"ImportPath": "github.com/ryanuber/columnize",
"Comment": "v2.0.1-8-g983d3a5",
"Rev": "983d3a5fab1bf04d1b412465d2d9f8430e2e917e"
"Comment": "v1.0.0-905-gadc2065",
"Rev": "adc206589ed49d18cecc9890ab93534704b04702"
},
{
"ImportPath": "github.com/ryanuber/columnize",

View File

@ -0,0 +1,5 @@
// Package volumes provides information and interaction with volumes in the
// OpenStack Block Storage service. A volume is a detachable block storage
// device, akin to a USB hard drive. It can only be attached to one instance at
// a time.
package volumes

View File

@ -0,0 +1,204 @@
package volumes
import (
"fmt"
"net/http"
"testing"
th "github.com/rackspace/gophercloud/testhelper"
fake "github.com/rackspace/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": [
{
"attachment_id": "03987cd1-0ad5-40d1-9b2a-7cc48295d4fa",
"id": "47e9ecc5-4045-4ee3-9a4b-d859d546a0cf",
"volume_id": "289da7f8-6440-407c-9fb4-7db01ec49164",
"server_id": "d1c4788b-9435-42e2-9b81-29f3be1cd01f",
"host_name": "stack",
"device": "/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"
}
}
`)
})
}

View File

@ -0,0 +1,251 @@
package volumes
import (
"fmt"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
)
// CreateOptsBuilder allows extensions to add additional parameters to the
// Create request.
type CreateOptsBuilder interface {
ToVolumeCreateMap() (map[string]interface{}, error)
}
// CreateOpts contains options for creating a Volume. This object is passed to
// the volumes.Create function. For more information about these parameters,
// see the Volume object.
type CreateOpts struct {
// The availability zone [OPTIONAL]
AvailabilityZone string
// ConsistencyGroupID is the ID of a consistency group [OPTINAL]
ConsistencyGroupID string
// The volume description [OPTIONAL]
Description string
// One or more metadata key and value pairs to associate with the volume [OPTIONAL]
Metadata map[string]string
// The volume name [OPTIONAL]
Name string
// The size of the volume, in gibibytes (GiB) [REQUIRED]
Size int
// the ID of the existing volume snapshot [OPTIONAL]
SnapshotID string
// SourceReplica is a UUID of an existing volume to replicate with [OPTIONAL]
SourceReplica string
// the ID of the existing volume [OPTIONAL]
SourceVolID string
// The ID of the image from which you want to create the volume.
// Required to create a bootable volume.
ImageID string
// The associated volume type [OPTIONAL]
VolumeType string
}
// ToVolumeCreateMap assembles a request body based on the contents of a
// CreateOpts.
func (opts CreateOpts) ToVolumeCreateMap() (map[string]interface{}, error) {
v := make(map[string]interface{})
if opts.Size == 0 {
return nil, fmt.Errorf("Required CreateOpts field 'Size' not set.")
}
v["size"] = opts.Size
if opts.AvailabilityZone != "" {
v["availability_zone"] = opts.AvailabilityZone
}
if opts.ConsistencyGroupID != "" {
v["consistencygroup_id"] = opts.ConsistencyGroupID
}
if opts.Description != "" {
v["description"] = opts.Description
}
if opts.ImageID != "" {
v["imageRef"] = opts.ImageID
}
if opts.Metadata != nil {
v["metadata"] = opts.Metadata
}
if opts.Name != "" {
v["name"] = opts.Name
}
if opts.SourceReplica != "" {
v["source_replica"] = opts.SourceReplica
}
if opts.SourceVolID != "" {
v["source_volid"] = opts.SourceVolID
}
if opts.SnapshotID != "" {
v["snapshot_id"] = opts.SnapshotID
}
if opts.VolumeType != "" {
v["volume_type"] = opts.VolumeType
}
return map[string]interface{}{"volume": v}, nil
}
// Create will create a new Volume based on the values in CreateOpts. To extract
// the Volume object from the response, call the Extract method on the
// CreateResult.
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
var res CreateResult
reqBody, err := opts.ToVolumeCreateMap()
if err != nil {
res.Err = err
return res
}
_, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
OkCodes: []int{202},
})
return res
}
// Delete will delete the existing Volume with the provided ID.
func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
var res DeleteResult
_, res.Err = client.Delete(deleteURL(client, id), nil)
return res
}
// Get retrieves the Volume with the provided ID. To extract the Volume object
// from the response, call the Extract method on the GetResult.
func Get(client *gophercloud.ServiceClient, id string) GetResult {
var res GetResult
_, res.Err = client.Get(getURL(client, id), &res.Body, nil)
return res
}
// ListOptsBuilder allows extensions to add additional parameters to the List
// request.
type ListOptsBuilder interface {
ToVolumeListQuery() (string, error)
}
// ListOpts holds options for listing Volumes. It is passed to the volumes.List
// function.
type ListOpts struct {
// admin-only option. Set it to true to see all tenant volumes.
AllTenants bool `q:"all_tenants"`
// List only volumes that contain Metadata.
Metadata map[string]string `q:"metadata"`
// List only volumes that have Name as the display name.
Name string `q:"name"`
// List only volumes that have a status of Status.
Status string `q:"status"`
}
// ToVolumeListQuery formats a ListOpts into a query string.
func (opts ListOpts) ToVolumeListQuery() (string, error) {
q, err := gophercloud.BuildQueryString(opts)
if err != nil {
return "", err
}
return q.String(), nil
}
// List returns Volumes optionally limited by the conditions provided in ListOpts.
func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
url := listURL(client)
if opts != nil {
query, err := opts.ToVolumeListQuery()
if err != nil {
return pagination.Pager{Err: err}
}
url += query
}
createPage := func(r pagination.PageResult) pagination.Page {
return ListResult{pagination.SinglePageBase(r)}
}
return pagination.NewPager(client, url, createPage)
}
// UpdateOptsBuilder allows extensions to add additional parameters to the
// Update request.
type UpdateOptsBuilder interface {
ToVolumeUpdateMap() (map[string]interface{}, error)
}
// UpdateOpts contain options for updating an existing Volume. This object is passed
// to the volumes.Update function. For more information about the parameters, see
// the Volume object.
type UpdateOpts struct {
// OPTIONAL
Name string
// OPTIONAL
Description string
// OPTIONAL
Metadata map[string]string
}
// ToVolumeUpdateMap assembles a request body based on the contents of an
// UpdateOpts.
func (opts UpdateOpts) ToVolumeUpdateMap() (map[string]interface{}, error) {
v := make(map[string]interface{})
if opts.Description != "" {
v["description"] = opts.Description
}
if opts.Metadata != nil {
v["metadata"] = opts.Metadata
}
if opts.Name != "" {
v["name"] = opts.Name
}
return map[string]interface{}{"volume": v}, nil
}
// Update will update the Volume with provided information. To extract the updated
// Volume from the response, call the Extract method on the UpdateResult.
func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult {
var res UpdateResult
reqBody, err := opts.ToVolumeUpdateMap()
if err != nil {
res.Err = err
return res
}
_, res.Err = client.Put(updateURL(client, id), reqBody, &res.Body, &gophercloud.RequestOpts{
OkCodes: []int{200},
})
return res
}
// IDFromName is a convienience function that returns a server's ID given its name.
func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
volumeCount := 0
volumeID := ""
if name == "" {
return "", fmt.Errorf("A volume name must be provided.")
}
pager := List(client, nil)
pager.EachPage(func(page pagination.Page) (bool, error) {
volumeList, err := ExtractVolumes(page)
if err != nil {
return false, err
}
for _, s := range volumeList {
if s.Name == name {
volumeCount++
volumeID = s.ID
}
}
return true, nil
})
switch volumeCount {
case 0:
return "", fmt.Errorf("Unable to find volume: %s", name)
case 1:
return volumeID, nil
default:
return "", fmt.Errorf("Found %d volumes matching %s", volumeCount, name)
}
}

View File

@ -0,0 +1,137 @@
package volumes
import (
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
"github.com/mitchellh/mapstructure"
)
// Volume contains all the information associated with an OpenStack Volume.
type Volume struct {
// Instances onto which the volume is attached.
Attachments []map[string]interface{} `mapstructure:"attachments"`
// AvailabilityZone is which availability zone the volume is in.
AvailabilityZone string `mapstructure:"availability_zone"`
// Indicates whether this is a bootable volume.
Bootable string `mapstructure:"bootable"`
// ConsistencyGroupID is the consistency group ID.
ConsistencyGroupID string `mapstructure:"consistencygroup_id"`
// The date when this volume was created.
CreatedAt string `mapstructure:"created_at"`
// Human-readable description for the volume.
Description string `mapstructure:"description"`
// Encrypted denotes if the volume is encrypted.
Encrypted bool `mapstructure:"encrypted"`
// Human-readable display name for the volume.
Name string `mapstructure:"name"`
// The type of volume to create, either SATA or SSD.
VolumeType string `mapstructure:"volume_type"`
// ReplicationDriverData contains data about the replication driver.
ReplicationDriverData string `mapstructure:"os-volume-replication:driver_data"`
// ReplicationExtendedStatus contains extended status about replication.
ReplicationExtendedStatus string `mapstructure:"os-volume-replication:extended_status"`
// ReplicationStatus is the status of replication.
ReplicationStatus string `mapstructure:"replication_status"`
// The ID of the snapshot from which the volume was created
SnapshotID string `mapstructure:"snapshot_id"`
// The ID of another block storage volume from which the current volume was created
SourceVolID string `mapstructure:"source_volid"`
// Current status of the volume.
Status string `mapstructure:"status"`
// TenantID is the id of the project that owns the volume.
TenantID string `mapstructure:"os-vol-tenant-attr:tenant_id"`
// Arbitrary key-value pairs defined by the user.
Metadata map[string]string `mapstructure:"metadata"`
// Multiattach denotes if the volume is multi-attach capable.
Multiattach bool `mapstructure:"multiattach"`
// Unique identifier for the volume.
ID string `mapstructure:"id"`
// Size of the volume in GB.
Size int `mapstructure:"size"`
// UserID is the id of the user who created the volume.
UserID string `mapstructure:"user_id"`
}
// CreateResult contains the response body and error from a Create request.
type CreateResult struct {
commonResult
}
// GetResult contains the response body and error from a Get request.
type GetResult struct {
commonResult
}
// DeleteResult contains the response body and error from a Delete request.
type DeleteResult struct {
gophercloud.ErrResult
}
// ListResult is a pagination.pager that is returned from a call to the List function.
type ListResult struct {
pagination.SinglePageBase
}
// IsEmpty returns true if a ListResult contains no Volumes.
func (r ListResult) IsEmpty() (bool, error) {
volumes, err := ExtractVolumes(r)
if err != nil {
return true, err
}
return len(volumes) == 0, nil
}
// ExtractVolumes extracts and returns Volumes. It is used while iterating over a volumes.List call.
func ExtractVolumes(page pagination.Page) ([]Volume, error) {
var response struct {
Volumes []Volume `json:"volumes"`
}
err := mapstructure.Decode(page.(ListResult).Body, &response)
return response.Volumes, err
}
// UpdateResult contains the response body and error from an Update request.
type UpdateResult struct {
commonResult
}
type commonResult struct {
gophercloud.Result
}
// Extract will get the Volume object out of the commonResult object.
func (r commonResult) Extract() (*Volume, error) {
if r.Err != nil {
return nil, r.Err
}
var res struct {
Volume *Volume `json:"volume"`
}
err := mapstructure.Decode(r.Body, &res)
return res.Volume, err
}

View File

@ -0,0 +1,23 @@
package volumes
import "github.com/rackspace/gophercloud"
func createURL(c *gophercloud.ServiceClient) string {
return c.ServiceURL("volumes")
}
func listURL(c *gophercloud.ServiceClient) string {
return c.ServiceURL("volumes", "detail")
}
func deleteURL(c *gophercloud.ServiceClient, id string) string {
return c.ServiceURL("volumes", id)
}
func getURL(c *gophercloud.ServiceClient, id string) string {
return deleteURL(c, id)
}
func updateURL(c *gophercloud.ServiceClient, id string) string {
return deleteURL(c, id)
}

View File

@ -0,0 +1,22 @@
package volumes
import (
"github.com/rackspace/gophercloud"
)
// WaitForStatus will continually poll the resource, checking for a particular
// status. It will do this for the amount of seconds defined.
func WaitForStatus(c *gophercloud.ServiceClient, id, status string, secs int) error {
return gophercloud.WaitFor(secs, func() (bool, error) {
current, err := Get(c, id).Extract()
if err != nil {
return false, err
}
if current.Status == status {
return true, nil
}
return false, nil
})
}

View File

@ -281,6 +281,29 @@ func NewBlockStorageV1(client *gophercloud.ProviderClient, eo gophercloud.Endpoi
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
}
// NewBlockStorageV2 creates a ServiceClient that may be used to access the v2 block storage service.
func NewBlockStorageV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
eo.ApplyDefaults("volume")
url, err := client.EndpointLocator(eo)
if err != nil {
return nil, err
}
// Force using v2 API
if strings.Contains(url, "/v1") {
url = strings.Replace(url, "/v1", "/v2", -1)
}
if !strings.Contains(url, "/v2") {
return nil, fmt.Errorf("Block Storage v2 endpoint not found")
}
return &gophercloud.ServiceClient{
ProviderClient: client,
Endpoint: url,
ResourceBase: url,
}, nil
}
// NewCDNV1 creates a ServiceClient that may be used to access the OpenStack v1
// CDN service.
func NewCDNV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {

View File

@ -51,6 +51,8 @@ type Image struct {
Status string
Updated string
Metadata map[string]string
}
// ImagePage contains a single page of results from a List operation.

View File

@ -138,6 +138,11 @@ func (p Pager) AllPages() (Page, error) {
// that type.
pageType := reflect.TypeOf(testPage)
// if it's a single page, just return the testPage (first page)
if _, found := pageType.FieldByName("SinglePageBase"); found {
return testPage, nil
}
// Switch on the page body type. Recognized types are `map[string]interface{}`,
// `[]byte`, and `[]interface{}`.
switch testPage.GetBody().(type) {
@ -153,7 +158,14 @@ func (p Pager) AllPages() (Page, error) {
key = k
}
}
pagesSlice = append(pagesSlice, b[key].([]interface{})...)
switch keyType := b[key].(type) {
case map[string]interface{}:
pagesSlice = append(pagesSlice, keyType)
case []interface{}:
pagesSlice = append(pagesSlice, b[key].([]interface{})...)
default:
return false, fmt.Errorf("Unsupported page body type: %+v", keyType)
}
return true, nil
})
if err != nil {