blob: 67858f123baa4a9915e2bece050f18de35dd9261 [file] [log] [blame]
Samuel A. Falvo II704a7502013-07-10 15:23:43 -07001package main
2
3import (
4 "fmt"
5 "os"
Samuel A. Falvo IIe91ff6d2013-07-11 15:46:10 -07006 "crypto/rand"
Samuel A. Falvo II8935ca32013-07-25 21:27:06 -07007 "github.com/rackspace/gophercloud"
Samuel A. Falvo II704a7502013-07-10 15:23:43 -07008)
9
10// getCredentials will verify existence of needed credential information
11// provided through environment variables. This function will not return
12// if at least one piece of required information is missing.
13func getCredentials() (provider, username, password string) {
14 provider = os.Getenv("SDK_PROVIDER")
15 username = os.Getenv("SDK_USERNAME")
16 password = os.Getenv("SDK_PASSWORD")
17
18 if (provider == "") || (username == "") || (password == "") {
19 fmt.Fprintf(os.Stderr, "One or more of the following environment variables aren't set:\n")
20 fmt.Fprintf(os.Stderr, " SDK_PROVIDER=\"%s\"\n", provider)
21 fmt.Fprintf(os.Stderr, " SDK_USERNAME=\"%s\"\n", username)
22 fmt.Fprintf(os.Stderr, " SDK_PASSWORD=\"%s\"\n", password)
23 os.Exit(1)
24 }
25
26 return
27}
Samuel A. Falvo IIe91ff6d2013-07-11 15:46:10 -070028
29// randomString generates a string of given length, but random content.
30// All content will be within the ASCII graphic character set.
31// (Implementation from Even Shaw's contribution on
32// 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 -070033func randomString(prefix string, n int) string {
Samuel A. Falvo IIe91ff6d2013-07-11 15:46:10 -070034 const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
35 var bytes = make([]byte, n)
36 rand.Read(bytes)
37 for i, b := range bytes {
38 bytes[i] = alphanum[b % byte(len(alphanum))]
39 }
Samuel A. Falvo IIe3b2d7a2013-07-12 11:08:02 -070040 return prefix + string(bytes)
Samuel A. Falvo II8935ca32013-07-25 21:27:06 -070041}
42
43// aSuitableImage finds a minimal image for use in dynamically creating servers.
44// If none can be found, this function will panic.
45func aSuitableImage(api gophercloud.CloudServersProvider) string {
46 images, err := api.ListImages()
47 if err != nil {
48 panic(err)
49 }
50
51 // TODO(sfalvo):
52 // Works for Rackspace, might not work for your provider!
53 // Need to figure out why ListImages() provides 0 values for
54 // Ram and Disk fields.
55 //
56 // Until then, just return Ubuntu 12.04 LTS.
57 for i := 0; i < len(images); i++ {
58 if images[i].Id == "23b564c9-c3e6-49f9-bc68-86c7a9ab5018" {
59 return images[i].Id
60 }
61 }
62 panic("Image 23b564c9-c3e6-49f9-bc68-86c7a9ab5018 (Ubuntu 12.04 LTS) not found.")
63}
64
65// aSuitableFlavor finds the minimum flavor capable of running the test image
66// chosen by aSuitableImage. If none can be found, this function will panic.
67func aSuitableFlavor(api gophercloud.CloudServersProvider) string {
68 flavors, err := api.ListFlavors()
69 if err != nil {
70 panic(err)
71 }
72
73 // TODO(sfalvo):
74 // Works for Rackspace, might not work for your provider!
75 // Need to figure out why ListFlavors() provides 0 values for
76 // Ram and Disk fields.
77 //
78 // Until then, just return Ubuntu 12.04 LTS.
79 for i := 0; i < len(flavors); i++ {
80 if flavors[i].Id == "2" {
81 return flavors[i].Id
82 }
83 }
84 panic("Flavor 2 (512MB 1-core 20GB machine) not found.")
85}
86
87// createServer creates a new server in a manner compatible with acceptance testing.
88// In particular, it ensures that the name of the server always starts with "ACPTTEST--",
89// which the delete servers acceptance test relies on to identify servers to delete.
90// Passing in empty image and flavor references will force the use of reasonable defaults.
91// An empty name string will result in a dynamically created name prefixed with "ACPTTEST--".
92// A blank admin password will cause a password to be automatically generated; however,
93// at present no means of recovering this password exists, as no acceptance tests yet require
94// this data.
Samuel A. Falvo II80699602013-07-25 23:35:57 -070095func createServer(servers gophercloud.CloudServersProvider, imageRef, flavorRef, name, adminPass string) (string, error) {
Samuel A. Falvo II8935ca32013-07-25 21:27:06 -070096 if imageRef == "" {
97 imageRef = aSuitableImage(servers)
98 }
99
100 if flavorRef == "" {
101 flavorRef = aSuitableFlavor(servers)
102 }
103
104 if len(name) < 1 {
105 name = randomString("ACPTTEST", 16)
106 }
107
108 if (len(name) < 8) || (name[0:8] != "ACPTTEST") {
109 name = fmt.Sprintf("ACPTTEST--%s", name)
110 }
111
Samuel A. Falvo II80699602013-07-25 23:35:57 -0700112 newServer, err := servers.CreateServer(gophercloud.NewServer{
Samuel A. Falvo II8935ca32013-07-25 21:27:06 -0700113 Name: name,
114 ImageRef: imageRef,
115 FlavorRef: flavorRef,
116 AdminPass: adminPass,
117 })
118
Samuel A. Falvo II80699602013-07-25 23:35:57 -0700119 if err != nil {
120 return "", err
121 }
122
123 return newServer.Id, nil
Samuel A. Falvo II8935ca32013-07-25 21:27:06 -0700124}
Samuel A. Falvo II8512e9a2013-07-26 22:53:29 -0700125
126// findAlternativeFlavor locates a flavor to resize a server to. It is guaranteed to be different
127// than what aSuitableFlavor() returns. If none could be found, this function will panic.
128func findAlternativeFlavor() string {
129 return "3" // 1GB image, up from 512MB image
130}