More technical debt payoff.
Applied refactoring across the entire acceptance test code base.
diff --git a/acceptance/02-list-servers.go b/acceptance/02-list-servers.go
index df9e28c..77bf82f 100644
--- a/acceptance/02-list-servers.go
+++ b/acceptance/02-list-servers.go
@@ -11,7 +11,7 @@
func main() {
flag.Parse()
- withIdentity(func(acc gophercloud.AccessProvider) {
+ withIdentity(false, func(acc gophercloud.AccessProvider) {
withServerApi(acc, func(api gophercloud.CloudServersProvider) {
tryFullDetails(api)
tryLinksOnly(api)
diff --git a/acceptance/03-get-server-details.go b/acceptance/03-get-server-details.go
index 77fa522..88d7978 100644
--- a/acceptance/03-get-server-details.go
+++ b/acceptance/03-get-server-details.go
@@ -13,7 +13,7 @@
func main() {
flag.Parse()
- withIdentity(func(auth gophercloud.AccessProvider) {
+ withIdentity(false, func(auth gophercloud.AccessProvider) {
withServerApi(auth, func(servers gophercloud.CloudServersProvider) {
var (
err error
diff --git a/acceptance/04-create-server.go b/acceptance/04-create-server.go
index 06c541b..05d8896 100644
--- a/acceptance/04-create-server.go
+++ b/acceptance/04-create-server.go
@@ -6,14 +6,11 @@
"github.com/rackspace/gophercloud"
)
-var provider, username, password string
-
var region, serverName, imageRef, flavorRef *string
var adminPass = flag.String("a", "", "Administrator password (auto-assigned if none)")
var quiet = flag.Bool("quiet", false, "Quiet mode for acceptance tests. $? non-zero if error.")
func configure() {
- provider, username, password = getCredentials()
region = flag.String("r", "DFW", "Rackspace region in which to create the server")
serverName = flag.String("n", randomString("ACPTTEST--", 16), "Server name (what you see in the control panel)")
imageRef = flag.String("i", "", "ID of image to deploy onto the server")
@@ -25,41 +22,24 @@
func main() {
configure()
- auth, err := gophercloud.Authenticate(
- provider,
- gophercloud.AuthOptions{
- Username: username,
- Password: password,
- },
- )
- if err != nil {
- panic(err)
- }
+ withIdentity(false, func(auth gophercloud.AccessProvider) {
+ withServerApi(auth, func(servers gophercloud.CloudServersProvider) {
+ _, err := createServer(servers, *imageRef, *flavorRef, *serverName, *adminPass)
+ if err != nil {
+ panic(err)
+ }
- servers, err := gophercloud.ServersApi(auth, gophercloud.ApiCriteria{
- Name: "cloudServersOpenStack",
- Region: *region,
- VersionId: "2",
- UrlChoice: gophercloud.PublicURL,
+ allServers, err := servers.ListServers()
+ if err != nil {
+ panic(err)
+ }
+
+ if !*quiet {
+ fmt.Printf("ID,Name,Status,Progress\n")
+ for _, i := range allServers {
+ fmt.Printf("%s,\"%s\",%s,%d\n", i.Id, i.Name, i.Status, i.Progress)
+ }
+ }
+ })
})
- if err != nil {
- panic(err)
- }
-
- _, err = createServer(servers, *imageRef, *flavorRef, *serverName, *adminPass)
- if err != nil {
- panic(err)
- }
-
- allServers, err := servers.ListServers()
- if err != nil {
- panic(err)
- }
-
- if !*quiet {
- fmt.Printf("ID,Name,Status,Progress\n")
- for _, i := range allServers {
- fmt.Printf("%s,\"%s\",%s,%d\n", i.Id, i.Name, i.Status, i.Progress)
- }
- }
}
diff --git a/acceptance/05-list-images.go b/acceptance/05-list-images.go
index 211a5ed..b28b3f5 100644
--- a/acceptance/05-list-images.go
+++ b/acceptance/05-list-images.go
@@ -10,39 +10,21 @@
var rgn = flag.String("r", "DFW", "Datacenter region to interrogate.")
func main() {
- provider, username, password := getCredentials()
flag.Parse()
- auth, err := gophercloud.Authenticate(
- provider,
- gophercloud.AuthOptions{
- Username: username,
- Password: password,
- },
- )
- if err != nil {
- panic(err)
- }
+ withIdentity(false, func(auth gophercloud.AccessProvider) {
+ withServerApi(auth, func(servers gophercloud.CloudServersProvider) {
+ images, err := servers.ListImages()
+ if err != nil {
+ panic(err)
+ }
- servers, err := gophercloud.ServersApi(auth, gophercloud.ApiCriteria{
- Name: "cloudServersOpenStack",
- Region: *rgn,
- VersionId: "2",
- UrlChoice: gophercloud.PublicURL,
+ if !*quiet {
+ fmt.Println("ID,Name,MinRam,MinDisk")
+ for _, image := range images {
+ fmt.Printf("%s,\"%s\",%d,%d\n", image.Id, image.Name, image.MinRam, image.MinRam)
+ }
+ }
+ })
})
- if err != nil {
- panic(err)
- }
-
- images, err := servers.ListImages()
- if err != nil {
- panic(err)
- }
-
- if !*quiet {
- fmt.Println("ID,Name,MinRam,MinDisk")
- for _, image := range images {
- fmt.Printf("%s,\"%s\",%d,%d\n", image.Id, image.Name, image.MinRam, image.MinRam)
- }
- }
}
diff --git a/acceptance/06-list-flavors.go b/acceptance/06-list-flavors.go
index ad56988..28ac215 100644
--- a/acceptance/06-list-flavors.go
+++ b/acceptance/06-list-flavors.go
@@ -10,39 +10,21 @@
var rgn = flag.String("r", "DFW", "Datacenter region to interrogate.")
func main() {
- provider, username, password := getCredentials()
flag.Parse()
- auth, err := gophercloud.Authenticate(
- provider,
- gophercloud.AuthOptions{
- Username: username,
- Password: password,
- },
- )
- if err != nil {
- panic(err)
- }
+ withIdentity(false, func(auth gophercloud.AccessProvider) {
+ withServerApi(auth, func(servers gophercloud.CloudServersProvider) {
+ flavors, err := servers.ListFlavors()
+ if err != nil {
+ panic(err)
+ }
- servers, err := gophercloud.ServersApi(auth, gophercloud.ApiCriteria{
- Name: "cloudServersOpenStack",
- Region: *rgn,
- VersionId: "2",
- UrlChoice: gophercloud.PublicURL,
+ if !*quiet {
+ fmt.Println("ID,Name,MinRam,MinDisk")
+ for _, f := range flavors {
+ fmt.Printf("%s,\"%s\",%d,%d\n", f.Id, f.Name, f.Ram, f.Disk)
+ }
+ }
+ })
})
- if err != nil {
- panic(err)
- }
-
- flavors, err := servers.ListFlavors()
- if err != nil {
- panic(err)
- }
-
- if !*quiet {
- fmt.Println("ID,Name,MinRam,MinDisk")
- for _, f := range flavors {
- fmt.Printf("%s,\"%s\",%d,%d\n", f.Id, f.Name, f.Ram, f.Disk)
- }
- }
}
diff --git a/acceptance/07-change-admin-password.go b/acceptance/07-change-admin-password.go
index 2ce7bbe..e44bda0 100644
--- a/acceptance/07-change-admin-password.go
+++ b/acceptance/07-change-admin-password.go
@@ -4,7 +4,6 @@
"flag"
"fmt"
"github.com/rackspace/gophercloud"
- "time"
)
var quiet = flag.Bool("quiet", false, "Quiet mode, for acceptance testing. $? still indicates errors though.")
@@ -12,62 +11,37 @@
var newPass = flag.String("p", "", "New password for the server.")
func main() {
- provider, username, password := getCredentials()
flag.Parse()
- acc, err := gophercloud.Authenticate(
- provider,
- gophercloud.AuthOptions{
- Username: username,
- Password: password,
- },
- )
- if err != nil {
- panic(err)
- }
+ withIdentity(func(acc gophercloud.AccessProvider) {
+ withServerApi(acc, func(api gophercloud.CloudServersProvider) {
+ // If user doesn't explicitly provide a server ID, create one dynamically.
+ if *serverId == "" {
+ var err error
+ *serverId, err = createServer(api, "", "", "", "")
+ if err != nil {
+ panic(err)
+ }
+ waitForServerState(api, *serverId, "ACTIVE")
+ }
- api, err := gophercloud.ServersApi(acc, gophercloud.ApiCriteria{
- Name: "cloudServersOpenStack",
- Region: "DFW",
- VersionId: "2",
- UrlChoice: gophercloud.PublicURL,
- })
- if err != nil {
- panic(err)
- }
+ // If no password is provided, create one dynamically.
+ if *newPass == "" {
+ *newPass = randomString("", 16)
+ }
- // If user doesn't explicitly provide a server ID, create one dynamically.
- if *serverId == "" {
- var err error
- *serverId, err = createServer(api, "", "", "", "")
- if err != nil {
- panic(err)
- }
-
- // Wait for server to finish provisioning.
- for {
- s, err := api.ServerById(*serverId)
+ // Submit the request for changing the admin password.
+ // Note that we don't verify this actually completes;
+ // doing so is beyond the scope of the SDK, and should be
+ // the responsibility of your specific OpenStack provider.
+ err := api.SetAdminPassword(*serverId, *newPass)
if err != nil {
panic(err)
}
- if s.Status == "ACTIVE" {
- break
+
+ if !*quiet {
+ fmt.Println("Password change request submitted.")
}
- time.Sleep(10 * time.Second)
- }
- }
-
- // If no password is provided, create one dynamically.
- if *newPass == "" {
- *newPass = randomString("", 16)
- }
-
- err = api.SetAdminPassword(*serverId, *newPass)
- if err != nil {
- panic(err)
- }
-
- if !*quiet {
- fmt.Println("Password change request submitted.")
- }
+ })
+ })
}
diff --git a/acceptance/08-reauthentication.go b/acceptance/08-reauthentication.go
index 8b198c7..b15e5e0 100644
--- a/acceptance/08-reauthentication.go
+++ b/acceptance/08-reauthentication.go
@@ -10,56 +10,39 @@
var rgn = flag.String("r", "DFW", "Datacenter region to interrogate.")
func main() {
- provider, username, password := getCredentials()
flag.Parse()
- // Authenticate initially against the service.
- auth, err := gophercloud.Authenticate(
- provider,
- gophercloud.AuthOptions{
- Username: username,
- Password: password,
- AllowReauth: true, // This enables reauthentication.
- },
- )
- if err != nil {
- panic(err)
- }
+ // Invoke withIdentity such that re-auth is enabled.
+ withIdentity(true, func(auth gophercloud.AccessProvider) {
+ token1 := auth.AuthToken()
- // Cache our initial authentication token.
- token1 := auth.AuthToken()
+ withServerApi(auth, func(servers gophercloud.CloudServersProvider) {
+ // Just to confirm everything works, we should be able to list images without error.
+ _, err := servers.ListImages()
+ if err != nil {
+ panic(err)
+ }
- // Acquire access to the cloud servers API.
- servers, err := gophercloud.ServersApi(auth, gophercloud.ApiCriteria{
- Name: "cloudServersOpenStack",
- Region: *rgn,
- VersionId: "2",
- UrlChoice: gophercloud.PublicURL,
+ // Revoke our current authentication token.
+ auth.Revoke(auth.AuthToken())
+
+ // Attempt to list images again. This should _succeed_, because we enabled re-authentication.
+ _, err = servers.ListImages()
+ if err != nil {
+ panic(err)
+ }
+
+ // However, our new authentication token should differ.
+ token2 := auth.AuthToken()
+
+ if !*quiet {
+ fmt.Println("Old authentication token: ", token1)
+ fmt.Println("New authentication token: ", token2)
+ }
+
+ if token1 == token2 {
+ panic("Tokens should differ")
+ }
+ })
})
- if err != nil {
- panic(err)
- }
-
- // Just to confirm everything works, we should be able to list images without error.
- _, err = servers.ListImages()
- if err != nil {
- panic(err)
- }
-
- // Revoke our current authentication token.
- auth.Revoke(auth.AuthToken())
-
- // Attempt to list images again. This should _succeed_, because we enabled re-authentication.
- _, err = servers.ListImages()
- if err != nil {
- panic(err)
- }
-
- // However, our new authentication token should differ.
- token2 := auth.AuthToken()
-
- if !*quiet {
- fmt.Println("Old authentication token: ", token1)
- fmt.Println("New authentication token: ", token2)
- }
}
diff --git a/acceptance/09-resize-server.go b/acceptance/09-resize-server.go
index 558b2cf..b12ef4b 100644
--- a/acceptance/09-resize-server.go
+++ b/acceptance/09-resize-server.go
@@ -10,43 +10,26 @@
var quiet = flag.Bool("quiet", false, "Quiet mode, for acceptance testing. $? still indicates errors though.")
func main() {
- provider, username, password := getCredentials()
flag.Parse()
- acc, err := gophercloud.Authenticate(
- provider,
- gophercloud.AuthOptions{
- Username: username,
- Password: password,
- },
- )
- if err != nil {
- panic(err)
- }
+ withIdentity(false, func(acc gophercloud.AccessProvider) {
+ withServerApi(acc, func(api gophercloud.CloudServersProvider) {
+ // These tests are going to take some time to complete.
+ // So, we'll do two tests at the same time to help amortize test time.
+ done := make(chan bool)
+ go resizeRejectTest(api, done)
+ go resizeAcceptTest(api, done)
+ _ = <- done
+ _ = <- done
- api, err := gophercloud.ServersApi(acc, gophercloud.ApiCriteria{
- Name: "cloudServersOpenStack",
- Region: "DFW",
- VersionId: "2",
- UrlChoice: gophercloud.PublicURL,
+ if !*quiet {
+ fmt.Println("Done.")
+ }
+ })
})
- if err != nil {
- panic(err)
- }
-
- // These tests are going to take some time to complete.
- // So, we'll do two tests at the same time to help amortize test time.
- done := make(chan bool)
- go resizeRejectTest(api, done)
- go resizeAcceptTest(api, done)
- _ = <- done
- _ = <- done
-
- if !*quiet {
- fmt.Println("Done.")
- }
}
+// Perform the resize test, but reject the resize request.
func resizeRejectTest(api gophercloud.CloudServersProvider, done chan bool) {
withServer(api, func(id string) {
newFlavorId := findAlternativeFlavor()
@@ -55,7 +38,7 @@
panic(err)
}
- waitForVerifyResize(api, id)
+ waitForServerState(api, id, "VERIFY_RESIZE")
err = api.RevertResize(id)
if err != nil {
@@ -65,6 +48,7 @@
done <- true
}
+// Perform the resize test, but accept the resize request.
func resizeAcceptTest(api gophercloud.CloudServersProvider, done chan bool) {
withServer(api, func(id string) {
newFlavorId := findAlternativeFlavor()
@@ -73,7 +57,7 @@
panic(err)
}
- waitForVerifyResize(api, id)
+ waitForServerState(api, id, "VERIFY_RESIZE")
err = api.ConfirmResize(id)
if err != nil {
@@ -83,19 +67,6 @@
done <- true
}
-func waitForVerifyResize(api gophercloud.CloudServersProvider, id string) {
- for {
- s, err := api.ServerById(id)
- if err != nil {
- panic(err)
- }
- if s.Status == "VERIFY_RESIZE" {
- break
- }
- time.Sleep(10 * time.Second)
- }
-}
-
func withServer(api gophercloud.CloudServersProvider, f func(string)) {
id, err := createServer(api, "", "", "", "")
if err != nil {
@@ -115,6 +86,13 @@
f(id)
+ // I've learned that resizing an instance can fail if a delete request
+ // comes in prior to its completion. This ends up leaving the server
+ // in an error state, and neither the resize NOR the delete complete.
+ // This is a bug in OpenStack, as far as I'm concerned, but thankfully,
+ // there's an easy work-around -- just wait for your server to return to
+ // active state first!
+ waitForServerState(api, id, "ACTIVE")
err = api.DeleteServerById(id)
if err != nil {
panic(err)
diff --git a/acceptance/99-delete-server.go b/acceptance/99-delete-server.go
index 8d05e8e..c39e44c 100644
--- a/acceptance/99-delete-server.go
+++ b/acceptance/99-delete-server.go
@@ -10,47 +10,37 @@
var region = flag.String("r", "DFW", "Datacenter region")
func main() {
- provider, username, password := getCredentials()
flag.Parse()
- auth, err := gophercloud.Authenticate(provider, gophercloud.AuthOptions{
- Username: username,
- Password: password,
- })
- if err != nil {
- panic(err)
- }
-
- servers, err := gophercloud.ServersApi(auth, gophercloud.ApiCriteria{
- Name: "cloudServersOpenStack",
- Region: *region,
- VersionId: "2",
- UrlChoice: gophercloud.PublicURL,
- })
- if err != nil {
- panic(err)
- }
-
- ss, err := servers.ListServers()
- if err != nil {
- panic(err)
- }
-
- n := 0
- for _, s := range ss {
- if len(s.Name) < 10 {
- continue
- }
- if s.Name[0:10] == "ACPTTEST--" {
- err := servers.DeleteServerById(s.Id)
+ withIdentity(false, func(auth gophercloud.AccessProvider) {
+ withServerApi(auth, func(servers gophercloud.CloudServersProvider) {
+ // Grab a listing of all servers.
+ ss, err := servers.ListServers()
if err != nil {
panic(err)
}
- n++
- }
- }
- if !*quiet {
- fmt.Printf("%d servers removed.\n", n)
- }
+ // And for each one that starts with the ACPTTEST prefix, delete it.
+ // These are likely left-overs from previously running acceptance tests.
+ // Note that 04-create-servers.go is intended to leak servers by intention,
+ // so as to test this code. :)
+ n := 0
+ for _, s := range ss {
+ if len(s.Name) < 8 {
+ continue
+ }
+ if s.Name[0:8] == "ACPTTEST" {
+ err := servers.DeleteServerById(s.Id)
+ if err != nil {
+ panic(err)
+ }
+ n++
+ }
+ }
+
+ if !*quiet {
+ fmt.Printf("%d servers removed.\n", n)
+ }
+ })
+ })
}
diff --git a/acceptance/libargs.go b/acceptance/libargs.go
index d9eae11..932e61e 100644
--- a/acceptance/libargs.go
+++ b/acceptance/libargs.go
@@ -132,13 +132,14 @@
// withIdentity authenticates the user against the provider's identity service, and provides an
// accessor for additional services.
-func withIdentity(f func(gophercloud.AccessProvider)) {
+func withIdentity(ar bool, f func(gophercloud.AccessProvider)) {
provider, username, password := getCredentials()
acc, err := gophercloud.Authenticate(
provider,
gophercloud.AuthOptions{
Username: username,
Password: password,
+ AllowReauth: ar,
},
)
if err != nil {