Merge pull request #227 from jamiehannaford/contributing-guide
Introducing a CONTRIBUTING guide
diff --git a/README.asciidoc b/README.asciidoc
deleted file mode 100644
index ebffbdb..0000000
--- a/README.asciidoc
+++ /dev/null
@@ -1,74 +0,0 @@
-== Gophercloud -- V0.2.0 image:https://secure.travis-ci.org/rackspace/gophercloud.png?branch=v0.2.0["build status",link="https://travis-ci.org/rackspace/gophercloud"]
-
-Gophercloud currently lets you authenticate with OpenStack providers to create and manage servers (compute service) and objects (object-storage service).
-We are working on extending the API to further include block storage, DNS, databases, security groups, and other features.
-
-WARNING: This library is still in the very early stages of development. Unless you want to contribute, it probably isn't what you want. Yet.
-
-=== Outstanding Features
-
-1. Apache 2.0 License, making Gophercloud friendly to commercial and open-source enterprises alike.
-2. Gophercloud is one of the most actively maintained Go SDKs for OpenStack.
-3. Gophercloud supports Identity V2, Nova V2, and Object Storage V1 APIs. More coming soon!
-5. Gophercloud supports automatic reauthentication upon auth token timeout, if enabled by your software.
-6. Gophercloud is the only SDK implementation with actual acceptance-level integration tests.
-
-=== Dependencies
-* Go 1.* (For information on installing Go and setting up your environment, go link:https://golang.org/doc/install[here])
-* git
-
-=== Getting the code
-
-To download Gophercloud, simply run
-```
-go get github.com/rackspace/gophercloud
-```
-It will automatically retrieve all dependencies. Goperhcloud and its dependencies will be located within your $GOPATH (%GOPATH% if you are using Windows).
-
-=== Running the tests
-
-Gophercloud has both unit tests and acceptance (integration) tests.
-
-To run the unit tests, run
-```
-go test -v github.com/rackspace/gophercloud
-```
-from the Gophercloud root directory.
-
-To run the acceptance tests, run
-```
-go test -v -tags acceptance github.com/rackspace/gophercloud
-```
-*Note: Running the acceptance tests briefly creates (and deletes) real resources. You may incur costs from your provider by running these.*
-
-To run specific tests, use a regular expression with the `run` flag. For example, to just run the authentication test (named TestAuthentication), run
-```
-go test -v -run "Authentication" -tags acceptance github.com/rackspace/gophercloud
-```
-
-=== What Does it Look Like?
-
-The Gophercloud 0.1.0 and earlier APIs are now deprecated and obsolete.
-No new feature development will occur for 0.1.0 or 0.0.0.
-However, we will accept and provide bug fixes for these APIs.
-Please refer to the acceptance tests in the master brach for code examples using the v0.1.0 API.
-The most up to date documentation for version 0.1.x can be found at link:http://godoc.org/github.com/rackspace/gophercloud[our Godoc.org documentation].
-
-We are working on a new API that provides much better support for extensions, pagination, and other features that proved difficult to implement before.
-This new API will be substantially more Go-idiomatic as well; one of the complaints received about 0.1.x and earlier is that it didn't "feel" right.
-To see what this new API is going to look like, you can look at the code examples up on the link:http://gophercloud.io/docs.html[Gophercloud website].
-If you're interested in tracking progress, note that features for version 0.2.0 will appear in the `v0.2.0` branch until merged to master.
-
-=== How can I Contribute?
-
-After using Gophercloud for a while, you might find that it lacks some useful feature, or that existing behavior seems buggy. We welcome contributions from our users for both missing functionality as well as for bug fixes. We encourage contributors to collaborate with the link:http://gophercloud.io/community.html[Gophercloud community.]
-
-Finally, Gophercloud maintains its own link:http://gophercloud.io[announcements and updates blog.]
-Feel free to check back now and again to see what's new.
-
-== License
-
-Copyright (C) 2013, 2014 Rackspace, Inc.
-
-Licensed under the Apache License, Version 2.0
-
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..74a4cd4
--- /dev/null
+++ b/README.md
@@ -0,0 +1,154 @@
+# gophercloud: the OpenStack SDK for Go
+[![Build Status](https://travis-ci.org/rackspace/gophercloud.svg?branch=v0.2.0)](https://travis-ci.org/rackspace/gophercloud)
+
+gophercloud is a flexible SDK that allows you to consume and work with OpenStack
+clouds in a simple and idiomatic way using golang. Many services are supported,
+including Compute, Block Storage, Object Storage, Networking, and Identity.
+Each service API is backed with getting started guides, code samples, reference
+documentation, unit tests and acceptance tests.
+
+## Useful links
+
+* [gophercloud homepage](http://gophercloud.io)
+* [Reference documentation](http://godoc.org/github.com/rackspace/gophercloud)
+* [Getting started guides](http://gophercloud.io/docs)
+* [Effective Go](https://golang.org/doc/effective_go.html)
+
+## How to install
+
+Before installing, you need to ensure that your [GOPATH environment variable](https://golang.org/doc/code.html#GOPATH)
+is pointing to an appropriate directory where you want to install gophercloud:
+
+```bash
+mkdir $HOME/go
+export GOPATH=$HOME/go
+```
+
+Once this is set up, you can install the gophercloud package like so:
+
+```bash
+go get github.com/rackspace/gophercloud
+```
+
+This will install all the source files you need into a `pkg` directory, which is
+referenceable from your own source files.
+
+## Getting started
+
+### Credentials
+
+Because you'll be hitting an API, you will need to retrieve your OpenStack
+credentials and either store them as environment variables or in your local Go
+files. The first method is recommended because it decouples credential
+information from source code, allowing you to push the latter to your version
+control system without any security risk.
+
+You will need to retrieve the following:
+
+* username
+* password
+* tenant name or tenant ID
+* a valid Keystone identity URL
+
+For users that have the OpenStack dashboard installed, there's a shortcut. If
+you visit the `project/access_and_security` path in Horizon and click on the
+"Download OpenStack RC File" button at the top right hand corner, you will
+download a bash file that exports all of your access details to environment
+variables. To execute the file, run `source admin-openrc.sh` and you will be
+prompted for your password.
+
+### Authentication
+
+Once you have access to your credentials, you can begin plugging them into
+gophercloud. The next step is authentication, and this is handled by a base
+"Provider" struct. To get one, you can either pass in your credentials
+explicitly, or tell gophercloud to use environment variables:
+
+```go
+import (
+ "github.com/rackspace/gophercloud"
+ "github.com/rackspace/gophercloud/openstack"
+ "github.com/rackspace/gophercloud/openstack/utils"
+)
+
+// Option 1: Pass in the values yourself
+opts := gophercloud.AuthOptions{
+ IdentityEndpoint: "https://my-openstack.com:5000/v2.0",
+ Username: "{username}",
+ Password: "{password}",
+ TenantID: "{tenant_id}",
+}
+
+// Option 2: Use a utility function to retrieve all your environment variables
+opts, err := utils.AuthOptions()
+```
+
+Once you have the `opts` variable, you can pass it in and get back a
+`ProviderClient` struct:
+
+```go
+provider, err := openstack.AuthenticatedClient(opts)
+```
+
+The `ProviderClient` is the top-level client that all of your OpenStack services
+derive from. The provider contains all of the authentication details that allow
+your Go code to access the API - such as the base URL and token ID.
+
+### Provision a server
+
+Once we have a base Provider, we inject it as a dependency into each OpenStack
+service. In order to work with the Compute API, we need a Compute service
+client; which can be created like so:
+
+```go
+client, err := openstack.NewComputeV2(provider, gophercloud.EndpointOpts{
+ Region: os.Getenv("OS_REGION_NAME"),
+})
+```
+
+We then use this `client` for any Compute API operation we want. In our case,
+we want to provision a new server - so we invoke the `Create` method and pass
+in the flavor ID (hardware specification) and image ID (operating system) we're
+interested in:
+
+```go
+import "github.com/rackspace/gophercloud/openstack/compute/v2/servers"
+
+server, err := servers.Create(client, servers.CreateOpts{
+ Name: "My new server!",
+ FlavorRef: "flavor_id",
+ ImageRef: "image_id",
+}).Extract()
+```
+
+If you are unsure about what images and flavors are, you can read our [Compute
+Getting Started guide](http://gophercloud.io/docs/compute). The above code
+sample creates a new server with the parameters, and embodies the new resource
+in the `server` variable (a
+[`servers.Server`](http://godoc.org/github.com/rackspace/gophercloud) struct).
+
+### Next steps
+
+Cool! You've handled authentication, got your `ProviderClient` and provisioned
+a new server. You're now ready to use more OpenStack services.
+
+* [Getting started with Compute](http://gophercloud.io/docs/compute)
+* [Getting started with Object Storage](http://gophercloud.io/docs/object-storage)
+* [Getting started with Networking](http://gophercloud.io/docs/networking)
+* [Getting started with Block Storage](http://gophercloud.io/docs/block-storage)
+* [Getting started with Identity](http://gophercloud.io/docs/identity)
+
+## Contributing
+
+Engaging the community and lowering barriers for contributors is something we
+care a lot about. For this reason, we've taken the time to write a [contributing
+guide](./CONTRIBUTING.md) for folks interested in getting involved in our project.
+If you're not sure how you can get involved, feel free to submit an issue or
+[e-mail us](mailto:sdk-support@rackspace.com) privately. You don't need to be a
+Go expert - all members of the community are welcome!
+
+## Help and feedback
+
+If you're struggling with something or have spotted a potential bug, feel free
+to submit an issue to our [bug tracker](/issues) or e-mail us directly at
+[sdk-support@rackspace.com](mailto:sdk-support@rackspace.com).
diff --git a/acceptance/rackspace/monitoring/pkg.go b/acceptance/rackspace/monitoring/pkg.go
deleted file mode 100644
index de6924d..0000000
--- a/acceptance/rackspace/monitoring/pkg.go
+++ /dev/null
@@ -1,4 +0,0 @@
-// +build acceptance
-
-package monitoring
-
diff --git a/acceptance/rackspace/monitoring/rbac_test.go b/acceptance/rackspace/monitoring/rbac_test.go
deleted file mode 100644
index cd01891..0000000
--- a/acceptance/rackspace/monitoring/rbac_test.go
+++ /dev/null
@@ -1,67 +0,0 @@
-// +build acceptance
-
-package monitoring
-
-import (
- "fmt"
- identity "github.com/rackspace/gophercloud/openstack/identity/v2"
- "github.com/rackspace/gophercloud/openstack/utils"
- "github.com/rackspace/gophercloud/rackspace/monitoring"
- "github.com/rackspace/gophercloud/rackspace/monitoring/notificationPlans"
- "testing"
-)
-
-func TestRBACPermissions(t *testing.T) {
- ao, err := utils.AuthOptions()
- if err != nil {
- t.Fatal(err)
- }
-
- ao.AllowReauth = true
- r, err := identity.Authenticate(ao)
- if err != nil {
- t.Fatal(err)
- }
-
- // Find the cloud monitoring API
-
- sc, err := identity.GetServiceCatalog(r)
- if err != nil {
- t.Fatal(err)
- }
-
- ces, err := sc.CatalogEntries()
- if err != nil {
- t.Fatal(err)
- }
-
- monUrl, err := findMonitoringEndpoint(ces)
- if err != nil {
- t.Fatal(err)
- }
-
- // Build ourselves an interface to cloud monitoring!
-
- np := notificationPlans.NewClient(monitoring.Options{
- Endpoint: monUrl,
- AuthOptions: ao,
- Authentication: r,
- })
-
- // Try to delete a bogus notification plan
-
- dr, err := np.Delete("ajkhdlkajhdflkajshdf")
- if err != nil {
- fmt.Printf("%#v\n", err)
- }
- fmt.Printf("%#v\n", dr)
-}
-
-func findMonitoringEndpoint(ces []identity.CatalogEntry) (string, error) {
- for _, ce := range ces {
- if ce.Type == "rax:monitor" {
- return ce.Endpoints[0].PublicURL, nil
- }
- }
- return "", fmt.Errorf("No monitoring API in the service catalog")
-}
diff --git a/openstack/blockstorage/v1/apiversions/requests.go b/openstack/blockstorage/v1/apiversions/requests.go
index b3a39f7..79a939c 100644
--- a/openstack/blockstorage/v1/apiversions/requests.go
+++ b/openstack/blockstorage/v1/apiversions/requests.go
@@ -7,7 +7,7 @@
"github.com/racker/perigee"
)
-// ListVersions lists all the Cinder API versions available to end-users.
+// List lists all the Cinder API versions available to end-users.
func List(c *gophercloud.ServiceClient) pagination.Pager {
return pagination.NewPager(c, listURL(c), func(r pagination.LastHTTPResponse) pagination.Page {
return APIVersionPage{pagination.SinglePageBase(r)}
diff --git a/openstack/blockstorage/v1/apiversions/results.go b/openstack/blockstorage/v1/apiversions/results.go
index eeff132..c4ac157 100644
--- a/openstack/blockstorage/v1/apiversions/results.go
+++ b/openstack/blockstorage/v1/apiversions/results.go
@@ -44,10 +44,12 @@
return resp.Versions, nil
}
+// GetResult represents the result of a get operation.
type GetResult struct {
gophercloud.CommonResult
}
+// Extract is a function that accepts a result and extracts an API version resource.
func (r GetResult) Extract() (*APIVersion, error) {
var resp struct {
Version *APIVersion `mapstructure:"version"`
diff --git a/openstack/blockstorage/v1/snapshots/requests.go b/openstack/blockstorage/v1/snapshots/requests.go
index 40b44d8..f3180d7 100644
--- a/openstack/blockstorage/v1/snapshots/requests.go
+++ b/openstack/blockstorage/v1/snapshots/requests.go
@@ -100,15 +100,16 @@
return pagination.NewPager(client, url, createPage)
}
-// UpdateOpts contain options for updating an existing Snapshot. This object is
-// passed to the snapshots.Update function. For more information about the
-// parameters, see the Snapshot object.
+// UpdateMetadataOpts contain options for updating an existing Snapshot. This
+// object is passed to the snapshots.Update function. For more information
+// about the parameters, see the Snapshot object.
type UpdateMetadataOpts struct {
Metadata map[string]interface{}
}
-// Update will update the Snapshot with provided information. To extract the updated
-// Snapshot from the response, call the ExtractMetadata method on the UpdateResult.
+// UpdateMetadata will update the Snapshot with provided information. To
+// extract the updated Snapshot from the response, call the ExtractMetadata
+// method on the UpdateMetadataResult.
func UpdateMetadata(client *gophercloud.ServiceClient, id string, opts *UpdateMetadataOpts) UpdateMetadataResult {
type request struct {
Metadata map[string]interface{} `json:"metadata,omitempty"`
diff --git a/openstack/blockstorage/v1/snapshots/util.go b/openstack/blockstorage/v1/snapshots/util.go
index b882875..64cdc60 100644
--- a/openstack/blockstorage/v1/snapshots/util.go
+++ b/openstack/blockstorage/v1/snapshots/util.go
@@ -4,6 +4,8 @@
"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()
diff --git a/openstack/blockstorage/v1/volumes/util.go b/openstack/blockstorage/v1/volumes/util.go
index 0e2f16e..1dda695 100644
--- a/openstack/blockstorage/v1/volumes/util.go
+++ b/openstack/blockstorage/v1/volumes/util.go
@@ -4,6 +4,8 @@
"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()
diff --git a/openstack/common/extensions/results.go b/openstack/common/extensions/results.go
index 2b8d8b7..9319018 100755
--- a/openstack/common/extensions/results.go
+++ b/openstack/common/extensions/results.go
@@ -8,7 +8,7 @@
"github.com/rackspace/gophercloud/pagination"
)
-// GetResult temporarility stores the result of a Get call.
+// GetResult temporarily stores the result of a Get call.
// Use its Extract() method to interpret it as an Extension.
type GetResult struct {
gophercloud.CommonResult
diff --git a/openstack/compute/v2/servers/doc.go b/openstack/compute/v2/servers/doc.go
index 77a7514..0a1791d 100644
--- a/openstack/compute/v2/servers/doc.go
+++ b/openstack/compute/v2/servers/doc.go
@@ -1,2 +1,3 @@
-// The servers package provides convenient access to standard, OpenStack-defined compute services.
+// Package servers provides convenient access to standard, OpenStack-defined
+// compute services.
package servers
diff --git a/openstack/networking/v2/extensions/external/requests.go b/openstack/networking/v2/extensions/external/requests.go
index f195cfa..afdd428 100644
--- a/openstack/networking/v2/extensions/external/requests.go
+++ b/openstack/networking/v2/extensions/external/requests.go
@@ -2,6 +2,8 @@
import "github.com/rackspace/gophercloud/openstack/networking/v2/networks"
+// AdminState gives users a solid type to work with for create and update
+// operations. It is recommended that users use the `Up` and `Down` enums.
type AdminState *bool
// Convenience vars for AdminStateUp values.
@@ -9,16 +11,19 @@
iTrue = true
iFalse = false
- Nothing AdminState = nil
- Up AdminState = &iTrue
- Down AdminState = &iFalse
+ Up AdminState = &iTrue
+ Down AdminState = &iFalse
)
+// CreateOpts is the structure used when creating new external network
+// resources. It embeds networks.CreateOpts and so inherits all of its required
+// and optional fields, with the addition of the External field.
type CreateOpts struct {
Parent networks.CreateOpts
External bool
}
+// ToNetworkCreateMap casts a CreateOpts struct to a map.
func (o CreateOpts) ToNetworkCreateMap() map[string]map[string]interface{} {
outer := o.Parent.ToNetworkCreateMap()
@@ -27,11 +32,15 @@
return outer
}
+// UpdateOpts is the structure used when updating existing external network
+// resources. It embeds networks.UpdateOpts and so inherits all of its required
+// and optional fields, with the addition of the External field.
type UpdateOpts struct {
Parent networks.UpdateOpts
External bool
}
+// ToNetworkUpdateMap casts an UpdateOpts struct to a map.
func (o UpdateOpts) ToNetworkUpdateMap() map[string]map[string]interface{} {
outer := o.Parent.ToNetworkUpdateMap()
diff --git a/openstack/networking/v2/extensions/lbaas/monitors/requests.go b/openstack/networking/v2/extensions/lbaas/monitors/requests.go
index 9f63fc5..fca7199 100644
--- a/openstack/networking/v2/extensions/lbaas/monitors/requests.go
+++ b/openstack/networking/v2/extensions/lbaas/monitors/requests.go
@@ -20,8 +20,8 @@
Delay int `q:"delay"`
Timeout int `q:"timeout"`
MaxRetries int `q:"max_retries"`
- HttpMethod string `q:"http_method"`
- UrlPath string `q:"url_path"`
+ HTTPMethod string `q:"http_method"`
+ URLPath string `q:"url_path"`
ExpectedCodes string `q:"expected_codes"`
AdminStateUp *bool `q:"admin_state_up"`
Status string `q:"status"`
@@ -49,6 +49,7 @@
})
}
+// Constants that represent approved monitoring types.
const (
TypePING = "PING"
TypeTCP = "TCP"
diff --git a/openstack/networking/v2/extensions/lbaas/vips/requests.go b/openstack/networking/v2/extensions/lbaas/vips/requests.go
index 8fadebf..ce4d9e4 100644
--- a/openstack/networking/v2/extensions/lbaas/vips/requests.go
+++ b/openstack/networking/v2/extensions/lbaas/vips/requests.go
@@ -8,6 +8,8 @@
"github.com/rackspace/gophercloud/pagination"
)
+// AdminState gives users a solid type to work with for create and update
+// operations. It is recommended that users use the `Up` and `Down` enums.
type AdminState *bool
// Convenience vars for AdminStateUp values.
@@ -15,9 +17,8 @@
iTrue = true
iFalse = false
- Nothing AdminState
- Up AdminState = &iTrue
- Down AdminState = &iFalse
+ Up AdminState = &iTrue
+ Down AdminState = &iFalse
)
// ListOpts allows the filtering and sorting of paginated collections through
diff --git a/openstack/networking/v2/extensions/provider/doc.go b/openstack/networking/v2/extensions/provider/doc.go
index 612d26e..373da44 100755
--- a/openstack/networking/v2/extensions/provider/doc.go
+++ b/openstack/networking/v2/extensions/provider/doc.go
@@ -1,4 +1,4 @@
-// Package networkattrs gives access to the provider Neutron plugin, allowing
+// Package provider gives access to the provider Neutron plugin, allowing
// network extended attributes. The provider extended attributes for networks
// enable administrative users to specify how network objects map to the
// underlying networking infrastructure. These extended attributes also appear
diff --git a/openstack/networking/v2/extensions/provider/results.go b/openstack/networking/v2/extensions/provider/results.go
index 96caac1..a20b259 100755
--- a/openstack/networking/v2/extensions/provider/results.go
+++ b/openstack/networking/v2/extensions/provider/results.go
@@ -8,6 +8,8 @@
"github.com/rackspace/gophercloud/pagination"
)
+// AdminState gives users a solid type to work with for create and update
+// operations. It is recommended that users use the `Up` and `Down` enums.
type AdminState *bool
// Convenience vars for AdminStateUp values.
@@ -15,9 +17,8 @@
iTrue = true
iFalse = false
- Nothing AdminState = nil
- Up AdminState = &iTrue
- Down AdminState = &iFalse
+ Up AdminState = &iTrue
+ Down AdminState = &iFalse
)
// NetworkExtAttrs represents an extended form of a Network with additional fields.
@@ -79,7 +80,7 @@
return res.Network, nil
}
-// ExtractGet decorates a CreateResult struct returned from a networks.Create()
+// ExtractCreate decorates a CreateResult struct returned from a networks.Create()
// function with extended attributes.
func ExtractCreate(r networks.CreateResult) (*NetworkExtAttrs, error) {
if r.Err != nil {
diff --git a/openstack/networking/v2/networks/requests.go b/openstack/networking/v2/networks/requests.go
index 6088b36..81b1545 100644
--- a/openstack/networking/v2/networks/requests.go
+++ b/openstack/networking/v2/networks/requests.go
@@ -57,12 +57,19 @@
return res
}
+// CreateOptsBuilder is the interface options structs have to satisfy in order
+// to be used in the main Create operation in this package. Since many
+// extensions decorate or modify the common logic, it is useful for them to
+// satisfy a basic interface in order for them to be used.
type CreateOptsBuilder interface {
ToNetworkCreateMap() map[string]map[string]interface{}
}
+// CreateOpts is the common options struct used in this package's Create
+// operation.
type CreateOpts networkOpts
+// ToNetworkCreateMap casts a CreateOpts struct to a map.
func (o CreateOpts) ToNetworkCreateMap() map[string]map[string]interface{} {
inner := make(map[string]interface{})
@@ -107,12 +114,19 @@
return res
}
+// UpdateOptsBuilder is the interface options structs have to satisfy in order
+// to be used in the main Update operation in this package. Since many
+// extensions decorate or modify the common logic, it is useful for them to
+// satisfy a basic interface in order for them to be used.
type UpdateOptsBuilder interface {
ToNetworkUpdateMap() map[string]map[string]interface{}
}
+// UpdateOpts is the common options struct used in this package's Update
+// operation.
type UpdateOpts networkOpts
+// ToNetworkUpdateMap casts a UpdateOpts struct to a map.
func (o UpdateOpts) ToNetworkUpdateMap() map[string]map[string]interface{} {
inner := make(map[string]interface{})
diff --git a/openstack/networking/v2/ports/urls_tests.go b/openstack/networking/v2/ports/urls_test.go
similarity index 100%
rename from openstack/networking/v2/ports/urls_tests.go
rename to openstack/networking/v2/ports/urls_test.go
diff --git a/openstack/networking/v2/subnets/urls_tests.go b/openstack/networking/v2/subnets/urls_test.go
similarity index 100%
rename from openstack/networking/v2/subnets/urls_tests.go
rename to openstack/networking/v2/subnets/urls_test.go
diff --git a/openstack/objectstorage/v1/accounts/doc.go b/openstack/objectstorage/v1/accounts/doc.go
index 5c94e1a..f5f894a 100644
--- a/openstack/objectstorage/v1/accounts/doc.go
+++ b/openstack/objectstorage/v1/accounts/doc.go
@@ -1,5 +1,8 @@
-/* The accounts package defines operations performed on an object-storage account.
-
-Reference: http://developer.openstack.org/api-ref-objectstorage-v1.html#storage_account_services
-*/
+// Package accounts contains functionality for working with Object Storage
+// account resources. An account is the top-level resource the object storage
+// hierarchy: containers belong to accounts, objects belong to containers.
+//
+// Another way of thinking of an account is like a namespace for all your
+// resources. It is synonymous with a project or tenant in other OpenStack
+// services.
package accounts
diff --git a/openstack/objectstorage/v1/accounts/requests_test.go b/openstack/objectstorage/v1/accounts/requests_test.go
index e1450d4..348f93e 100644
--- a/openstack/objectstorage/v1/accounts/requests_test.go
+++ b/openstack/objectstorage/v1/accounts/requests_test.go
@@ -4,34 +4,24 @@
"net/http"
"testing"
- "github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/testhelper"
+ fake "github.com/rackspace/gophercloud/testhelper/client"
)
-const tokenId = "abcabcabcabc"
-
var metadata = map[string]string{"gophercloud-test": "accounts"}
-func serviceClient() *gophercloud.ServiceClient {
- return &gophercloud.ServiceClient{
- Provider: &gophercloud.ProviderClient{TokenID: tokenId},
- Endpoint: testhelper.Endpoint(),
- }
-}
-
func TestUpdateAccount(t *testing.T) {
testhelper.SetupHTTP()
defer testhelper.TeardownHTTP()
testhelper.Mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
testhelper.TestMethod(t, r, "POST")
- testhelper.TestHeader(t, r, "X-Auth-Token", tokenId)
+ testhelper.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
testhelper.TestHeader(t, r, "X-Account-Meta-Gophercloud-Test", "accounts")
w.WriteHeader(http.StatusNoContent)
})
- client := serviceClient()
- err := Update(client, UpdateOpts{Metadata: metadata})
+ err := Update(fake.ServiceClient(), UpdateOpts{Metadata: metadata})
if err != nil {
t.Fatalf("Unable to update account: %v", err)
}
@@ -43,12 +33,11 @@
testhelper.Mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
testhelper.TestMethod(t, r, "HEAD")
- testhelper.TestHeader(t, r, "X-Auth-Token", tokenId)
+ testhelper.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
w.WriteHeader(http.StatusNoContent)
})
- client := serviceClient()
- _, err := Get(client, GetOpts{})
+ _, err := Get(fake.ServiceClient(), GetOpts{})
if err != nil {
t.Fatalf("Unable to get account metadata: %v", err)
}
diff --git a/openstack/objectstorage/v1/containers/doc.go b/openstack/objectstorage/v1/containers/doc.go
index 9b6ac17..5fed553 100644
--- a/openstack/objectstorage/v1/containers/doc.go
+++ b/openstack/objectstorage/v1/containers/doc.go
@@ -1,5 +1,8 @@
-/* The containers package defines operations performed on an object-storage container.
-
-Reference: http://developer.openstack.org/api-ref-objectstorage-v1.html#storage_container_services
-*/
+// Package containers contains functionality for working with Object Storage
+// container resources. A container serves as a logical namespace for objects
+// that are placed inside it - an object with the same name in two different
+// containers represents two different objects.
+//
+// In addition to containing objects, you can also use the container to control
+// access to objects by using an access control list (ACL).
package containers
diff --git a/openstack/objectstorage/v1/containers/requests_test.go b/openstack/objectstorage/v1/containers/requests_test.go
index 1ab09a9..09930d0 100644
--- a/openstack/objectstorage/v1/containers/requests_test.go
+++ b/openstack/objectstorage/v1/containers/requests_test.go
@@ -5,31 +5,20 @@
"net/http"
"testing"
- "github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
"github.com/rackspace/gophercloud/testhelper"
-)
-
-const (
- tokenId = "abcabcabcabc"
+ fake "github.com/rackspace/gophercloud/testhelper/client"
)
var metadata = map[string]string{"gophercloud-test": "containers"}
-func serviceClient() *gophercloud.ServiceClient {
- return &gophercloud.ServiceClient{
- Provider: &gophercloud.ProviderClient{TokenID: tokenId},
- Endpoint: testhelper.Endpoint(),
- }
-}
-
func TestListContainerInfo(t *testing.T) {
testhelper.SetupHTTP()
defer testhelper.TeardownHTTP()
testhelper.Mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
testhelper.TestMethod(t, r, "GET")
- testhelper.TestHeader(t, r, "X-Auth-Token", tokenId)
+ testhelper.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
testhelper.TestHeader(t, r, "Accept", "application/json")
w.Header().Set("Content-Type", "application/json")
@@ -56,9 +45,9 @@
}
})
- client := serviceClient()
count := 0
- List(client, &ListOpts{Full: true}).EachPage(func(page pagination.Page) (bool, error) {
+
+ List(fake.ServiceClient(), &ListOpts{Full: true}).EachPage(func(page pagination.Page) (bool, error) {
count++
actual, err := ExtractInfo(page)
if err != nil {
@@ -95,7 +84,7 @@
testhelper.Mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
testhelper.TestMethod(t, r, "GET")
- testhelper.TestHeader(t, r, "X-Auth-Token", tokenId)
+ testhelper.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
testhelper.TestHeader(t, r, "Accept", "text/plain")
w.Header().Set("Content-Type", "text/plain")
@@ -111,9 +100,9 @@
}
})
- client := serviceClient()
count := 0
- List(client, &ListOpts{Full: false}).EachPage(func(page pagination.Page) (bool, error) {
+
+ List(fake.ServiceClient(), &ListOpts{Full: false}).EachPage(func(page pagination.Page) (bool, error) {
count++
actual, err := ExtractNames(page)
if err != nil {
@@ -139,13 +128,12 @@
testhelper.Mux.HandleFunc("/testContainer", func(w http.ResponseWriter, r *http.Request) {
testhelper.TestMethod(t, r, "PUT")
- testhelper.TestHeader(t, r, "X-Auth-Token", tokenId)
+ testhelper.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
testhelper.TestHeader(t, r, "Accept", "application/json")
w.WriteHeader(http.StatusNoContent)
})
- client := serviceClient()
- _, err := Create(client, "testContainer", nil).ExtractHeaders()
+ _, err := Create(fake.ServiceClient(), "testContainer", nil).ExtractHeaders()
if err != nil {
t.Fatalf("Unexpected error creating container: %v", err)
}
@@ -157,13 +145,12 @@
testhelper.Mux.HandleFunc("/testContainer", func(w http.ResponseWriter, r *http.Request) {
testhelper.TestMethod(t, r, "DELETE")
- testhelper.TestHeader(t, r, "X-Auth-Token", tokenId)
+ testhelper.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
testhelper.TestHeader(t, r, "Accept", "application/json")
w.WriteHeader(http.StatusNoContent)
})
- client := serviceClient()
- _, err := Delete(client, "testContainer").ExtractHeaders()
+ _, err := Delete(fake.ServiceClient(), "testContainer").ExtractHeaders()
if err != nil {
t.Fatalf("Unexpected error deleting container: %v", err)
}
@@ -175,13 +162,12 @@
testhelper.Mux.HandleFunc("/testContainer", func(w http.ResponseWriter, r *http.Request) {
testhelper.TestMethod(t, r, "POST")
- testhelper.TestHeader(t, r, "X-Auth-Token", tokenId)
+ testhelper.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
testhelper.TestHeader(t, r, "Accept", "application/json")
w.WriteHeader(http.StatusNoContent)
})
- client := serviceClient()
- _, err := Update(client, "testContainer", nil).ExtractHeaders()
+ _, err := Update(fake.ServiceClient(), "testContainer", nil).ExtractHeaders()
if err != nil {
t.Fatalf("Unexpected error updating container metadata: %v", err)
}
@@ -193,13 +179,12 @@
testhelper.Mux.HandleFunc("/testContainer", func(w http.ResponseWriter, r *http.Request) {
testhelper.TestMethod(t, r, "HEAD")
- testhelper.TestHeader(t, r, "X-Auth-Token", tokenId)
+ testhelper.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
testhelper.TestHeader(t, r, "Accept", "application/json")
w.WriteHeader(http.StatusNoContent)
})
- client := serviceClient()
- _, err := Get(client, "testContainer").ExtractMetadata()
+ _, err := Get(fake.ServiceClient(), "testContainer").ExtractMetadata()
if err != nil {
t.Fatalf("Unexpected error getting container metadata: %v", err)
}
diff --git a/openstack/objectstorage/v1/containers/results.go b/openstack/objectstorage/v1/containers/results.go
index 80425bd..be96fca 100644
--- a/openstack/objectstorage/v1/containers/results.go
+++ b/openstack/objectstorage/v1/containers/results.go
@@ -9,13 +9,20 @@
"github.com/rackspace/gophercloud/pagination"
)
+// Container represents a container resource.
type Container struct {
- Bytes int `json:"bytes" mapstructure:"bytes"`
- Count int `json:"count" mapstructure:"count"`
- Name string `json:"name" mapstructure:"name"`
+ // The total number of bytes stored in the container.
+ Bytes int `json:"bytes" mapstructure:"bytes"`
+
+ // The total number of objects stored in the container.
+ Count int `json:"count" mapstructure:"count"`
+
+ // The name of the container.
+ Name string `json:"name" mapstructure:"name"`
}
-// ListResult is a *http.Response that is returned from a call to the List function.
+// ContainerPage is the page returned by a pager when traversing over a
+// collection of containers.
type ContainerPage struct {
pagination.MarkerPageBase
}
@@ -124,14 +131,23 @@
return cr.Resp.Header, nil
}
+// CreateResult represents the result of a create operation. To extract the
+// the headers from the HTTP response, you can invoke the 'ExtractHeaders'
+// method on the result struct.
type CreateResult struct {
commonResult
}
+// UpdateResult represents the result of an update operation. To extract the
+// the headers from the HTTP response, you can invoke the 'ExtractHeaders'
+// method on the result struct.
type UpdateResult struct {
commonResult
}
+// DeleteResult represents the result of a delete operation. To extract the
+// the headers from the HTTP response, you can invoke the 'ExtractHeaders'
+// method on the result struct.
type DeleteResult struct {
commonResult
}
diff --git a/openstack/objectstorage/v1/objects/doc.go b/openstack/objectstorage/v1/objects/doc.go
index 2a7461b..30a9add 100644
--- a/openstack/objectstorage/v1/objects/doc.go
+++ b/openstack/objectstorage/v1/objects/doc.go
@@ -1,5 +1,5 @@
-/* The objects package defines operations performed on an object-storage object.
-
-Reference: http://developer.openstack.org/api-ref-objectstorage-v1.html#storage_object_services
-*/
+// Package objects contains functionality for working with Object Storage
+// object resources. An object is a resource that represents and contains data
+// - such as documents, images, and so on. You can also store custom metadata
+// with an object.
package objects
diff --git a/openstack/objectstorage/v1/objects/requests_test.go b/openstack/objectstorage/v1/objects/requests_test.go
index 15956cd..089081f 100644
--- a/openstack/objectstorage/v1/objects/requests_test.go
+++ b/openstack/objectstorage/v1/objects/requests_test.go
@@ -6,38 +6,26 @@
"net/http"
"testing"
- "github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
"github.com/rackspace/gophercloud/testhelper"
-)
-
-const (
- tokenId = "abcabcabcabc"
+ fake "github.com/rackspace/gophercloud/testhelper/client"
)
var metadata = map[string]string{"Gophercloud-Test": "objects"}
-func serviceClient() *gophercloud.ServiceClient {
- return &gophercloud.ServiceClient{
- Provider: &gophercloud.ProviderClient{TokenID: tokenId},
- Endpoint: testhelper.Endpoint(),
- }
-}
-
func TestDownloadObject(t *testing.T) {
testhelper.SetupHTTP()
defer testhelper.TeardownHTTP()
testhelper.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) {
testhelper.TestMethod(t, r, "GET")
- testhelper.TestHeader(t, r, "X-Auth-Token", tokenId)
+ testhelper.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
testhelper.TestHeader(t, r, "Accept", "application/json")
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "Successful download with Gophercloud")
})
- client := serviceClient()
- content, err := Download(client, "testContainer", "testObject", nil).ExtractContent()
+ content, err := Download(fake.ServiceClient(), "testContainer", "testObject", nil).ExtractContent()
if err != nil {
t.Fatalf("Unexpected error downloading object: %v", err)
}
@@ -52,7 +40,7 @@
testhelper.Mux.HandleFunc("/testContainer", func(w http.ResponseWriter, r *http.Request) {
testhelper.TestMethod(t, r, "GET")
- testhelper.TestHeader(t, r, "X-Auth-Token", tokenId)
+ testhelper.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
testhelper.TestHeader(t, r, "Accept", "application/json")
w.Header().Set("Content-Type", "application/json")
@@ -83,9 +71,9 @@
}
})
- client := serviceClient()
count := 0
- err := List(client, "testContainer", &ListOpts{Full: true}).EachPage(func(page pagination.Page) (bool, error) {
+
+ err := List(fake.ServiceClient(), "testContainer", &ListOpts{Full: true}).EachPage(func(page pagination.Page) (bool, error) {
count++
actual, err := ExtractInfo(page)
if err != nil {
@@ -129,7 +117,7 @@
testhelper.Mux.HandleFunc("/testContainer", func(w http.ResponseWriter, r *http.Request) {
testhelper.TestMethod(t, r, "GET")
- testhelper.TestHeader(t, r, "X-Auth-Token", tokenId)
+ testhelper.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
testhelper.TestHeader(t, r, "Accept", "text/plain")
w.Header().Set("Content-Type", "text/plain")
@@ -145,9 +133,8 @@
}
})
- client := serviceClient()
count := 0
- List(client, "testContainer", &ListOpts{Full: false}).EachPage(func(page pagination.Page) (bool, error) {
+ List(fake.ServiceClient(), "testContainer", &ListOpts{Full: false}).EachPage(func(page pagination.Page) (bool, error) {
count++
actual, err := ExtractNames(page)
if err != nil {
@@ -173,14 +160,13 @@
testhelper.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) {
testhelper.TestMethod(t, r, "PUT")
- testhelper.TestHeader(t, r, "X-Auth-Token", tokenId)
+ testhelper.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
testhelper.TestHeader(t, r, "Accept", "application/json")
w.WriteHeader(http.StatusCreated)
})
- client := serviceClient()
content := bytes.NewBufferString("Did gyre and gimble in the wabe")
- _, err := Create(client, "testContainer", "testObject", content, nil).ExtractHeaders()
+ _, err := Create(fake.ServiceClient(), "testContainer", "testObject", content, nil).ExtractHeaders()
if err != nil {
t.Fatalf("Unexpected error creating object: %v", err)
}
@@ -192,14 +178,13 @@
testhelper.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) {
testhelper.TestMethod(t, r, "COPY")
- testhelper.TestHeader(t, r, "X-Auth-Token", tokenId)
+ testhelper.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
testhelper.TestHeader(t, r, "Accept", "application/json")
testhelper.TestHeader(t, r, "Destination", "/newTestContainer/newTestObject")
w.WriteHeader(http.StatusCreated)
})
- client := serviceClient()
- _, err := Copy(client, "testContainer", "testObject", &CopyOpts{Destination: "/newTestContainer/newTestObject"}).ExtractHeaders()
+ _, err := Copy(fake.ServiceClient(), "testContainer", "testObject", &CopyOpts{Destination: "/newTestContainer/newTestObject"}).ExtractHeaders()
if err != nil {
t.Fatalf("Unexpected error copying object: %v", err)
}
@@ -211,13 +196,12 @@
testhelper.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) {
testhelper.TestMethod(t, r, "DELETE")
- testhelper.TestHeader(t, r, "X-Auth-Token", tokenId)
+ testhelper.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
testhelper.TestHeader(t, r, "Accept", "application/json")
w.WriteHeader(http.StatusNoContent)
})
- client := serviceClient()
- _, err := Delete(client, "testContainer", "testObject", nil).ExtractHeaders()
+ _, err := Delete(fake.ServiceClient(), "testContainer", "testObject", nil).ExtractHeaders()
if err != nil {
t.Fatalf("Unexpected error deleting object: %v", err)
}
@@ -229,14 +213,13 @@
testhelper.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) {
testhelper.TestMethod(t, r, "POST")
- testhelper.TestHeader(t, r, "X-Auth-Token", tokenId)
+ testhelper.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
testhelper.TestHeader(t, r, "Accept", "application/json")
testhelper.TestHeader(t, r, "X-Object-Meta-Gophercloud-Test", "objects")
w.WriteHeader(http.StatusAccepted)
})
- client := serviceClient()
- _, err := Update(client, "testContainer", "testObject", &UpdateOpts{Metadata: metadata}).ExtractHeaders()
+ _, err := Update(fake.ServiceClient(), "testContainer", "testObject", &UpdateOpts{Metadata: metadata}).ExtractHeaders()
if err != nil {
t.Fatalf("Unexpected error updating object metadata: %v", err)
}
@@ -248,15 +231,14 @@
testhelper.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) {
testhelper.TestMethod(t, r, "HEAD")
- testhelper.TestHeader(t, r, "X-Auth-Token", tokenId)
+ testhelper.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
testhelper.TestHeader(t, r, "Accept", "application/json")
w.Header().Add("X-Object-Meta-Gophercloud-Test", "objects")
w.WriteHeader(http.StatusNoContent)
})
- client := serviceClient()
expected := metadata
- actual, err := Get(client, "testContainer", "testObject", nil).ExtractMetadata()
+ actual, err := Get(fake.ServiceClient(), "testContainer", "testObject", nil).ExtractMetadata()
if err != nil {
t.Fatalf("Unexpected error getting object metadata: %v", err)
}
diff --git a/openstack/objectstorage/v1/objects/results.go b/openstack/objectstorage/v1/objects/results.go
index aaeb040..f7db3ed 100644
--- a/openstack/objectstorage/v1/objects/results.go
+++ b/openstack/objectstorage/v1/objects/results.go
@@ -19,7 +19,8 @@
Name string `json:"name" mapstructure:"name"`
}
-// ListResult is a single page of objects that is returned from a call to the List function.
+// ObjectPage is a single page of objects that is returned from a call to the
+// List function.
type ObjectPage struct {
pagination.MarkerPageBase
}
@@ -149,18 +150,22 @@
return cr.Resp.Header, nil
}
+// CreateResult represents the result of a create operation.
type CreateResult struct {
commonResult
}
+// UpdateResult represents the result of an update operation.
type UpdateResult struct {
commonResult
}
+// DeleteResult represents the result of a delete operation.
type DeleteResult struct {
commonResult
}
+// CopyResult represents the result of a copy operation.
type CopyResult struct {
commonResult
}
diff --git a/package.go b/package.go
index 396e523..fb6f24a 100644
--- a/package.go
+++ b/package.go
@@ -1,7 +1,4 @@
-// Gophercloud provides a multi-vendor interface to OpenStack-compatible clouds which attempts to follow
-// established Go community coding standards and social norms.
-//
-// Unless you intend on contributing code to the SDK, you will almost certainly never have to use any
-// Context structures or any of its methods. Contextual methods exist for easier unit testing only.
-// Stick with the global functions unless you know exactly what you're doing, and why.
+// Package gophercloud provides a multi-vendor interface to OpenStack-compatible
+// clouds. The package attempts to follow established community standards and
+// golang idioms. Contributions are welcome!
package gophercloud
diff --git a/params.go b/params.go
index 10aefea..26c48c0 100644
--- a/params.go
+++ b/params.go
@@ -21,6 +21,8 @@
return nil
}
+// MaybeInt takes an int that might be a zero-value, and either returns a
+// pointer to its address or a nil value (i.e. empty pointer).
func MaybeInt(original int) *int {
if original != 0 {
return &original
@@ -58,6 +60,19 @@
return v.Interface() == z.Interface()
}
+// BuildQueryString accepts a generic structure and parses it URL struct. It
+// converts field names into query names based on tags. So for example, this
+// type:
+//
+// struct {
+// Bar string `q:"x_bar"`
+// Baz int `q:"lorem_ipsum"`
+// }{
+// Bar: "XXX",
+// Baz: "YYY",
+// }
+//
+// will be converted into ?x_bar=XXX&lorem_ipsum=YYYY
func BuildQueryString(opts interface{}) (*url.URL, error) {
optsValue := reflect.ValueOf(opts)
if optsValue.Kind() == reflect.Ptr {
@@ -69,7 +84,7 @@
optsType = optsType.Elem()
}
- optsSlice := make([]string, 0)
+ var optsSlice []string
if optsValue.Kind() == reflect.Struct {
for i := 0; i < optsValue.NumField(); i++ {
v := optsValue.Field(i)
@@ -115,10 +130,9 @@
return nil, fmt.Errorf("Options type is not a struct.")
}
-func BuildRequestBody(opts interface{}) (map[string]interface{}, error) {
- return nil, nil
-}
-
+// BuildHeaders accepts a generic structure and parses it string map. It
+// converts field names into header names based on "h" tags, and field values
+// into header values by a simple one-to-one mapping.
func BuildHeaders(opts interface{}) (map[string]string, error) {
optsValue := reflect.ValueOf(opts)
if optsValue.Kind() == reflect.Ptr {