blob: a9bb92f44a22211f548fecf6fedfb6d6b34cac22 [file] [log] [blame]
Samuel A. Falvo II2dd7d2f2014-06-30 16:18:08 -07001// +build acceptance,old
2
Samuel A. Falvo II704a7502013-07-10 15:23:43 -07003package main
4
5import (
Samuel A. Falvo IIe91ff6d2013-07-11 15:46:10 -07006 "crypto/rand"
Mark Peekd27e2532013-08-27 07:58:09 -07007 "fmt"
Samuel A. Falvo II8935ca32013-07-25 21:27:06 -07008 "github.com/rackspace/gophercloud"
Mark Peekd27e2532013-08-27 07:58:09 -07009 "os"
Max Lincoln5b250e02013-12-13 14:49:38 -030010 "strings"
Samuel A. Falvo II002b6512013-07-29 16:30:40 -070011 "time"
Samuel A. Falvo II704a7502013-07-10 15:23:43 -070012)
13
14// getCredentials will verify existence of needed credential information
15// provided through environment variables. This function will not return
16// if at least one piece of required information is missing.
Rafael Garciae4a550e2013-12-06 17:00:32 -030017func getCredentials() (provider, username, password, apiKey string) {
Samuel A. Falvo II704a7502013-07-10 15:23:43 -070018 provider = os.Getenv("SDK_PROVIDER")
19 username = os.Getenv("SDK_USERNAME")
20 password = os.Getenv("SDK_PASSWORD")
Rafael Garcia752cb332013-12-12 22:16:58 -030021 apiKey = os.Getenv("SDK_API_KEY")
Samuel A. Falvo II704a7502013-07-10 15:23:43 -070022
23 if (provider == "") || (username == "") || (password == "") {
24 fmt.Fprintf(os.Stderr, "One or more of the following environment variables aren't set:\n")
25 fmt.Fprintf(os.Stderr, " SDK_PROVIDER=\"%s\"\n", provider)
26 fmt.Fprintf(os.Stderr, " SDK_USERNAME=\"%s\"\n", username)
27 fmt.Fprintf(os.Stderr, " SDK_PASSWORD=\"%s\"\n", password)
28 os.Exit(1)
29 }
30
31 return
32}
Samuel A. Falvo IIe91ff6d2013-07-11 15:46:10 -070033
34// randomString generates a string of given length, but random content.
35// All content will be within the ASCII graphic character set.
36// (Implementation from Even Shaw's contribution on
37// http://stackoverflow.com/questions/12771930/what-is-the-fastest-way-to-generate-a-long-random-string-in-go).
Samuel A. Falvo IIe3b2d7a2013-07-12 11:08:02 -070038func randomString(prefix string, n int) string {
Mark Peekd27e2532013-08-27 07:58:09 -070039 const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
40 var bytes = make([]byte, n)
41 rand.Read(bytes)
42 for i, b := range bytes {
43 bytes[i] = alphanum[b%byte(len(alphanum))]
44 }
45 return prefix + string(bytes)
Samuel A. Falvo II8935ca32013-07-25 21:27:06 -070046}
47
48// aSuitableImage finds a minimal image for use in dynamically creating servers.
49// If none can be found, this function will panic.
50func aSuitableImage(api gophercloud.CloudServersProvider) string {
51 images, err := api.ListImages()
52 if err != nil {
53 panic(err)
54 }
55
56 // TODO(sfalvo):
57 // Works for Rackspace, might not work for your provider!
58 // Need to figure out why ListImages() provides 0 values for
59 // Ram and Disk fields.
60 //
61 // Until then, just return Ubuntu 12.04 LTS.
62 for i := 0; i < len(images); i++ {
Max Lincoln5b250e02013-12-13 14:49:38 -030063 if strings.Contains(images[i].Name, "Ubuntu 12.04 LTS") {
Samuel A. Falvo II8935ca32013-07-25 21:27:06 -070064 return images[i].Id
65 }
66 }
Max Lincoln5b250e02013-12-13 14:49:38 -030067 panic("Image for Ubuntu 12.04 LTS not found.")
Samuel A. Falvo II8935ca32013-07-25 21:27:06 -070068}
69
70// aSuitableFlavor finds the minimum flavor capable of running the test image
71// chosen by aSuitableImage. If none can be found, this function will panic.
72func aSuitableFlavor(api gophercloud.CloudServersProvider) string {
73 flavors, err := api.ListFlavors()
74 if err != nil {
75 panic(err)
76 }
77
78 // TODO(sfalvo):
79 // Works for Rackspace, might not work for your provider!
80 // Need to figure out why ListFlavors() provides 0 values for
81 // Ram and Disk fields.
82 //
83 // Until then, just return Ubuntu 12.04 LTS.
84 for i := 0; i < len(flavors); i++ {
85 if flavors[i].Id == "2" {
86 return flavors[i].Id
87 }
88 }
89 panic("Flavor 2 (512MB 1-core 20GB machine) not found.")
90}
91
92// createServer creates a new server in a manner compatible with acceptance testing.
93// In particular, it ensures that the name of the server always starts with "ACPTTEST--",
94// which the delete servers acceptance test relies on to identify servers to delete.
95// Passing in empty image and flavor references will force the use of reasonable defaults.
96// An empty name string will result in a dynamically created name prefixed with "ACPTTEST--".
97// A blank admin password will cause a password to be automatically generated; however,
98// at present no means of recovering this password exists, as no acceptance tests yet require
99// this data.
Samuel A. Falvo II80699602013-07-25 23:35:57 -0700100func createServer(servers gophercloud.CloudServersProvider, imageRef, flavorRef, name, adminPass string) (string, error) {
Samuel A. Falvo II8935ca32013-07-25 21:27:06 -0700101 if imageRef == "" {
102 imageRef = aSuitableImage(servers)
103 }
104
105 if flavorRef == "" {
106 flavorRef = aSuitableFlavor(servers)
107 }
108
109 if len(name) < 1 {
110 name = randomString("ACPTTEST", 16)
111 }
112
113 if (len(name) < 8) || (name[0:8] != "ACPTTEST") {
114 name = fmt.Sprintf("ACPTTEST--%s", name)
115 }
116
Samuel A. Falvo II80699602013-07-25 23:35:57 -0700117 newServer, err := servers.CreateServer(gophercloud.NewServer{
Samuel A. Falvo II8935ca32013-07-25 21:27:06 -0700118 Name: name,
119 ImageRef: imageRef,
120 FlavorRef: flavorRef,
121 AdminPass: adminPass,
122 })
123
Samuel A. Falvo II80699602013-07-25 23:35:57 -0700124 if err != nil {
125 return "", err
126 }
127
128 return newServer.Id, nil
Samuel A. Falvo II8935ca32013-07-25 21:27:06 -0700129}
Samuel A. Falvo II8512e9a2013-07-26 22:53:29 -0700130
131// findAlternativeFlavor locates a flavor to resize a server to. It is guaranteed to be different
132// than what aSuitableFlavor() returns. If none could be found, this function will panic.
133func findAlternativeFlavor() string {
Mark Peekd27e2532013-08-27 07:58:09 -0700134 return "3" // 1GB image, up from 512MB image
Samuel A. Falvo IIf722dbf2013-07-29 15:44:30 -0700135}
136
Samuel A. Falvo II414c15c2013-08-01 15:16:46 -0700137// findAlternativeImage locates an image to resize or rebuild a server with. It is guaranteed to be
138// different than what aSuitableImage() returns. If none could be found, this function will panic.
139func findAlternativeImage() string {
140 return "c6f9c411-e708-4952-91e5-62ded5ea4d3e"
141}
142
Samuel A. Falvo IIf722dbf2013-07-29 15:44:30 -0700143// withIdentity authenticates the user against the provider's identity service, and provides an
144// accessor for additional services.
Samuel A. Falvo II887d7802013-07-29 17:55:37 -0700145func withIdentity(ar bool, f func(gophercloud.AccessProvider)) {
Rafael Garciae4a550e2013-12-06 17:00:32 -0300146 provider, username, password, _ := getCredentials()
Samuel A. Falvo IIf722dbf2013-07-29 15:44:30 -0700147 acc, err := gophercloud.Authenticate(
148 provider,
149 gophercloud.AuthOptions{
Mark Peekd27e2532013-08-27 07:58:09 -0700150 Username: username,
151 Password: password,
Samuel A. Falvo II887d7802013-07-29 17:55:37 -0700152 AllowReauth: ar,
Samuel A. Falvo IIf722dbf2013-07-29 15:44:30 -0700153 },
154 )
155 if err != nil {
156 panic(err)
157 }
158
159 f(acc)
160}
161
162// withServerApi acquires the cloud servers API.
163func withServerApi(acc gophercloud.AccessProvider, f func(gophercloud.CloudServersProvider)) {
164 api, err := gophercloud.ServersApi(acc, gophercloud.ApiCriteria{
165 Name: "cloudServersOpenStack",
Samuel A. Falvo IIf722dbf2013-07-29 15:44:30 -0700166 VersionId: "2",
167 UrlChoice: gophercloud.PublicURL,
168 })
169 if err != nil {
170 panic(err)
171 }
172
173 f(api)
174}
Samuel A. Falvo II002b6512013-07-29 16:30:40 -0700175
176// waitForServerState polls, every 10 seconds, for a given server to appear in the indicated state.
177// This call will block forever if it never appears in the desired state, so if a timeout is required,
178// make sure to call this function in a goroutine.
179func waitForServerState(api gophercloud.CloudServersProvider, id, state string) error {
180 for {
181 s, err := api.ServerById(id)
182 if err != nil {
183 return err
184 }
185 if s.Status == state {
186 return nil
187 }
188 time.Sleep(10 * time.Second)
189 }
190 panic("Impossible")
Mark Peekd27e2532013-08-27 07:58:09 -0700191}
Mark Peekd2188c42013-08-27 08:16:28 -0700192
193// waitForImageState polls, every 10 seconds, for a given image to appear in the indicated state.
194// This call will block forever if it never appears in the desired state, so if a timeout is required,
195// make sure to call this function in a goroutine.
196func waitForImageState(api gophercloud.CloudServersProvider, id, state string) error {
197 for {
198 s, err := api.ImageById(id)
199 if err != nil {
200 return err
201 }
202 if s.Status == state {
203 return nil
204 }
205 time.Sleep(10 * time.Second)
206 }
207 panic("Impossible")
208}