blob: 396241ca1ac5d8887a261aad31d451e24455f732 [file] [log] [blame]
Samuel A. Falvo II43d83532014-07-31 14:34:48 -07001// +build acceptance
2
3package tools
4
5import (
6 "crypto/rand"
7 "fmt"
Samuel A. Falvo II43d83532014-07-31 14:34:48 -07008 "os"
9 "text/tabwriter"
10 "time"
Ash Wilson5deff162014-09-09 09:33:03 -040011
12 "github.com/rackspace/gophercloud"
Ash Wilsona26eea02014-09-10 16:21:49 -040013 "github.com/rackspace/gophercloud/openstack/compute/v2/servers"
Ash Wilson5deff162014-09-09 09:33:03 -040014 identity "github.com/rackspace/gophercloud/openstack/identity/v2"
15 "github.com/rackspace/gophercloud/openstack/utils"
Samuel A. Falvo II43d83532014-07-31 14:34:48 -070016)
17
18var errTimeout = fmt.Errorf("Timeout.")
19
20type testState struct {
Ash Wilson5deff162014-09-09 09:33:03 -040021 O gophercloud.AuthOptions
Jon Perritt5eb55b12014-08-18 14:48:23 -050022 A identity.AuthResults
23 SC *identity.ServiceCatalog
24 EPs []identity.Endpoint
25 W *tabwriter.Writer
26 ImageId string
27 FlavorId string
28 Region string
29 EP string
30 Client *servers.Client
31 CreatedServer *servers.Server
32 GottenServer *servers.Server
33 UpdatedServer *servers.Server
34 ServerName string
35 AlternateName string
Samuel A. Falvo II43d83532014-07-31 14:34:48 -070036 FlavorIdResize string
37}
38
39func SetupForList(service string) (*testState, error) {
40 var err error
41
42 ts := new(testState)
43
44 ts.O, err = utils.AuthOptions()
45 if err != nil {
46 return ts, err
47 }
48
Ash Wilson61b2d342014-09-09 09:46:01 -040049 client := &gophercloud.ServiceClient{Endpoint: ts.O.IdentityEndpoint + "/"}
50 ts.A, err = identity.Authenticate(client, ts.O)
Samuel A. Falvo II43d83532014-07-31 14:34:48 -070051 if err != nil {
52 return ts, err
53 }
54
55 ts.SC, err = identity.GetServiceCatalog(ts.A)
56 if err != nil {
57 return ts, err
58 }
59
60 ts.EPs, err = FindAllEndpoints(ts.SC, service)
61 if err != nil {
62 return ts, err
63 }
64
65 ts.W = new(tabwriter.Writer)
66 ts.W.Init(os.Stdout, 2, 8, 2, ' ', 0)
67
68 return ts, nil
69}
70
71func SetupForCRUD() (*testState, error) {
72 ts, err := SetupForList("compute")
73 if err != nil {
74 return ts, err
75 }
76
77 ts.ImageId = os.Getenv("OS_IMAGE_ID")
78 if ts.ImageId == "" {
79 return ts, fmt.Errorf("Expected OS_IMAGE_ID environment variable to be set")
80 }
81
82 ts.FlavorId = os.Getenv("OS_FLAVOR_ID")
83 if ts.FlavorId == "" {
84 return ts, fmt.Errorf("Expected OS_FLAVOR_ID environment variable to be set")
85 }
86
87 ts.FlavorIdResize = os.Getenv("OS_FLAVOR_ID_RESIZE")
88 if ts.FlavorIdResize == "" {
89 return ts, fmt.Errorf("Expected OS_FLAVOR_ID_RESIZE environment variable to be set")
90 }
91
92 if ts.FlavorIdResize == ts.FlavorId {
93 return ts, fmt.Errorf("OS_FLAVOR_ID and OS_FLAVOR_ID_RESIZE cannot be the same")
94 }
95
96 ts.Region = os.Getenv("OS_REGION_NAME")
97 if ts.Region == "" {
98 ts.Region = ts.EPs[0].Region
99 }
100
101 ts.EP, err = FindEndpointForRegion(ts.EPs, ts.Region)
102 if err != nil {
103 return ts, err
104 }
105
106 return ts, err
107}
108
109func FindAllEndpoints(sc *identity.ServiceCatalog, service string) ([]identity.Endpoint, error) {
110 ces, err := sc.CatalogEntries()
111 if err != nil {
112 return nil, err
113 }
114
115 for _, ce := range ces {
116 if ce.Type == service {
117 return ce.Endpoints, nil
118 }
119 }
120
121 return nil, fmt.Errorf(service + " endpoint not found.")
122}
123
124func FindEndpointForRegion(eps []identity.Endpoint, r string) (string, error) {
125 for _, ep := range eps {
126 if ep.Region == r {
127 return ep.PublicURL, nil
128 }
129 }
130 return "", fmt.Errorf("Unknown region %s", r)
131}
132
133func CountDown(ts *testState, timeout int) (bool, int, error) {
134 if timeout < 1 {
135 return false, 0, errTimeout
136 }
137 time.Sleep(1 * time.Second)
138 timeout--
139
140 gr, err := servers.GetDetail(ts.Client, ts.CreatedServer.Id)
141 if err != nil {
142 return false, timeout, err
143 }
144
145 ts.GottenServer, err = servers.GetServer(gr)
146 if err != nil {
147 return false, timeout, err
148 }
149
150 return true, timeout, nil
151}
152
153func CreateServer(ts *testState) error {
154 ts.ServerName = RandomString("ACPTTEST", 16)
155 fmt.Printf("Attempting to create server: %s\n", ts.ServerName)
156
157 ts.Client = servers.NewClient(ts.EP, ts.A, ts.O)
158
159 cr, err := servers.Create(ts.Client, map[string]interface{}{
160 "flavorRef": ts.FlavorId,
161 "imageRef": ts.ImageId,
162 "name": ts.ServerName,
163 })
164 if err != nil {
165 return err
166 }
167
168 ts.CreatedServer, err = servers.GetServer(cr)
169 return err
170}
171
172func WaitForStatus(ts *testState, s string) error {
173 var (
174 inProgress bool
175 timeout int
176 err error
177 )
178
179 for inProgress, timeout, err = CountDown(ts, 300); inProgress; inProgress, timeout, err = CountDown(ts, timeout) {
180 if ts.GottenServer.Id != ts.CreatedServer.Id {
181 return fmt.Errorf("created server id (%s) != gotten server id (%s)", ts.CreatedServer.Id, ts.GottenServer.Id)
182 }
183
184 if ts.GottenServer.Status == s {
185 fmt.Printf("Server reached state %s after %d seconds (approximately)\n", s, 300-timeout)
186 break
187 }
188 }
189
190 if err == errTimeout {
191 fmt.Printf("Time out -- I'm not waiting around.\n")
192 err = nil
193 }
194
195 return err
196}
197
198func ChangeServerName(ts *testState) error {
199 var (
200 inProgress bool
201 timeout int
202 )
203
204 ts.AlternateName = RandomString("ACPTTEST", 16)
205 for ts.AlternateName == ts.ServerName {
206 ts.AlternateName = RandomString("ACPTTEST", 16)
207 }
208 fmt.Println("Attempting to change server name")
209
210 ur, err := servers.Update(ts.Client, ts.CreatedServer.Id, map[string]interface{}{
211 "name": ts.AlternateName,
212 })
213 if err != nil {
214 return err
215 }
216
217 ts.UpdatedServer, err = servers.GetServer(ur)
218 if err != nil {
219 return err
220 }
221
222 if ts.UpdatedServer.Id != ts.CreatedServer.Id {
223 return fmt.Errorf("Expected updated and created server to share the same ID")
224 }
225
226 for inProgress, timeout, err = CountDown(ts, 300); inProgress; inProgress, timeout, err = CountDown(ts, timeout) {
227 if ts.GottenServer.Id != ts.UpdatedServer.Id {
228 return fmt.Errorf("Updated server ID (%s) != gotten server ID (%s)", ts.UpdatedServer.Id, ts.GottenServer.Id)
229 }
230
231 if ts.GottenServer.Name == ts.AlternateName {
232 fmt.Printf("Server updated after %d seconds (approximately)\n", 300-timeout)
233 break
234 }
235 }
236
237 if err == errTimeout {
238 fmt.Printf("I'm not waiting around.\n")
239 err = nil
240 }
241
242 return err
243}
244
245func MakeNewPassword(oldPass string) string {
Jon Perritt5eb55b12014-08-18 14:48:23 -0500246 fmt.Println("Current password: " + oldPass)
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700247 randomPassword := RandomString("", 16)
248 for randomPassword == oldPass {
249 randomPassword = RandomString("", 16)
250 }
Jon Perritt5eb55b12014-08-18 14:48:23 -0500251 fmt.Println(" New password: " + randomPassword)
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700252 return randomPassword
253}
254
255func ChangeAdminPassword(ts *testState) error {
256 randomPassword := MakeNewPassword(ts.CreatedServer.AdminPass)
Jon Perritt5eb55b12014-08-18 14:48:23 -0500257
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700258 err := servers.ChangeAdminPassword(ts.Client, ts.CreatedServer.Id, randomPassword)
259 if err != nil {
260 return err
261 }
Jon Perritt5eb55b12014-08-18 14:48:23 -0500262
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700263 err = WaitForStatus(ts, "PASSWORD")
264 if err != nil {
265 return err
266 }
Jon Perritt5eb55b12014-08-18 14:48:23 -0500267
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700268 return WaitForStatus(ts, "ACTIVE")
269}
270
271func RebootServer(ts *testState) error {
Jon Perritt5eb55b12014-08-18 14:48:23 -0500272 fmt.Println("Attempting reboot of server " + ts.CreatedServer.Id)
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700273 err := servers.Reboot(ts.Client, ts.CreatedServer.Id, servers.OSReboot)
274 if err != nil {
275 return err
276 }
Jon Perritt5eb55b12014-08-18 14:48:23 -0500277
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700278 err = WaitForStatus(ts, "REBOOT")
279 if err != nil {
280 return err
281 }
Jon Perritt5eb55b12014-08-18 14:48:23 -0500282
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700283 return WaitForStatus(ts, "ACTIVE")
284}
285
286func RebuildServer(ts *testState) error {
Jon Perritt5eb55b12014-08-18 14:48:23 -0500287 fmt.Println("Attempting to rebuild server " + ts.CreatedServer.Id)
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700288
289 newPassword := MakeNewPassword(ts.CreatedServer.AdminPass)
290 newName := RandomString("ACPTTEST", 16)
291 sr, err := servers.Rebuild(ts.Client, ts.CreatedServer.Id, newName, newPassword, ts.ImageId, nil)
292 if err != nil {
293 return err
294 }
Jon Perritt5eb55b12014-08-18 14:48:23 -0500295
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700296 s, err := servers.GetServer(sr)
297 if err != nil {
298 return err
299 }
300 if s.Id != ts.CreatedServer.Id {
301 return fmt.Errorf("Expected rebuilt server ID of %s; got %s", ts.CreatedServer.Id, s.Id)
302 }
303
304 err = WaitForStatus(ts, "REBUILD")
305 if err != nil {
306 return err
307 }
Jon Perritt5eb55b12014-08-18 14:48:23 -0500308
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700309 return WaitForStatus(ts, "ACTIVE")
310}
311
312func ResizeServer(ts *testState) error {
Jon Perritt5eb55b12014-08-18 14:48:23 -0500313 fmt.Println("Attempting to resize server " + ts.CreatedServer.Id)
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700314
315 err := servers.Resize(ts.Client, ts.CreatedServer.Id, ts.FlavorIdResize)
316 if err != nil {
317 return err
318 }
319
320 err = WaitForStatus(ts, "RESIZE")
321 if err != nil {
322 return err
323 }
324
325 return WaitForStatus(ts, "VERIFY_RESIZE")
326}
327
328func ConfirmResize(ts *testState) error {
Jon Perritt5eb55b12014-08-18 14:48:23 -0500329 fmt.Println("Attempting to confirm resize for server " + ts.CreatedServer.Id)
330
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700331 err := servers.ConfirmResize(ts.Client, ts.CreatedServer.Id)
332 if err != nil {
333 return err
334 }
Jon Perritt5eb55b12014-08-18 14:48:23 -0500335
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700336 return WaitForStatus(ts, "ACTIVE")
337}
338
339func RevertResize(ts *testState) error {
Jon Perritt5eb55b12014-08-18 14:48:23 -0500340 fmt.Println("Attempting to revert resize for server " + ts.CreatedServer.Id)
341
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700342 err := servers.RevertResize(ts.Client, ts.CreatedServer.Id)
343 if err != nil {
344 return err
345 }
346
347 err = WaitForStatus(ts, "REVERT_RESIZE")
348 if err != nil {
349 return err
350 }
351
352 return WaitForStatus(ts, "ACTIVE")
353}
354
355// randomString generates a string of given length, but random content.
356// All content will be within the ASCII graphic character set.
357// (Implementation from Even Shaw's contribution on
358// http://stackoverflow.com/questions/12771930/what-is-the-fastest-way-to-generate-a-long-random-string-in-go).
359func RandomString(prefix string, n int) string {
360 const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
361 var bytes = make([]byte, n)
362 rand.Read(bytes)
363 for i, b := range bytes {
364 bytes[i] = alphanum[b%byte(len(alphanum))]
365 }
366 return prefix + string(bytes)
367}