blob: 042ab34a7ae84a9d7f4a9c22cfc0637e647bbb14 [file] [log] [blame]
Samuel A. Falvo IIb5d93f22014-02-21 15:00:20 -08001// +build acceptance
2
Samuel A. Falvo II0abdb102014-02-13 23:19:26 -08003package openstack
4
5import (
Samuel A. Falvo IIe246ac02014-02-13 23:20:09 -08006 "crypto/rand"
Samuel A. Falvo II0abdb102014-02-13 23:19:26 -08007 "fmt"
8 "github.com/rackspace/gophercloud/openstack/compute/servers"
9 "github.com/rackspace/gophercloud/openstack/identity"
10 "github.com/rackspace/gophercloud/openstack/utils"
11 "os"
12 "text/tabwriter"
13 "time"
Samuel A. Falvo II0abdb102014-02-13 23:19:26 -080014)
15
16var errTimeout = fmt.Errorf("Timeout.")
17
18type testState struct {
Samuel A. Falvo IIe246ac02014-02-13 23:20:09 -080019 o identity.AuthOptions
20 a identity.AuthResults
21 sc *identity.ServiceCatalog
22 eps []identity.Endpoint
23 w *tabwriter.Writer
24 imageId string
25 flavorId string
26 region string
27 ep string
28 client *servers.Client
Samuel A. Falvo II0abdb102014-02-13 23:19:26 -080029 createdServer *servers.Server
Samuel A. Falvo IIe246ac02014-02-13 23:20:09 -080030 gottenServer *servers.Server
Samuel A. Falvo II0abdb102014-02-13 23:19:26 -080031 updatedServer *servers.Server
Samuel A. Falvo IIe246ac02014-02-13 23:20:09 -080032 serverName string
Samuel A. Falvo II0abdb102014-02-13 23:19:26 -080033 alternateName string
Samuel A. Falvo II808bb632014-03-12 00:07:50 -070034 flavorIdResize string
Samuel A. Falvo II0abdb102014-02-13 23:19:26 -080035}
36
Jon Perritt816d2a02014-03-11 20:49:46 -050037func setupForList(service string) (*testState, error) {
Samuel A. Falvo II0abdb102014-02-13 23:19:26 -080038 var err error
39
40 ts := new(testState)
41
42 ts.o, err = utils.AuthOptions()
43 if err != nil {
44 return ts, err
45 }
46
47 ts.a, err = identity.Authenticate(ts.o)
48 if err != nil {
49 return ts, err
50 }
51
52 ts.sc, err = identity.GetServiceCatalog(ts.a)
53 if err != nil {
54 return ts, err
55 }
56
Jon Perritt816d2a02014-03-11 20:49:46 -050057 ts.eps, err = findAllEndpoints(ts.sc, service)
Samuel A. Falvo II0abdb102014-02-13 23:19:26 -080058 if err != nil {
59 return ts, err
60 }
61
62 ts.w = new(tabwriter.Writer)
63 ts.w.Init(os.Stdout, 2, 8, 2, ' ', 0)
64
65 return ts, nil
66}
67
68func setupForCRUD() (*testState, error) {
Jon Perritt816d2a02014-03-11 20:49:46 -050069 ts, err := setupForList("compute")
Samuel A. Falvo II0abdb102014-02-13 23:19:26 -080070 if err != nil {
71 return ts, err
72 }
73
74 ts.imageId = os.Getenv("OS_IMAGE_ID")
75 if ts.imageId == "" {
76 return ts, fmt.Errorf("Expected OS_IMAGE_ID environment variable to be set")
77 }
78
79 ts.flavorId = os.Getenv("OS_FLAVOR_ID")
80 if ts.flavorId == "" {
81 return ts, fmt.Errorf("Expected OS_FLAVOR_ID environment variable to be set")
82 }
83
Samuel A. Falvo II808bb632014-03-12 00:07:50 -070084 ts.flavorIdResize = os.Getenv("OS_FLAVOR_ID_RESIZE")
85 if ts.flavorIdResize == "" {
86 return ts, fmt.Errorf("Expected OS_FLAVOR_ID_RESIZE environment variable to be set")
87 }
88
89 if ts.flavorIdResize == ts.flavorId {
90 return ts, fmt.Errorf("OS_FLAVOR_ID and OS_FLAVOR_ID_RESIZE cannot be the same")
91 }
92
Samuel A. Falvo II0abdb102014-02-13 23:19:26 -080093 ts.region = os.Getenv("OS_REGION_NAME")
94 if ts.region == "" {
95 ts.region = ts.eps[0].Region
96 }
97
98 ts.ep, err = findEndpointForRegion(ts.eps, ts.region)
99 if err != nil {
100 return ts, err
101 }
102
103 return ts, err
104}
105
Jon Perritt816d2a02014-03-11 20:49:46 -0500106func findAllEndpoints(sc *identity.ServiceCatalog, service string) ([]identity.Endpoint, error) {
Samuel A. Falvo II0abdb102014-02-13 23:19:26 -0800107 ces, err := sc.CatalogEntries()
108 if err != nil {
109 return nil, err
110 }
111
112 for _, ce := range ces {
Jon Perritt816d2a02014-03-11 20:49:46 -0500113 if ce.Type == service {
Samuel A. Falvo II0abdb102014-02-13 23:19:26 -0800114 return ce.Endpoints, nil
115 }
116 }
117
Jon Perritt816d2a02014-03-11 20:49:46 -0500118 return nil, fmt.Errorf(service + " endpoint not found.")
Samuel A. Falvo II0abdb102014-02-13 23:19:26 -0800119}
120
121func findEndpointForRegion(eps []identity.Endpoint, r string) (string, error) {
122 for _, ep := range eps {
123 if ep.Region == r {
124 return ep.PublicURL, nil
125 }
126 }
127 return "", fmt.Errorf("Unknown region %s", r)
128}
129
130func countDown(ts *testState, timeout int) (bool, int, error) {
131 if timeout < 1 {
132 return false, 0, errTimeout
133 }
134 time.Sleep(1 * time.Second)
135 timeout--
136
137 gr, err := servers.GetDetail(ts.client, ts.createdServer.Id)
138 if err != nil {
139 return false, timeout, err
140 }
141
142 ts.gottenServer, err = servers.GetServer(gr)
143 if err != nil {
144 return false, timeout, err
145 }
146
147 return true, timeout, nil
148}
149
150func createServer(ts *testState) error {
151 ts.serverName = randomString("ACPTTEST", 16)
152 fmt.Printf("Attempting to create server: %s\n", ts.serverName)
153
154 ts.client = servers.NewClient(ts.ep, ts.a, ts.o)
155
156 cr, err := servers.Create(ts.client, map[string]interface{}{
157 "flavorRef": ts.flavorId,
Samuel A. Falvo IIe246ac02014-02-13 23:20:09 -0800158 "imageRef": ts.imageId,
159 "name": ts.serverName,
Samuel A. Falvo II0abdb102014-02-13 23:19:26 -0800160 })
161 if err != nil {
162 return err
163 }
164
165 ts.createdServer, err = servers.GetServer(cr)
166 return err
167}
168
169func waitForStatus(ts *testState, s string) error {
170 var (
171 inProgress bool
Samuel A. Falvo IIe246ac02014-02-13 23:20:09 -0800172 timeout int
173 err error
Samuel A. Falvo II0abdb102014-02-13 23:19:26 -0800174 )
175
Samuel A. Falvo IIe246ac02014-02-13 23:20:09 -0800176 for inProgress, timeout, err = countDown(ts, 300); inProgress; inProgress, timeout, err = countDown(ts, timeout) {
Samuel A. Falvo II0abdb102014-02-13 23:19:26 -0800177 if ts.gottenServer.Id != ts.createdServer.Id {
178 return fmt.Errorf("created server id (%s) != gotten server id (%s)", ts.createdServer.Id, ts.gottenServer.Id)
179 }
180
181 if ts.gottenServer.Status == s {
Samuel A. Falvo IIca5f9a32014-03-11 17:52:58 -0700182 fmt.Printf("Server reached state %s after %d seconds (approximately)\n", s, 300-timeout)
Samuel A. Falvo II0abdb102014-02-13 23:19:26 -0800183 break
184 }
185 }
186
187 if err == errTimeout {
Samuel A. Falvo IIca5f9a32014-03-11 17:52:58 -0700188 fmt.Printf("Time out -- I'm not waiting around.\n")
Samuel A. Falvo II0abdb102014-02-13 23:19:26 -0800189 err = nil
190 }
191
192 return err
193}
194
195func changeServerName(ts *testState) error {
196 var (
197 inProgress bool
Samuel A. Falvo IIe246ac02014-02-13 23:20:09 -0800198 timeout int
Samuel A. Falvo II0abdb102014-02-13 23:19:26 -0800199 )
200
201 ts.alternateName = randomString("ACPTTEST", 16)
202 for ts.alternateName == ts.serverName {
203 ts.alternateName = randomString("ACPTTEST", 16)
204 }
205 fmt.Println("Attempting to change server name")
206
207 ur, err := servers.Update(ts.client, ts.createdServer.Id, map[string]interface{}{
208 "name": ts.alternateName,
209 })
210 if err != nil {
211 return err
212 }
213
214 ts.updatedServer, err = servers.GetServer(ur)
215 if err != nil {
216 return err
217 }
218
219 if ts.updatedServer.Id != ts.createdServer.Id {
220 return fmt.Errorf("Expected updated and created server to share the same ID")
221 }
222
Samuel A. Falvo IIe246ac02014-02-13 23:20:09 -0800223 for inProgress, timeout, err = countDown(ts, 300); inProgress; inProgress, timeout, err = countDown(ts, timeout) {
Samuel A. Falvo II0abdb102014-02-13 23:19:26 -0800224 if ts.gottenServer.Id != ts.updatedServer.Id {
225 return fmt.Errorf("Updated server ID (%s) != gotten server ID (%s)", ts.updatedServer.Id, ts.gottenServer.Id)
226 }
227
228 if ts.gottenServer.Name == ts.alternateName {
229 fmt.Printf("Server updated after %d seconds (approximately)\n", 300-timeout)
230 break
231 }
232 }
233
234 if err == errTimeout {
235 fmt.Printf("I'm not waiting around.\n")
236 err = nil
237 }
238
239 return err
240}
241
Samuel A. Falvo II808bb632014-03-12 00:07:50 -0700242func makeNewPassword(oldPass string) string {
243 fmt.Println("Current password: "+oldPass)
Samuel A. Falvo IIca5f9a32014-03-11 17:52:58 -0700244 randomPassword := randomString("", 16)
Samuel A. Falvo II808bb632014-03-12 00:07:50 -0700245 for randomPassword == oldPass {
Samuel A. Falvo IIca5f9a32014-03-11 17:52:58 -0700246 randomPassword = randomString("", 16)
247 }
248 fmt.Println(" New password: "+randomPassword)
Samuel A. Falvo II808bb632014-03-12 00:07:50 -0700249 return randomPassword
250}
251
252func changeAdminPassword(ts *testState) error {
253 randomPassword := makeNewPassword(ts.createdServer.AdminPass)
Samuel A. Falvo IIca5f9a32014-03-11 17:52:58 -0700254
255 err := servers.ChangeAdminPassword(ts.client, ts.createdServer.Id, randomPassword)
256 if err != nil {
257 return err
258 }
259
260 err = waitForStatus(ts, "PASSWORD")
261 if err != nil {
262 return err
263 }
264
265 return waitForStatus(ts, "ACTIVE")
266}
267
Samuel A. Falvo II41c9f612014-03-11 19:00:10 -0700268func rebootServer(ts *testState) error {
269 fmt.Println("Attempting reboot of server "+ts.createdServer.Id)
270 err := servers.Reboot(ts.client, ts.createdServer.Id, servers.OSReboot)
271 if err != nil {
272 return err
273 }
274
275 err = waitForStatus(ts, "REBOOT")
276 if err != nil {
277 return err
278 }
279
280 return waitForStatus(ts, "ACTIVE")
281}
282
Samuel A. Falvo II808bb632014-03-12 00:07:50 -0700283func rebuildServer(ts *testState) error {
284 fmt.Println("Attempting to rebuild server "+ts.createdServer.Id)
285
286 newPassword := makeNewPassword(ts.createdServer.AdminPass)
287 newName := randomString("ACPTTEST", 16)
288 sr, err := servers.Rebuild(ts.client, ts.createdServer.Id, newName, newPassword, ts.imageId, nil)
289 if err != nil {
290 return err
291 }
292
293 s, err := servers.GetServer(sr)
294 if err != nil {
295 return err
296 }
297 if s.Id != ts.createdServer.Id {
298 return fmt.Errorf("Expected rebuilt server ID of %s; got %s", ts.createdServer.Id, s.Id)
299 }
300
301 err = waitForStatus(ts, "REBUILD")
302 if err != nil {
303 return err
304 }
305
306 return waitForStatus(ts, "ACTIVE")
307}
308
309func resizeServer(ts *testState) error {
310 fmt.Println("Attempting to resize server "+ts.createdServer.Id)
311
312 err := servers.Resize(ts.client, ts.createdServer.Id, ts.flavorIdResize)
313 if err != nil {
314 return err
315 }
316
317 err = waitForStatus(ts, "RESIZE")
318 if err != nil {
319 return err
320 }
321
322 return waitForStatus(ts, "VERIFY_RESIZE")
323}
324
325func confirmResize(ts *testState) error {
326 fmt.Println("Attempting to confirm resize for server "+ts.createdServer.Id)
327
328 err := servers.ConfirmResize(ts.client, ts.createdServer.Id)
329 if err != nil {
330 return err
331 }
332
333 return waitForStatus(ts, "ACTIVE")
334}
335
336func revertResize(ts *testState) error {
337 fmt.Println("Attempting to revert resize for server "+ts.createdServer.Id)
338
339 err := servers.RevertResize(ts.client, ts.createdServer.Id)
340 if err != nil {
341 return err
342 }
343
344 err = waitForStatus(ts, "REVERT_RESIZE")
345 if err != nil {
346 return err
347 }
348
349 return waitForStatus(ts, "ACTIVE")
350}
351
Samuel A. Falvo II0abdb102014-02-13 23:19:26 -0800352// randomString generates a string of given length, but random content.
353// All content will be within the ASCII graphic character set.
354// (Implementation from Even Shaw's contribution on
355// http://stackoverflow.com/questions/12771930/what-is-the-fastest-way-to-generate-a-long-random-string-in-go).
356func randomString(prefix string, n int) string {
357 const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
358 var bytes = make([]byte, n)
359 rand.Read(bytes)
360 for i, b := range bytes {
361 bytes[i] = alphanum[b%byte(len(alphanum))]
362 }
363 return prefix + string(bytes)
364}