blob: 93f4ce41c405c1f7cd71b90ad500d13ed7060463 [file] [log] [blame]
Jamie Hannafordfac40db2015-02-09 17:27:08 +01001package instances
2
3import (
4 "fmt"
5
6 "github.com/racker/perigee"
7 "github.com/rackspace/gophercloud"
8)
9
10// CreateOptsBuilder is the top-level interface for create options.
11type CreateOptsBuilder interface {
12 ToInstanceCreateMap() (map[string]interface{}, error)
13}
14
15// DatastoreOpts represents the configuration for how an instance stores data.
16type DatastoreOpts struct {
17 Version string
18 Type string
19}
20
21func (opts DatastoreOpts) ToMap() (map[string]string, error) {
22 return map[string]string{
23 "version": opts.Version,
24 "type": opts.Type,
25 }, nil
26}
27
28// DatabaseOpts is the struct responsible for configuring a database; often in
29// the context of an instance.
30type DatabaseOpts struct {
31 // Specifies the name of the database. Optional.
32 Name string
33
34 // Set of symbols and encodings. Optional; the default character set is utf8.
35 CharSet string
36
37 // Set of rules for comparing characters in a character set. Optional; the
38 // default value for collate is utf8_general_ci.
39 Collate string
40}
41
42func (opts DatabaseOpts) ToMap() (map[string]string, error) {
43 db := map[string]string{}
44 if opts.Name != "" {
45 db["name"] = opts.Name
46 }
47 if opts.CharSet != "" {
48 db["character_set"] = opts.CharSet
49 }
50 if opts.Collate != "" {
51 db["collate"] = opts.Collate
52 }
53 return db, nil
54}
55
56type DatabasesOpts []DatabaseOpts
57
58func (opts DatabasesOpts) ToMap() ([]map[string]string, error) {
59 var dbs []map[string]string
60 for _, db := range opts {
61 dbMap, err := db.ToMap()
62 if err != nil {
63 return dbs, err
64 }
65 dbs = append(dbs, dbMap)
66 }
67 return dbs, nil
68}
69
70// UserOpts is the struct responsible for configuring a user; often in the
71// context of an instance.
72type UserOpts struct {
73 // Specifies a name for the user.
74 Name string
75
76 // Specifies a password for the user.
77 Password string
78
79 // An array of databases that this user will connect to. The `name` field is
80 // the only requirement for each option.
81 Databases []DatabaseOpts
82
83 // Specifies the host from which a user is allowed to connect to the database.
84 // Possible values are a string containing an IPv4 address or "%" to allow
85 // connecting from any host. Optional; the default is "%".
86 Host string
87}
88
89func (opts UserOpts) ToMap() (map[string]interface{}, error) {
90 user := map[string]interface{}{}
91
92 if opts.Name != "" {
93 user["name"] = opts.Name
94 }
95 if opts.Password != "" {
96 user["password"] = opts.Password
97 }
98 if opts.Host != "" {
99 user["host"] = opts.Host
100 }
101
102 var dbs []map[string]string
103 for _, db := range opts.Databases {
104 dbs = append(dbs, map[string]string{"name": db.Name})
105 }
106 if len(dbs) > 0 {
107 user["databases"] = dbs
108 }
109
110 return user, nil
111}
112
113type UsersOpts []UserOpts
114
115func (opts UsersOpts) ToMap() ([]map[string]interface{}, error) {
116 var users []map[string]interface{}
117 for _, opt := range opts {
118 user, err := opt.ToMap()
119 if err != nil {
120 return users, err
121 }
122 users = append(users, user)
123 }
124 return users, nil
125}
126
127// CreateOpts is the struct responsible for configuring a new database instance.
128type CreateOpts struct {
129 // Either the integer UUID (in string form) of the flavor, or its URI
130 // reference as specified in the response from the List() call. Required.
131 FlavorRef string
132
133 // Specifies the volume size in gigabytes (GB). The value must be between 1
134 // and 300. Required.
135 Size int
136
137 // Name of the instance to create. The length of the name is limited to
138 // 255 characters and any characters are permitted. Optional.
139 Name string
140
141 // ID of the configuration group to associate with the instance. Optional.
142 ConfigID string
143
144 // Options to configure the type of datastore the instance will use. This is
145 // optional, and if excluded will default to MySQL.
146 Datastore *DatastoreOpts
147
148 // A slice of database information options.
149 Databases DatabasesOpts
150
151 // A slice of user information options.
152 Users UsersOpts
153
154 // Specifies the backup ID from which to restore the database instance. There
155 // are some things to be aware of before using this field. When you execute
156 // the Restore Backup operation, a new database instance is created to store
157 // the backup whose ID is specified by the restorePoint attribute. This will
158 // mean that:
159 // - All users, passwords and access that were on the instance at the time of
160 // the backup will be restored along with the databases.
161 // - You can create new users or databases if you want, but they cannot be
162 // the same as the ones from the instance that was backed up.
163 RestorePoint string
164}
165
166func (opts CreateOpts) ToInstanceCreateMap() (map[string]interface{}, error) {
167 if opts.Size > 300 || opts.Size < 1 {
168 return nil, fmt.Errorf("Size (GB) must be between 1-300")
169 }
170 if opts.FlavorRef == "" {
171 return nil, fmt.Errorf("FlavorRef is a required field")
172 }
173
174 instance := map[string]interface{}{
175 "volume": map[string]int{"size": opts.Size},
176 "flavorRef": opts.FlavorRef,
177 }
178
179 if opts.Name != "" {
180 instance["name"] = opts.Name
181 }
182 if opts.ConfigID != "" {
183 instance["configuration"] = opts.ConfigID
184 }
185 if opts.Datastore != nil {
186 ds, err := opts.Datastore.ToMap()
187 if err != nil {
188 return nil, err
189 }
190 instance["datastore"] = ds
191 }
192 if len(opts.Databases) > 0 {
193 dbs, err := opts.Databases.ToMap()
194 if err != nil {
195 return nil, err
196 }
197 instance["databases"] = dbs
198 }
199 if len(opts.Users) > 0 {
200 users, err := opts.Users.ToMap()
201 if err != nil {
202 return nil, err
203 }
204 instance["users"] = users
205 }
206 if opts.RestorePoint != "" {
207 instance["restorePoint"] = opts.RestorePoint
208 }
209
210 return map[string]interface{}{"instance": instance}, nil
211}
212
213// Create will provision a new Database instance.
214func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
215 var res CreateResult
216
217 reqBody, err := opts.ToInstanceCreateMap()
218 if err != nil {
219 res.Err = err
220 return res
221 }
222
223 resp, err := perigee.Request("POST", createURL(client), perigee.Options{
224 MoreHeaders: client.AuthenticatedHeaders(),
225 ReqBody: &reqBody,
226 OkCodes: []int{200},
227 })
228
229 res.Header = resp.HttpResponse.Header
230 res.Err = err
231
232 return res
233}