blob: dc2cde8d3e1738a7a51cbbac5141c2ae01dff2cf [file] [log] [blame]
package openstack
import (
"fmt"
"github.com/rackspace/gophercloud/openstack/compute/servers"
"github.com/rackspace/gophercloud/openstack/identity"
"github.com/rackspace/gophercloud/openstack/utils"
"os"
"text/tabwriter"
"time"
"crypto/rand"
)
var errTimeout = fmt.Errorf("Timeout.")
type testState struct {
o identity.AuthOptions
a identity.AuthResults
sc *identity.ServiceCatalog
eps []identity.Endpoint
w *tabwriter.Writer
imageId string
flavorId string
region string
ep string
client *servers.Client
createdServer *servers.Server
gottenServer *servers.Server
updatedServer *servers.Server
serverName string
alternateName string
}
func setupForList() (*testState, error) {
var err error
ts := new(testState)
ts.o, err = utils.AuthOptions()
if err != nil {
return ts, err
}
ts.a, err = identity.Authenticate(ts.o)
if err != nil {
return ts, err
}
ts.sc, err = identity.GetServiceCatalog(ts.a)
if err != nil {
return ts, err
}
ts.eps, err = findAllComputeEndpoints(ts.sc)
if err != nil {
return ts, err
}
ts.w = new(tabwriter.Writer)
ts.w.Init(os.Stdout, 2, 8, 2, ' ', 0)
return ts, nil
}
func setupForCRUD() (*testState, error) {
ts, err := setupForList()
if err != nil {
return ts, err
}
ts.imageId = os.Getenv("OS_IMAGE_ID")
if ts.imageId == "" {
return ts, fmt.Errorf("Expected OS_IMAGE_ID environment variable to be set")
}
ts.flavorId = os.Getenv("OS_FLAVOR_ID")
if ts.flavorId == "" {
return ts, fmt.Errorf("Expected OS_FLAVOR_ID environment variable to be set")
}
ts.region = os.Getenv("OS_REGION_NAME")
if ts.region == "" {
ts.region = ts.eps[0].Region
}
ts.ep, err = findEndpointForRegion(ts.eps, ts.region)
if err != nil {
return ts, err
}
return ts, err
}
func findAllComputeEndpoints(sc *identity.ServiceCatalog) ([]identity.Endpoint, error) {
ces, err := sc.CatalogEntries()
if err != nil {
return nil, err
}
for _, ce := range ces {
if ce.Type == "compute" {
return ce.Endpoints, nil
}
}
return nil, fmt.Errorf("Compute endpoint not found.")
}
func findEndpointForRegion(eps []identity.Endpoint, r string) (string, error) {
for _, ep := range eps {
if ep.Region == r {
return ep.PublicURL, nil
}
}
return "", fmt.Errorf("Unknown region %s", r)
}
func countDown(ts *testState, timeout int) (bool, int, error) {
if timeout < 1 {
return false, 0, errTimeout
}
time.Sleep(1 * time.Second)
timeout--
gr, err := servers.GetDetail(ts.client, ts.createdServer.Id)
if err != nil {
return false, timeout, err
}
ts.gottenServer, err = servers.GetServer(gr)
if err != nil {
return false, timeout, err
}
return true, timeout, nil
}
func createServer(ts *testState) error {
ts.serverName = randomString("ACPTTEST", 16)
fmt.Printf("Attempting to create server: %s\n", ts.serverName)
ts.client = servers.NewClient(ts.ep, ts.a, ts.o)
cr, err := servers.Create(ts.client, map[string]interface{}{
"flavorRef": ts.flavorId,
"imageRef": ts.imageId,
"name": ts.serverName,
})
if err != nil {
return err
}
ts.createdServer, err = servers.GetServer(cr)
return err
}
func waitForStatus(ts *testState, s string) error {
var (
inProgress bool
timeout int
err error
)
for inProgress, timeout, err = countDown(ts, 300) ; inProgress ; inProgress, timeout, err = countDown(ts, timeout) {
if ts.gottenServer.Id != ts.createdServer.Id {
return fmt.Errorf("created server id (%s) != gotten server id (%s)", ts.createdServer.Id, ts.gottenServer.Id)
}
if ts.gottenServer.Status == s {
fmt.Printf("Server created after %d seconds (approximately)\n", 300-timeout)
break
}
}
if err == errTimeout {
fmt.Printf("I'm not waiting around.\n")
err = nil
}
return err
}
func changeServerName(ts *testState) error {
var (
inProgress bool
timeout int
)
ts.alternateName = randomString("ACPTTEST", 16)
for ts.alternateName == ts.serverName {
ts.alternateName = randomString("ACPTTEST", 16)
}
fmt.Println("Attempting to change server name")
ur, err := servers.Update(ts.client, ts.createdServer.Id, map[string]interface{}{
"name": ts.alternateName,
})
if err != nil {
return err
}
ts.updatedServer, err = servers.GetServer(ur)
if err != nil {
return err
}
if ts.updatedServer.Id != ts.createdServer.Id {
return fmt.Errorf("Expected updated and created server to share the same ID")
}
for inProgress, timeout, err = countDown(ts, 300) ; inProgress ; inProgress, timeout, err = countDown(ts, timeout) {
if ts.gottenServer.Id != ts.updatedServer.Id {
return fmt.Errorf("Updated server ID (%s) != gotten server ID (%s)", ts.updatedServer.Id, ts.gottenServer.Id)
}
if ts.gottenServer.Name == ts.alternateName {
fmt.Printf("Server updated after %d seconds (approximately)\n", 300-timeout)
break
}
}
if err == errTimeout {
fmt.Printf("I'm not waiting around.\n")
err = nil
}
return err
}
// randomString generates a string of given length, but random content.
// All content will be within the ASCII graphic character set.
// (Implementation from Even Shaw's contribution on
// http://stackoverflow.com/questions/12771930/what-is-the-fastest-way-to-generate-a-long-random-string-in-go).
func randomString(prefix string, n int) string {
const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
var bytes = make([]byte, n)
rand.Read(bytes)
for i, b := range bytes {
bytes[i] = alphanum[b%byte(len(alphanum))]
}
return prefix + string(bytes)
}