Merge pull request #283 from jamiehannaford/upgrade-guide
Adding Upgrade guide
diff --git a/UPGRADING.md b/UPGRADING.md
new file mode 100644
index 0000000..da3758b
--- /dev/null
+++ b/UPGRADING.md
@@ -0,0 +1,338 @@
+# Upgrading to v1.0.0
+
+With the arrival of this new major version increment, the unfortunate news is
+that breaking changes have been introduced to existing services. The API
+has been completely rewritten from the ground up to make the library more
+extensible, maintainable and easy-to-use.
+
+Below we've compiled upgrade instructions for the various services that
+existed before. If you have a specific issue that is not addressed below,
+please [submit an issue](/issues/new) or
+[e-mail our support team](mailto:sdk-support@rackspace.com).
+
+* [Authentication](#authentication)
+* [Servers](#servers)
+ * [List servers](#list-servers)
+ * [Get server details](#get-server-details)
+ * [Create server](#create-server)
+ * [Resize server](#resize-server)
+ * [Reboot server](#reboot-server)
+ * [Update server](#update-server)
+ * [Rebuild server](#rebuild-server)
+ * [Change admin password](#change-admin-password)
+ * [Delete server](#delete-server)
+ * [Rescue server](#rescue-server)
+* [Images and flavors](#images-and-flavors)
+ * [List images](#list-images)
+ * [List flavors](#list-flavors)
+ * [Create/delete image](#createdelete-image)
+* [Other](#other)
+ * [List keypairs](#list-keypairs)
+ * [Create/delete keypair](#createdelete-keypair)
+ * [List IP addresses](#list-ip-addresses)
+
+# Authentication
+
+One of the major differences that this release introduces is the level of
+sub-packaging to differentiate between services and providers. You now have
+the option of authenticating with OpenStack and other providers (like Rackspace).
+
+To authenticate with a vanilla OpenStack installation, you can either specify
+your credentials like this:
+
+```go
+import (
+ "github.com/rackspace/gophercloud"
+ "github.com/rackspace/gophercloud/openstack"
+)
+
+opts := gophercloud.AuthOptions{
+ IdentityEndpoint: "https://my-openstack.com:5000/v2.0",
+ Username: "{username}",
+ Password: "{password}",
+ TenantID: "{tenant_id}",
+}
+```
+
+Or have them pulled in through environment variables, like this:
+
+```go
+opts, err := openstack.AuthOptionsFromEnv()
+```
+
+Once you have your `AuthOptions` struct, you pass it in to get back a `Provider`,
+like so:
+
+```go
+provider, err := openstack.AuthenticatedClient(opts)
+```
+
+This provider is the top-level structure that all services are created from.
+
+# Servers
+
+Before you can interact with the Compute API, you need to retrieve a
+`gophercloud.ServiceClient`. To do this:
+
+```go
+// Define your region, etc.
+opts := gophercloud.EndpointOpts{Region: "RegionOne"}
+
+client, err := openstack.NewComputeV2(provider, opts)
+```
+
+## List servers
+
+All operations that involve API collections (servers, flavors, images) now use
+the `pagination.Pager` interface. This interface represents paginated entities
+that can be iterated over.
+
+Once you have a Pager, you can then pass a callback function into its `EachPage`
+method, and this will allow you to traverse over the collection and execute
+arbitrary functionality. So, an example with list servers:
+
+```go
+import (
+ "fmt"
+ "github.com/rackspace/gophercloud/pagination"
+ "github.com/rackspace/gophercloud/openstack/compute/v2/servers"
+)
+
+// We have the option of filtering the server list. If we want the full
+// collection, leave it as an empty struct or nil
+opts := servers.ListOpts{Name: "server_1"}
+
+// Retrieve a pager (i.e. a paginated collection)
+pager := servers.List(client, opts)
+
+// Define an anonymous function to be executed on each page's iteration
+err := pager.EachPage(func(page pagination.Page) (bool, error) {
+ serverList, err := servers.ExtractServers(page)
+
+ // `s' will be a servers.Server struct
+ for _, s := range serverList {
+ fmt.Printf("We have a server. ID=%s, Name=%s", s.ID, s.Name)
+ }
+})
+```
+
+## Get server details
+
+```go
+import "github.com/rackspace/gophercloud/openstack/compute/v2/servers"
+
+// Get the HTTP result
+response := servers.Get(client, "server_id")
+
+// Extract a Server struct from the response
+server, err := response.Extract()
+```
+
+## Create server
+
+```go
+import "github.com/rackspace/gophercloud/openstack/compute/v2/servers"
+
+// Define our options
+opts := servers.CreateOpts{
+ Name: "new_server",
+ FlavorRef: "flavorID",
+ ImageRef: "imageID",
+}
+
+// Get our response
+response := servers.Create(client, opts)
+
+// Extract
+server, err := response.Extract()
+```
+
+## Change admin password
+
+```go
+import "github.com/rackspace/gophercloud/openstack/compute/v2/servers"
+
+result := servers.ChangeAdminPassword(client, "server_id", "newPassword_&123")
+```
+
+## Resize server
+
+```go
+import "github.com/rackspace/gophercloud/openstack/compute/v2/servers"
+
+result := servers.Resize(client, "server_id", "new_flavor_id")
+```
+
+## Reboot server
+
+```go
+import "github.com/rackspace/gophercloud/openstack/compute/v2/servers"
+
+// You have a choice of two reboot methods: servers.SoftReboot or servers.HardReboot
+result := servers.Reboot(client, "server_id", servers.SoftReboot)
+```
+
+## Update server
+
+```go
+import "github.com/rackspace/gophercloud/openstack/compute/v2/servers"
+
+opts := servers.UpdateOpts{Name: "new_name"}
+
+server, err := servers.Update(client, "server_id", opts).Extract()
+```
+
+## Rebuild server
+
+```go
+import "github.com/rackspace/gophercloud/openstack/compute/v2/servers"
+
+// You have the option of specifying additional options
+opts := RebuildOpts{
+ Name: "new_name",
+ AdminPass: "admin_password",
+ ImageID: "image_id",
+ Metadata: map[string]string{"owner": "me"},
+}
+
+result := servers.Rebuild(client, "server_id", opts)
+
+// You can extract a servers.Server struct from the HTTP response
+server, err := result.Extract()
+```
+
+## Delete server
+
+```go
+import "github.com/rackspace/gophercloud/openstack/compute/v2/servers"
+
+response := servers.Delete(client, "server_id")
+```
+
+## Rescue server
+
+The server rescue extension for Compute is not currently supported.
+
+# Images and flavors
+
+## List images
+
+As with listing servers (see above), you first retrieve a Pager, and then pass
+in a callback over each page:
+
+```go
+import (
+ "github.com/rackspace/gophercloud/pagination"
+ "github.com/rackspace/gophercloud/openstack/compute/v2/images"
+)
+
+// We have the option of filtering the image list. If we want the full
+// collection, leave it as an empty struct
+opts := images.ListOpts{ChangesSince: "2014-01-01T01:02:03Z", Name: "Ubuntu 12.04"}
+
+// Retrieve a pager (i.e. a paginated collection)
+pager := images.List(client, opts)
+
+// Define an anonymous function to be executed on each page's iteration
+err := pager.EachPage(func(page pagination.Page) (bool, error) {
+ imageList, err := images.ExtractImages(page)
+
+ for _, i := range imageList {
+ // "i" will be a images.Image
+ }
+})
+```
+
+## List flavors
+
+```go
+import (
+ "github.com/rackspace/gophercloud/pagination"
+ "github.com/rackspace/gophercloud/openstack/compute/v2/flavors"
+)
+
+// We have the option of filtering the flavor list. If we want the full
+// collection, leave it as an empty struct
+opts := flavors.ListOpts{ChangesSince: "2014-01-01T01:02:03Z", MinRAM: 4}
+
+// Retrieve a pager (i.e. a paginated collection)
+pager := flavors.List(client, opts)
+
+// Define an anonymous function to be executed on each page's iteration
+err := pager.EachPage(func(page pagination.Page) (bool, error) {
+ flavorList, err := networks.ExtractFlavors(page)
+
+ for _, f := range flavorList {
+ // "f" will be a flavors.Flavor
+ }
+})
+```
+
+## Create/delete image
+
+Image management has been shifted to Glance, but unfortunately this service is
+not supported as of yet. You can, however, list Compute images like so:
+
+```go
+import "github.com/rackspace/gophercloud/openstack/compute/v2/images"
+
+// Retrieve a pager (i.e. a paginated collection)
+pager := images.List(client, opts)
+
+// Define an anonymous function to be executed on each page's iteration
+err := pager.EachPage(func(page pagination.Page) (bool, error) {
+ imageList, err := images.ExtractImages(page)
+
+ for _, i := range imageList {
+ // "i" will be a images.Image
+ }
+})
+```
+
+# Other
+
+## List keypairs
+
+```go
+import "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs"
+
+// Retrieve a pager (i.e. a paginated collection)
+pager := keypairs.List(client, opts)
+
+// Define an anonymous function to be executed on each page's iteration
+err := pager.EachPage(func(page pagination.Page) (bool, error) {
+ keyList, err := keypairs.ExtractKeyPairs(page)
+
+ for _, k := range keyList {
+ // "k" will be a keypairs.KeyPair
+ }
+})
+```
+
+## Create/delete keypairs
+
+To create a new keypair, you need to specify its name and, optionally, a
+pregenerated OpenSSH-formatted public key.
+
+```go
+import "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs"
+
+opts := keypairs.CreateOpts{
+ Name: "new_key",
+ PublicKey: "...",
+}
+
+response := keypairs.Create(client, opts)
+
+key, err := response.Extract()
+```
+
+To delete an existing keypair:
+
+```go
+response := keypairs.Delete(client, "keypair_id")
+```
+
+## List IP addresses
+
+This operation is not currently supported.
diff --git a/util_test.go b/util_test.go
index 52ab801..5a15a00 100644
--- a/util_test.go
+++ b/util_test.go
@@ -2,21 +2,12 @@
import (
"testing"
- "time"
th "github.com/rackspace/gophercloud/testhelper"
)
func TestWaitFor(t *testing.T) {
- err := WaitFor(0, func() (bool, error) {
- time.Sleep(1 * time.Second)
- return true, nil
- })
- if err == nil {
- t.Errorf("Expected error: 'Time out in WaitFor'")
- }
-
- err = WaitFor(5, func() (bool, error) {
+ err := WaitFor(5, func() (bool, error) {
return true, nil
})
th.CheckNoErr(t, err)