blob: 100ea5ec4fd681924ae030d5d4287c5c88e91166 [file] [log] [blame]
Samuel A. Falvo II43d83532014-07-31 14:34:48 -07001// +build acceptance
2
3package compute
4
5import (
6 "crypto/rand"
7 "fmt"
Samuel A. Falvo II43d83532014-07-31 14:34:48 -07008 "os"
9 "text/tabwriter"
10 "time"
Jamie Hannafordc8fc6ea2014-09-10 13:59:58 +020011
12 "github.com/rackspace/gophercloud/openstack/compute/v2/servers"
13 identity "github.com/rackspace/gophercloud/openstack/identity/v2"
14 "github.com/rackspace/gophercloud/openstack/utils"
Samuel A. Falvo II43d83532014-07-31 14:34:48 -070015)
16
17var errTimeout = fmt.Errorf("Timeout.")
18
19type testState struct {
Jon Perritt5eb55b12014-08-18 14:48:23 -050020 o identity.AuthOptions
21 a identity.AuthResults
22 sc *identity.ServiceCatalog
23 eps []identity.Endpoint
24 w *tabwriter.Writer
25 imageId string
26 flavorId string
27 region string
28 ep string
29 client *servers.Client
30 createdServer *servers.Server
31 gottenServer *servers.Server
32 updatedServer *servers.Server
33 serverName string
34 alternateName string
Samuel A. Falvo II43d83532014-07-31 14:34:48 -070035 flavorIdResize string
36}
37
38func SetupForList(service string) (*testState, error) {
39 var err error
40
41 ts := new(testState)
42
43 ts.o, err = utils.AuthOptions()
44 if err != nil {
45 return ts, err
46 }
47
48 ts.a, err = identity.Authenticate(ts.o)
49 if err != nil {
50 return ts, err
51 }
52
53 ts.sc, err = identity.GetServiceCatalog(ts.a)
54 if err != nil {
55 return ts, err
56 }
57
58 ts.eps, err = FindAllEndpoints(ts.sc, service)
59 if err != nil {
60 return ts, err
61 }
62
63 ts.w = new(tabwriter.Writer)
64 ts.w.Init(os.Stdout, 2, 8, 2, ' ', 0)
65
66 return ts, nil
67}
68
69func SetupForCRUD() (*testState, error) {
70 ts, err := SetupForList("compute")
71 if err != nil {
72 return ts, err
73 }
74
75 ts.imageId = os.Getenv("OS_IMAGE_ID")
76 if ts.imageId == "" {
77 return ts, fmt.Errorf("Expected OS_IMAGE_ID environment variable to be set")
78 }
79
80 ts.flavorId = os.Getenv("OS_FLAVOR_ID")
81 if ts.flavorId == "" {
82 return ts, fmt.Errorf("Expected OS_FLAVOR_ID environment variable to be set")
83 }
84
85 ts.flavorIdResize = os.Getenv("OS_FLAVOR_ID_RESIZE")
86 if ts.flavorIdResize == "" {
87 return ts, fmt.Errorf("Expected OS_FLAVOR_ID_RESIZE environment variable to be set")
88 }
89
90 if ts.flavorIdResize == ts.flavorId {
91 return ts, fmt.Errorf("OS_FLAVOR_ID and OS_FLAVOR_ID_RESIZE cannot be the same")
92 }
93
94 ts.region = os.Getenv("OS_REGION_NAME")
95 if ts.region == "" {
96 ts.region = ts.eps[0].Region
97 }
98
99 ts.ep, err = FindEndpointForRegion(ts.eps, ts.region)
100 if err != nil {
101 return ts, err
102 }
103
104 return ts, err
105}
106
107func FindAllEndpoints(sc *identity.ServiceCatalog, service string) ([]identity.Endpoint, error) {
108 ces, err := sc.CatalogEntries()
109 if err != nil {
110 return nil, err
111 }
112
113 for _, ce := range ces {
114 if ce.Type == service {
115 return ce.Endpoints, nil
116 }
117 }
118
119 return nil, fmt.Errorf(service + " endpoint not found.")
120}
121
122func FindEndpointForRegion(eps []identity.Endpoint, r string) (string, error) {
123 for _, ep := range eps {
124 if ep.Region == r {
125 return ep.PublicURL, nil
126 }
127 }
128 return "", fmt.Errorf("Unknown region %s", r)
129}
130
131func CountDown(ts *testState, timeout int) (bool, int, error) {
132 if timeout < 1 {
133 return false, 0, errTimeout
134 }
135 time.Sleep(1 * time.Second)
136 timeout--
137
138 gr, err := servers.GetDetail(ts.client, ts.createdServer.Id)
139 if err != nil {
140 return false, timeout, err
141 }
142
143 ts.gottenServer, err = servers.GetServer(gr)
144 if err != nil {
145 return false, timeout, err
146 }
147
148 return true, timeout, nil
149}
150
151func CreateServer(ts *testState) error {
152 ts.serverName = RandomString("ACPTTEST", 16)
153 fmt.Printf("Attempting to create server: %s\n", ts.serverName)
154
155 ts.client = servers.NewClient(ts.ep, ts.a, ts.o)
156
157 cr, err := servers.Create(ts.client, map[string]interface{}{
158 "flavorRef": ts.flavorId,
159 "imageRef": ts.imageId,
160 "name": ts.serverName,
161 })
162 if err != nil {
163 return err
164 }
165
166 ts.createdServer, err = servers.GetServer(cr)
167 return err
168}
169
170func WaitForStatus(ts *testState, s string) error {
171 var (
172 inProgress bool
173 timeout int
174 err error
175 )
176
177 for inProgress, timeout, err = CountDown(ts, 300); inProgress; inProgress, timeout, err = CountDown(ts, timeout) {
178 if ts.gottenServer.Id != ts.createdServer.Id {
179 return fmt.Errorf("created server id (%s) != gotten server id (%s)", ts.createdServer.Id, ts.gottenServer.Id)
180 }
181
182 if ts.gottenServer.Status == s {
183 fmt.Printf("Server reached state %s after %d seconds (approximately)\n", s, 300-timeout)
184 break
185 }
186 }
187
188 if err == errTimeout {
189 fmt.Printf("Time out -- I'm not waiting around.\n")
190 err = nil
191 }
192
193 return err
194}
195
196func ChangeServerName(ts *testState) error {
197 var (
198 inProgress bool
199 timeout int
200 )
201
202 ts.alternateName = RandomString("ACPTTEST", 16)
203 for ts.alternateName == ts.serverName {
204 ts.alternateName = RandomString("ACPTTEST", 16)
205 }
206 fmt.Println("Attempting to change server name")
207
208 ur, err := servers.Update(ts.client, ts.createdServer.Id, map[string]interface{}{
209 "name": ts.alternateName,
210 })
211 if err != nil {
212 return err
213 }
214
215 ts.updatedServer, err = servers.GetServer(ur)
216 if err != nil {
217 return err
218 }
219
220 if ts.updatedServer.Id != ts.createdServer.Id {
221 return fmt.Errorf("Expected updated and created server to share the same ID")
222 }
223
224 for inProgress, timeout, err = CountDown(ts, 300); inProgress; inProgress, timeout, err = CountDown(ts, timeout) {
225 if ts.gottenServer.Id != ts.updatedServer.Id {
226 return fmt.Errorf("Updated server ID (%s) != gotten server ID (%s)", ts.updatedServer.Id, ts.gottenServer.Id)
227 }
228
229 if ts.gottenServer.Name == ts.alternateName {
230 fmt.Printf("Server updated after %d seconds (approximately)\n", 300-timeout)
231 break
232 }
233 }
234
235 if err == errTimeout {
236 fmt.Printf("I'm not waiting around.\n")
237 err = nil
238 }
239
240 return err
241}
242
243func MakeNewPassword(oldPass string) string {
Jon Perritt5eb55b12014-08-18 14:48:23 -0500244 fmt.Println("Current password: " + oldPass)
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700245 randomPassword := RandomString("", 16)
246 for randomPassword == oldPass {
247 randomPassword = RandomString("", 16)
248 }
Jon Perritt5eb55b12014-08-18 14:48:23 -0500249 fmt.Println(" New password: " + randomPassword)
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700250 return randomPassword
251}
252
253func ChangeAdminPassword(ts *testState) error {
254 randomPassword := MakeNewPassword(ts.createdServer.AdminPass)
Jon Perritt5eb55b12014-08-18 14:48:23 -0500255
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700256 err := servers.ChangeAdminPassword(ts.client, ts.createdServer.Id, randomPassword)
257 if err != nil {
258 return err
259 }
Jon Perritt5eb55b12014-08-18 14:48:23 -0500260
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700261 err = WaitForStatus(ts, "PASSWORD")
262 if err != nil {
263 return err
264 }
Jon Perritt5eb55b12014-08-18 14:48:23 -0500265
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700266 return WaitForStatus(ts, "ACTIVE")
267}
268
269func RebootServer(ts *testState) error {
Jon Perritt5eb55b12014-08-18 14:48:23 -0500270 fmt.Println("Attempting reboot of server " + ts.createdServer.Id)
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700271 err := servers.Reboot(ts.client, ts.createdServer.Id, servers.OSReboot)
272 if err != nil {
273 return err
274 }
Jon Perritt5eb55b12014-08-18 14:48:23 -0500275
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700276 err = WaitForStatus(ts, "REBOOT")
277 if err != nil {
278 return err
279 }
Jon Perritt5eb55b12014-08-18 14:48:23 -0500280
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700281 return WaitForStatus(ts, "ACTIVE")
282}
283
284func RebuildServer(ts *testState) error {
Jon Perritt5eb55b12014-08-18 14:48:23 -0500285 fmt.Println("Attempting to rebuild server " + ts.createdServer.Id)
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700286
287 newPassword := MakeNewPassword(ts.createdServer.AdminPass)
288 newName := RandomString("ACPTTEST", 16)
289 sr, err := servers.Rebuild(ts.client, ts.createdServer.Id, newName, newPassword, ts.imageId, nil)
290 if err != nil {
291 return err
292 }
Jon Perritt5eb55b12014-08-18 14:48:23 -0500293
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700294 s, err := servers.GetServer(sr)
295 if err != nil {
296 return err
297 }
298 if s.Id != ts.createdServer.Id {
299 return fmt.Errorf("Expected rebuilt server ID of %s; got %s", ts.createdServer.Id, s.Id)
300 }
301
302 err = WaitForStatus(ts, "REBUILD")
303 if err != nil {
304 return err
305 }
Jon Perritt5eb55b12014-08-18 14:48:23 -0500306
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700307 return WaitForStatus(ts, "ACTIVE")
308}
309
310func ResizeServer(ts *testState) error {
Jon Perritt5eb55b12014-08-18 14:48:23 -0500311 fmt.Println("Attempting to resize server " + ts.createdServer.Id)
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700312
313 err := servers.Resize(ts.client, ts.createdServer.Id, ts.flavorIdResize)
314 if err != nil {
315 return err
316 }
317
318 err = WaitForStatus(ts, "RESIZE")
319 if err != nil {
320 return err
321 }
322
323 return WaitForStatus(ts, "VERIFY_RESIZE")
324}
325
326func ConfirmResize(ts *testState) error {
Jon Perritt5eb55b12014-08-18 14:48:23 -0500327 fmt.Println("Attempting to confirm resize for server " + ts.createdServer.Id)
328
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700329 err := servers.ConfirmResize(ts.client, ts.createdServer.Id)
330 if err != nil {
331 return err
332 }
Jon Perritt5eb55b12014-08-18 14:48:23 -0500333
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700334 return WaitForStatus(ts, "ACTIVE")
335}
336
337func RevertResize(ts *testState) error {
Jon Perritt5eb55b12014-08-18 14:48:23 -0500338 fmt.Println("Attempting to revert resize for server " + ts.createdServer.Id)
339
Samuel A. Falvo II43d83532014-07-31 14:34:48 -0700340 err := servers.RevertResize(ts.client, ts.createdServer.Id)
341 if err != nil {
342 return err
343 }
344
345 err = WaitForStatus(ts, "REVERT_RESIZE")
346 if err != nil {
347 return err
348 }
349
350 return WaitForStatus(ts, "ACTIVE")
351}
352
353// randomString generates a string of given length, but random content.
354// All content will be within the ASCII graphic character set.
355// (Implementation from Even Shaw's contribution on
356// http://stackoverflow.com/questions/12771930/what-is-the-fastest-way-to-generate-a-long-random-string-in-go).
357func RandomString(prefix string, n int) string {
358 const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
359 var bytes = make([]byte, n)
360 rand.Read(bytes)
361 for i, b := range bytes {
362 bytes[i] = alphanum[b%byte(len(alphanum))]
363 }
364 return prefix + string(bytes)
365}